@@ -9,183 +9,208 @@ import RichEditorSwiftUI
99import SwiftUI
1010
1111struct ContentView : View {
12- @Environment ( \. colorScheme) var colorScheme
13-
14- @ObservedObject var state : RichEditorState
15- @State private var isInspectorPresented = false
16- @State private var fileName : String = " "
17- @State private var exportFormat : RichTextDataFormat ? = nil
18- @State private var otherExportFormat : RichTextExportOption ? = nil
19- @State private var exportService : StandardRichTextExportService = . init( )
20-
21- init ( state: RichEditorState ? = nil ) {
22- if let state {
23- self . state = state
24- } else {
25- if let richText = readJSONFromFile (
26- fileName: " Sample_json " ,
27- type: RichText . self)
28- {
29- self . state = . init( richText: richText)
30- } else {
31- self . state = . init( input : " Hello World! " )
32- }
33- }
34- }
12+ @Environment ( \. colorScheme) var colorScheme
13+
14+ @ObservedObject var state : RichEditorState
15+ @State private var isInspectorPresented = false
16+ @State private var fileName : String = " "
17+ @State private var exportFormat : RichTextDataFormat ? = nil
18+ @State private var otherExportFormat : RichTextExportOption ? = nil
19+ @State private var exportService : StandardRichTextExportService = . init( )
20+
21+ init ( state: RichEditorState ? = nil ) {
22+ if let state {
23+ self . state = state
24+ } else {
25+ if let richText = readJSONFromFile (
26+ fileName: " Sample_json " ,
27+ type: RichText . self)
28+ {
29+ self . state = . init( richText: richText, handleImageDropAction : handleImages ( _ : _ : ) )
30+ } else {
31+ self . state = . init(
32+ input : " Hello World! " ,
33+ handleImageDropAction : handleImages ( _ : _ : ) )
34+ }
3535
36- var body : some View {
37- NavigationStack {
38- VStack {
39- #if os(macOS)
40- RichTextFormat . Toolbar ( context: state)
41- #endif
42-
43- RichTextEditor (
44- context: _state,
45- viewConfiguration: { _ in
46-
47- }
48- )
49- . background (
50- colorScheme == . dark ? . gray. opacity ( 0.3 ) : Color . white
51- )
52- . cornerRadius ( 10 )
53-
54- #if os(iOS)
55- RichTextKeyboardToolbar (
56- context: state,
57- leadingButtons: { $0 } ,
58- trailingButtons: { $0 } ,
59- formatSheet: { $0 }
60- )
61- #endif
62- }
63- #if os(iOS) || os(macOS)
64- . inspector( isPresented: $isInspectorPresented) {
65- RichTextFormat . Sidebar ( context: state)
66- #if os(macOS)
67- . inspectorColumnWidth(
68- min: 200 , ideal: 200 , max: 315 )
69- #endif
70- }
71- #endif
72- . padding( 10 )
73- #if os(iOS) || os(macOS)
74- . toolbar {
75- ToolbarItemGroup ( placement: . automatic) {
76- toolBarGroup
77- }
78- }
79- #endif
80- . background( colorScheme == . dark ? . black : . gray. opacity ( 0.07 ) )
81- . navigationTitle ( " Rich Editor " )
82- . alert ( " Enter file name " , isPresented: getBindingAlert ( ) ) {
83- TextField ( " Enter file name " , text: $fileName)
84- Button ( " OK " , action: submit)
85- } message: {
86- Text ( " Please enter file name " )
87- }
88- . focusedValue ( \. richEditorState, state)
89- . toolbarRole ( . automatic)
90- #if os(iOS) || os(macOS) || os(visionOS)
91- . richTextFormatSheetConfig( . init( colorPickers: colorPickers) )
92- . richTextFormatSidebarConfig (
93- . init(
94- colorPickers: colorPickers,
95- fontPicker: isMac
96- )
97- )
98- . richTextFormatToolbarConfig ( . init( colorPickers: [ ] ) )
99- #endif
100- }
10136 }
37+ }
10238
103- #if os(iOS) || os(macOS)
104- var toolBarGroup : some View {
105- return Group {
106- RichTextExportMenu . init (
107- formatAction: { format in
108- exportFormat = format
109- } ,
110- otherOptionAction: { format in
111- otherExportFormat = format
112- }
113- )
114- #if !os(macOS)
115- . frame( width: 25 , alignment: . center)
116- #endif
117- Button (
118- action: {
119- print ( " Exported JSON == \( state. outputAsString ( ) ) " )
120- } ,
121- label: {
122- Image ( systemName: " printer.inverse " )
123- }
124- )
125- #if !os(macOS)
126- . frame( width: 25 , alignment: . center)
127- #endif
128- Toggle ( isOn: $isInspectorPresented) {
129- Image . richTextFormatBrush
130- . resizable ( )
131- . aspectRatio ( 1 , contentMode: . fit)
132- }
133- #if !os(macOS)
134- . frame( width: 25 , alignment: . center)
135- #endif
136- }
137- }
138- #endif
139-
140- func getBindingAlert( ) -> Binding < Bool > {
141- . init(
142- get: { exportFormat != nil || otherExportFormat != nil } ,
143- set: { newValue in
144- exportFormat = nil
145- otherExportFormat = nil
146- } )
147- }
148-
149- func submit( ) {
150- guard !fileName. isEmpty else { return }
151- var path : URL ?
39+ var body : some View {
40+ NavigationStack {
41+ VStack {
42+ #if os(macOS)
43+ RichTextFormat . Toolbar ( context: state)
44+ #endif
15245
153- if let exportFormat {
154- path = try ? exportService. generateExportFile (
155- withName: fileName, content: state. attributedString,
156- format: exportFormat)
46+ RichTextEditor (
47+ context: _state,
48+ viewConfiguration: { _ in
49+
50+ }
51+ )
52+ . background (
53+ colorScheme == . dark ? . gray. opacity ( 0.3 ) : Color . white
54+ )
55+ . cornerRadius ( 10 )
56+
57+ #if os(iOS)
58+ RichTextKeyboardToolbar (
59+ context: state,
60+ leadingButtons: { $0 } ,
61+ trailingButtons: { $0 } ,
62+ formatSheet: { $0 }
63+ )
64+ #endif
65+ }
66+ #if os(iOS) || os(macOS)
67+ . inspector( isPresented: $isInspectorPresented) {
68+ RichTextFormat . Sidebar ( context: state)
69+ #if os(macOS)
70+ . inspectorColumnWidth(
71+ min: 200 , ideal: 200 , max: 315 )
72+ #endif
15773 }
158- if let otherExportFormat {
159- switch otherExportFormat {
160- case . pdf:
161- path = try ? exportService. generatePdfExportFile (
162- withName: fileName, content: state. attributedString)
163- case . json:
164- path = try ? exportService. generateJsonExportFile (
165- withName: fileName, content: state. richText)
166- }
74+ #endif
75+ . padding( 10 )
76+ #if os(iOS) || os(macOS)
77+ . toolbar {
78+ ToolbarItemGroup ( placement: . automatic) {
79+ toolBarGroup
80+ }
16781 }
168- if let path {
169- print ( " Exported at path == \( path) " )
82+ #endif
83+ . background( colorScheme == . dark ? . black : . gray. opacity ( 0.07 ) )
84+ . navigationTitle ( " Rich Editor " )
85+ . alert ( " Enter file name " , isPresented: getBindingAlert ( ) ) {
86+ TextField ( " Enter file name " , text: $fileName)
87+ Button ( " OK " , action: submit)
88+ } message: {
89+ Text ( " Please enter file name " )
90+ }
91+ . focusedValue ( \. richEditorState, state)
92+ . toolbarRole ( . automatic)
93+ #if os(iOS) || os(macOS) || os(visionOS)
94+ . richTextFormatSheetConfig( . init( colorPickers: colorPickers) )
95+ . richTextFormatSidebarConfig (
96+ . init(
97+ colorPickers: colorPickers,
98+ fontPicker: isMac
99+ )
100+ )
101+ . richTextFormatToolbarConfig ( . init( colorPickers: [ ] ) )
102+ #endif
103+ }
104+ }
105+
106+ #if os(iOS) || os(macOS)
107+ var toolBarGroup : some View {
108+ return Group {
109+ RichTextExportMenu . init (
110+ formatAction: { format in
111+ exportFormat = format
112+ } ,
113+ otherOptionAction: { format in
114+ otherExportFormat = format
115+ }
116+ )
117+ #if !os(macOS)
118+ . frame( width: 25 , alignment: . center)
119+ #endif
120+ Button (
121+ action: {
122+ print ( " Exported JSON == \( state. outputAsString ( ) ) " )
123+ } ,
124+ label: {
125+ Image ( systemName: " printer.inverse " )
126+ }
127+ )
128+ #if !os(macOS)
129+ . frame( width: 25 , alignment: . center)
130+ #endif
131+ Toggle ( isOn: $isInspectorPresented) {
132+ Image . richTextFormatBrush
133+ . resizable ( )
134+ . aspectRatio ( 1 , contentMode: . fit)
170135 }
136+ #if !os(macOS)
137+ . frame( width: 25 , alignment: . center)
138+ #endif
139+ }
171140 }
141+ #endif
142+
143+ func getBindingAlert( ) -> Binding < Bool > {
144+ . init(
145+ get: { exportFormat != nil || otherExportFormat != nil } ,
146+ set: { newValue in
147+ exportFormat = nil
148+ otherExportFormat = nil
149+ } )
150+ }
151+
152+ func submit( ) {
153+ guard !fileName. isEmpty else { return }
154+ var path : URL ?
155+
156+ if let exportFormat {
157+ path = try ? exportService. generateExportFile (
158+ withName: fileName, content: state. attributedString,
159+ format: exportFormat)
160+ }
161+ if let otherExportFormat {
162+ switch otherExportFormat {
163+ case . pdf:
164+ path = try ? exportService. generatePdfExportFile (
165+ withName: fileName, content: state. attributedString)
166+ case . json:
167+ path = try ? exportService. generateJsonExportFile (
168+ withName: fileName, content: state. richText)
169+ }
170+ }
171+ if let path {
172+ print ( " Exported at path == \( path) " )
173+ }
174+ }
172175}
173176
174177extension ContentView {
175178
176- var isMac : Bool {
177- #if os(macOS)
178- true
179- #else
180- false
181- #endif
182- }
179+ var isMac : Bool {
180+ #if os(macOS)
181+ true
182+ #else
183+ false
184+ #endif
185+ }
183186
184- var colorPickers : [ RichTextColor ] {
185- [ . foreground, . background]
186- }
187+ var colorPickers : [ RichTextColor ] {
188+ [ . foreground, . background]
189+ }
187190
188- var formatToolbarEdge : VerticalEdge {
189- isMac ? . top : . bottom
190- }
191+ var formatToolbarEdge : VerticalEdge {
192+ isMac ? . top : . bottom
193+ }
194+ }
195+
196+ private func handleImages(
197+ _ action: ImageAttachmentAction ,
198+ _ onCompletion: ( ( ImageAttachmentCompleteAction ) -> Void ) ?
199+ ) {
200+ switch action {
201+ case . save( let images) :
202+ images. forEach ( {
203+ $0. updateUrl ( with: " https://example.com/image/ \( $0. id) .jpg " )
204+ } )
205+ onCompletion ? ( . saved( images) )
206+ case . delete( _) :
207+ onCompletion ? ( . deleted)
208+ return
209+ case . getImage( _) :
210+ onCompletion ? ( . getImage( nil ) )
211+ return
212+ case . getImages( _) :
213+ onCompletion ? ( . getImages( [ ] ) )
214+ return
215+ }
191216}
0 commit comments