@@ -10,171 +10,189 @@ import SwiftUI
10
10
import Combine
11
11
12
12
enum ModalView : Identifiable {
13
- case settings
14
- case welcome
15
- case external
16
-
17
- var id : Int {
18
- hashValue
19
- }
13
+ case settings
14
+ case welcome
15
+ case external
16
+
17
+ var id : Int {
18
+ hashValue
19
+ }
20
20
}
21
21
22
22
struct SnipViewApp : View {
23
-
24
- @ObservedObject var viewModel : SnipViewAppViewModel
25
-
26
- @EnvironmentObject var appState : AppState
27
- @EnvironmentObject var settings : Settings
28
-
29
-
30
- var body : some View {
31
- appNavigation
32
- . frame ( maxWidth: . infinity, maxHeight: . infinity)
33
- }
34
-
35
- @ViewBuilder
36
- var appNavigation : some View {
37
- ZStack {
38
- NavigationView {
39
-
40
- if let sidebarViewModel = viewModel. sidebarViewModel {
41
- Sidebar ( viewModel: sidebarViewModel)
42
- . frame ( minWidth: 300 )
23
+
24
+ @ObservedObject var viewModel : SnipViewAppViewModel
25
+
26
+ @EnvironmentObject var appState : AppState
27
+ @EnvironmentObject var settings : Settings
28
+
29
+
30
+ var body : some View {
31
+ appNavigation
32
+ . frame ( maxWidth: . infinity, maxHeight: . infinity)
33
+ }
34
+
35
+ @ViewBuilder
36
+ var appNavigation : some View {
37
+ ZStack {
38
+ NavigationView {
39
+
40
+ if let sidebarViewModel = viewModel. sidebarViewModel {
41
+ Sidebar ( viewModel: sidebarViewModel)
42
+ . frame ( minWidth: 300 )
43
+ }
44
+
45
+ if let codeViewerViewModel = viewModel. codeViewerViewModel {
46
+ CodeViewer ( viewModel: codeViewerViewModel)
47
+ }
48
+
49
+ }
43
50
}
44
-
45
- if let codeViewerViewModel = viewModel. codeViewerViewModel {
46
- CodeViewer ( viewModel: codeViewerViewModel)
51
+ . frame ( maxWidth: . infinity, maxHeight: . infinity)
52
+ . environment ( \. themePrimaryColor, settings. snipAppTheme == . auto ? . primary : . primaryTheme)
53
+ . environment ( \. themeSecondaryColor, settings. snipAppTheme == . auto ? . secondary : . secondaryTheme)
54
+ . environment ( \. themeTextColor, settings. snipAppTheme == . auto ? . text : . white)
55
+ . environment ( \. themeShadowColor, settings. snipAppTheme == . auto ? . shadow : . shadowTheme)
56
+ . onAppear {
57
+ SyncManager . shared. initialize ( )
58
+ viewModel. trigger ( action: . syncGists( ) )
47
59
}
48
-
49
- }
50
- }
51
- . frame ( maxWidth: . infinity, maxHeight: . infinity)
52
- . environment ( \. themePrimaryColor, settings. snipAppTheme == . auto ? . primary : . primaryTheme)
53
- . environment ( \. themeSecondaryColor, settings. snipAppTheme == . auto ? . secondary : . secondaryTheme)
54
- . environment ( \. themeTextColor, settings. snipAppTheme == . auto ? . text : . white)
55
- . environment ( \. themeShadowColor, settings. snipAppTheme == . auto ? . shadow : . shadowTheme)
56
- . onAppear {
57
- SyncManager . shared. initialize ( )
58
- viewModel. trigger ( action: . syncGists( ) )
59
- }
60
- . sheet ( item: $viewModel. modalView) { content in
61
-
62
- switch content {
63
- case . welcome:
64
- WelcomeView ( viewModel: WelcomeViewModel ( isVisible: $appState. shouldOpenWelcome) )
65
- . frame ( width: 800 , height: 600 )
66
- case . settings:
67
- SettingsView ( viewModel: SettingsViewModel ( isVisible: $settings. shouldOpenSettings) )
68
- . frame ( width: 800 , height: 600 )
69
- case . external:
70
- ExternalSnippet ( viewModel: ExternalSnippetViewModel ( isVisible: $viewModel. snippetManager. hasExternalSnippetQueued,
71
- snipItem: $viewModel. snippetManager. tempSnipItem,
72
- onTrigger: viewModel. trigger ( action: ) ) )
73
- . frame ( width: 800 , height: 600 )
74
- }
75
- }
76
- . toolbar {
77
- ToolbarItem ( placement: . primaryAction) {
78
- Button ( action: viewModel. openExtensionLink) {
79
- Image ( systemName: " square.3.stack.3d.middle.fill " )
60
+ . sheet ( item: $viewModel. modalView) { content in
61
+
62
+ switch content {
63
+ case . welcome:
64
+ WelcomeView ( viewModel: WelcomeViewModel ( isVisible: $appState. shouldOpenWelcome) )
65
+ . frame ( width: 800 , height: 600 )
66
+ case . settings:
67
+ SettingsView ( viewModel: SettingsViewModel ( isVisible: $settings. shouldOpenSettings) )
68
+ . frame ( width: 800 , height: 600 )
69
+ case . external:
70
+ ExternalSnippet ( viewModel: ExternalSnippetViewModel ( isVisible: $viewModel. snippetManager. hasExternalSnippetQueued,
71
+ snipItem: $viewModel. snippetManager. tempSnipItem,
72
+ onTrigger: viewModel. trigger ( action: ) ) )
73
+ . frame ( width: 800 , height: 600 )
74
+ }
80
75
}
81
- . help ( NSLocalizedString ( " Extract_Stack " , comment: " " ) )
82
- . onHover { inside in
83
- if inside {
84
- NSCursor . pointingHand. push ( )
85
- } else {
86
- NSCursor . pop ( )
87
- }
76
+ . toolbar {
77
+ ToolbarItem ( placement: . navigation) {
78
+ Button ( action: viewModel. toggleSidebar) {
79
+ Image ( systemName: " sidebar.left " )
80
+ }
81
+ . keyboardShortcut ( KeyEquivalent . leftArrow, modifiers: [ . command] )
82
+ . onHover { inside in
83
+ if inside {
84
+ NSCursor . pointingHand. push ( )
85
+ } else {
86
+ NSCursor . pop ( )
87
+ }
88
+ }
89
+ }
90
+
91
+ ToolbarItem ( placement: . primaryAction) {
92
+ Button ( action: viewModel. openExtensionLink) {
93
+ Image ( systemName: " square.3.stack.3d.middle.fill " )
94
+ }
95
+ . help ( NSLocalizedString ( " Extract_Stack " , comment: " " ) )
96
+ . onHover { inside in
97
+ if inside {
98
+ NSCursor . pointingHand. push ( )
99
+ } else {
100
+ NSCursor . pop ( )
101
+ }
102
+ }
103
+ }
104
+ }
105
+ . onOpenURL { url in
106
+ DeepLinkManager . handleDeepLink ( url: url)
88
107
}
89
- }
90
- }
91
- . onOpenURL { url in
92
- DeepLinkManager . handleDeepLink ( url: url)
93
108
}
94
- }
95
109
}
96
110
97
111
98
112
final class SnipViewAppViewModel : ObservableObject {
99
-
100
- @Published var snippets : [ SnipItem ] = [ ]
101
- @Published var selectionSnipItem : SnipItem ?
102
- @Published var snippetManager = SnippetManager . shared
103
- @Published var modalView : ModalView ?
104
-
105
- var appState : AppState
106
- var settings : Settings
107
-
108
- var cancellables : Set < AnyCancellable > = [ ]
109
-
110
- var sidebarViewModel : SideBarViewModel ?
111
- var codeViewerViewModel : CodeViewerViewModel ?
112
-
113
- init ( appState: AppState ,
114
- settings: Settings ) {
115
-
116
- self . appState = appState
117
- self . settings = settings
118
-
119
- SnippetManager
120
- . shared
121
- . snipets
122
- . sink { [ weak self] ( snippets) in
123
- guard let this = self else { return }
124
- this. snippets = snippets
125
- this. selectionSnipItem = snippets. flatternSnippets. first ( where: { $0. id == appState. selectedSnippetId } )
126
- }
127
- . store ( in: & stores)
128
-
129
- Publishers . CombineLatest3 ( settings. $shouldOpenSettings, appState. $shouldOpenWelcome, snippetManager. $hasExternalSnippetQueued)
130
- . map ( triggerModalOpening ( openSettings: openWelcome: openExternalSnippet: ) )
131
- . sink { [ weak self] ( modalView) in
132
- guard let this = self else { return }
133
- this. modalView = modalView
134
- }
135
- . store ( in: & stores)
136
-
137
- sidebarViewModel = SideBarViewModel ( snippets: $snippets. eraseToAnyPublisher ( ) ,
138
- onTrigger: trigger ( action: ) ,
139
- onSnippetSelection: didSelectSnipItem ( _: filter: ) )
140
-
141
- codeViewerViewModel = CodeViewerViewModel ( snipItem: $selectionSnipItem. eraseToAnyPublisher ( ) ,
142
- onTrigger: trigger ( action: ) ,
143
- onDimiss: didDeselectSnipItem)
144
- }
145
-
146
- func trigger( action: SnipItemsListAction ) {
147
- SnippetManager . shared. trigger ( action: action)
148
- }
149
-
150
- func triggerModalOpening( openSettings: Bool , openWelcome: Bool , openExternalSnippet: Bool ) -> ModalView ? {
151
- if openWelcome {
152
- return . welcome
113
+
114
+ @Published var snippets : [ SnipItem ] = [ ]
115
+ @Published var selectionSnipItem : SnipItem ?
116
+ @Published var snippetManager = SnippetManager . shared
117
+ @Published var modalView : ModalView ?
118
+
119
+ var appState : AppState
120
+ var settings : Settings
121
+
122
+ var cancellables : Set < AnyCancellable > = [ ]
123
+
124
+ var sidebarViewModel : SideBarViewModel ?
125
+ var codeViewerViewModel : CodeViewerViewModel ?
126
+
127
+ init ( appState: AppState ,
128
+ settings: Settings ) {
129
+
130
+ self . appState = appState
131
+ self . settings = settings
132
+
133
+ SnippetManager
134
+ . shared
135
+ . snipets
136
+ . sink { [ weak self] ( snippets) in
137
+ guard let this = self else { return }
138
+ this. snippets = snippets
139
+ this. selectionSnipItem = snippets. flatternSnippets. first ( where: { $0. id == appState. selectedSnippetId } )
140
+ }
141
+ . store ( in: & stores)
142
+
143
+ Publishers . CombineLatest3 ( settings. $shouldOpenSettings, appState. $shouldOpenWelcome, snippetManager. $hasExternalSnippetQueued)
144
+ . map ( triggerModalOpening ( openSettings: openWelcome: openExternalSnippet: ) )
145
+ . sink { [ weak self] ( modalView) in
146
+ guard let this = self else { return }
147
+ this. modalView = modalView
148
+ }
149
+ . store ( in: & stores)
150
+
151
+ sidebarViewModel = SideBarViewModel ( snippets: $snippets. eraseToAnyPublisher ( ) ,
152
+ onTrigger: trigger ( action: ) ,
153
+ onSnippetSelection: didSelectSnipItem ( _: filter: ) )
154
+
155
+ codeViewerViewModel = CodeViewerViewModel ( snipItem: $selectionSnipItem. eraseToAnyPublisher ( ) ,
156
+ onTrigger: trigger ( action: ) ,
157
+ onDimiss: didDeselectSnipItem)
153
158
}
154
- else if openSettings {
155
- return . settings
159
+
160
+ func trigger( action: SnipItemsListAction ) {
161
+ SnippetManager . shared. trigger ( action: action)
156
162
}
157
- else if openExternalSnippet {
158
- return . external
163
+
164
+ func triggerModalOpening( openSettings: Bool , openWelcome: Bool , openExternalSnippet: Bool ) -> ModalView ? {
165
+ if openWelcome {
166
+ return . welcome
167
+ }
168
+ else if openSettings {
169
+ return . settings
170
+ }
171
+ else if openExternalSnippet {
172
+ return . external
173
+ }
174
+ else {
175
+ return nil
176
+ }
159
177
}
160
- else {
161
- return nil
178
+
179
+ func didSelectSnipItem( _ snip: SnipItem , filter: ModelFilter ) {
180
+ appState. selectedSnippetId = snip. id
181
+ appState. selectedSnippetFilter = filter
182
+ selectionSnipItem = snip
183
+ }
184
+
185
+ func didDeselectSnipItem( ) {
186
+ appState. selectedSnippetId = nil
187
+ selectionSnipItem = nil
188
+ }
189
+
190
+ func openExtensionLink( ) {
191
+ guard let url = URL ( string: " https://cutt.ly/whQTNO3 " ) else { return }
192
+ NSWorkspace . shared. open ( url)
193
+ }
194
+
195
+ func toggleSidebar( ) {
196
+ NSApp . keyWindow? . firstResponder? . tryToPerform ( #selector( NSSplitViewController . toggleSidebar ( _: ) ) , with: nil )
162
197
}
163
- }
164
-
165
- func didSelectSnipItem( _ snip: SnipItem , filter: ModelFilter ) {
166
- appState. selectedSnippetId = snip. id
167
- appState. selectedSnippetFilter = filter
168
- selectionSnipItem = snip
169
- }
170
-
171
- func didDeselectSnipItem( ) {
172
- appState. selectedSnippetId = nil
173
- selectionSnipItem = nil
174
- }
175
-
176
- func openExtensionLink( ) {
177
- guard let url = URL ( string: " https://cutt.ly/whQTNO3 " ) else { return }
178
- NSWorkspace . shared. open ( url)
179
- }
180
198
}
0 commit comments