5
5
// Created by Michael on 2/14/25.
6
6
//
7
7
8
- import SwiftUI
9
8
import SwiftData
9
+ import SwiftUI
10
10
11
11
struct ContentView : View {
12
12
@Environment ( \. modelContext) private var modelContext
13
13
@Environment ( \. dismiss) private var dismiss
14
-
14
+
15
15
@Query private var items : [ DjangoFilesSession ]
16
16
@State private var showingEditor = false
17
- @State private var columnVisibility = NavigationSplitViewVisibility . detailOnly
17
+ @State private var columnVisibility = NavigationSplitViewVisibility
18
+ . detailOnly
18
19
@State private var selectedServer : DjangoFilesSession ?
19
- @State private var selectedSession : DjangoFilesSession ? // Track session for settings
20
+ @State private var selectedSession : DjangoFilesSession ? // Track session for settings
20
21
@State private var needsRefresh = false // Added to handle refresh after adding server
21
- @State private var itemToDelete : DjangoFilesSession ? // Track item to be deleted
22
- @State private var showingDeleteAlert = false // Track if delete alert is showing
23
-
22
+ @State private var itemToDelete : DjangoFilesSession ? // Track item to be deleted
23
+ @State private var showingDeleteAlert = false // Track if delete alert is showing
24
+
24
25
@State private var token : String ?
25
-
26
+
26
27
@State private var viewingSettings : Bool = false
27
-
28
-
28
+
29
+ // stupid work around where we have to show the toolbar on ipad so splitview does not crash due to toolbar state
30
+ let toolbarVisibility : Visibility =
31
+ UIDevice . current. userInterfaceIdiom == . pad ? . visible : . hidden
32
+
29
33
var body : some View {
30
34
NavigationSplitView ( columnVisibility: $columnVisibility) {
31
35
List ( selection: $selectedServer) {
32
36
ForEach ( items, id: \. self) { item in
33
37
NavigationLink ( value: item) {
34
38
Text ( item. url)
35
- . swipeActions ( ) {
39
+ . swipeActions {
36
40
Button ( role: . destructive) {
37
41
itemToDelete = item
38
42
showingDeleteAlert = true
@@ -54,8 +58,7 @@ struct ContentView: View {
54
58
ToolbarItem {
55
59
Button ( action: {
56
60
self . showingEditor. toggle ( )
57
- } )
58
- {
61
+ } ) {
59
62
Label ( " Add Item " , systemImage: " plus " )
60
63
}
61
64
}
@@ -74,7 +77,7 @@ struct ContentView: View {
74
77
. onAppear {
75
78
columnVisibility = . detailOnly
76
79
}
77
- . toolbarVisibility ( . hidden , for : . navigationBar )
80
+ . toolbar ( toolbarVisibility )
78
81
} else {
79
82
LoginView (
80
83
selectedServer: server,
@@ -86,10 +89,11 @@ struct ContentView: View {
86
89
. onAppear {
87
90
columnVisibility = . detailOnly
88
91
}
92
+ . toolbarBackground ( . hidden, for: . navigationBar)
89
93
}
90
94
}
91
95
}
92
- . sheet ( isPresented: $showingEditor) {
96
+ . sheet ( isPresented: $showingEditor) {
93
97
SessionEditor ( session: nil )
94
98
. onDisappear {
95
99
if items. count > 0 {
@@ -101,18 +105,21 @@ struct ContentView: View {
101
105
. sheet ( item: $selectedSession) { session in
102
106
SessionSelector ( session: session)
103
107
}
104
- . onAppear ( ) {
105
- selectedServer = items. first ( where: { $0. defaultSession } ) ?? items. first
106
- if items. count == 0 {
108
+ . onAppear {
109
+ selectedServer =
110
+ items. first ( where: { $0. defaultSession } ) ?? items. first
111
+ if items. count == 0 {
107
112
self . showingEditor. toggle ( )
108
113
}
109
114
}
110
115
. frame ( maxWidth: . infinity, maxHeight: . infinity)
111
116
. edgesIgnoringSafeArea ( . all)
112
117
. alert ( " Delete Server " , isPresented: $showingDeleteAlert) {
113
- Button ( " Cancel " , role: . cancel) { }
118
+ Button ( " Cancel " , role: . cancel) { }
114
119
Button ( " Delete " , role: . destructive) {
115
- if let item = itemToDelete, let index = items. firstIndex ( of: item) {
120
+ if let item = itemToDelete,
121
+ let index = items. firstIndex ( of: item)
122
+ {
116
123
deleteItems ( offsets: [ index] )
117
124
if selectedServer == item {
118
125
needsRefresh = true
@@ -121,10 +128,12 @@ struct ContentView: View {
121
128
}
122
129
}
123
130
} message: {
124
- Text ( " Are you sure you want to delete \( URL ( string: itemToDelete? . url ?? " " ) ? . host ?? " this server " ) ? This action cannot be undone. " )
131
+ Text (
132
+ " Are you sure you want to delete \( URL ( string: itemToDelete? . url ?? " " ) ? . host ?? " this server " ) ? This action cannot be undone. "
133
+ )
125
134
}
126
135
}
127
-
136
+
128
137
private func deleteItems( offsets: IndexSet ) {
129
138
withAnimation {
130
139
for index in offsets {
@@ -137,107 +146,111 @@ struct ContentView: View {
137
146
public struct AuthViewContainer : View {
138
147
@Environment ( \. modelContext) private var modelContext
139
148
@Environment ( \. dismiss) private var dismiss
140
- @Environment ( \. presentationMode) private var presentationMode : Binding < PresentationMode >
149
+ @Environment ( \. presentationMode) private var presentationMode :
150
+ Binding < PresentationMode >
141
151
@Query private var items : [ DjangoFilesSession ]
142
-
152
+
143
153
@State private var isAuthViewLoading : Bool = true
144
-
154
+
145
155
var viewingSettings : Binding < Bool >
146
156
let selectedServer : DjangoFilesSession
147
157
var columnVisibility : Binding < NavigationSplitViewVisibility >
148
158
var showingEditor : Binding < Bool >
149
159
var needsRefresh : Binding < Bool >
150
-
160
+
151
161
@State private var authController : AuthController = AuthController ( )
152
-
162
+
153
163
public var body : some View {
154
- if viewingSettings. wrappedValue{
155
- SessionSelector ( session: selectedServer, viewingSelect: viewingSettings)
156
- . onAppear ( ) {
157
- columnVisibility. wrappedValue = . automatic
158
- }
164
+ if viewingSettings. wrappedValue {
165
+ SessionSelector (
166
+ session: selectedServer,
167
+ viewingSelect: viewingSettings
168
+ )
169
+ . onAppear {
170
+ columnVisibility. wrappedValue = . automatic
159
171
}
160
- else if selectedServer. url != " " {
161
- Color . djangoFilesBackground. ignoresSafeArea ( )
162
- . overlay {
172
+ } else if selectedServer. url != " " {
173
+ Color . djangoFilesBackground. ignoresSafeArea ( )
174
+ . overlay {
163
175
AuthView (
164
176
authController: authController,
165
177
httpsUrl: selectedServer. url,
166
- doReset: authController. url? . absoluteString ?? " " != selectedServer. url || !selectedServer. auth,
178
+ doReset: authController. url? . absoluteString ?? " "
179
+ != selectedServer. url || !selectedServer. auth,
167
180
session: selectedServer
168
- )
169
- . onStartedLoading {
170
- isAuthViewLoading = true
181
+ )
182
+ . onStartedLoading {
183
+ isAuthViewLoading = true
184
+ }
185
+ . onCancelled {
186
+ isAuthViewLoading = false
187
+ dismiss ( )
188
+ }
189
+ . onAppear {
190
+ if needsRefresh. wrappedValue {
191
+ authController. reset ( )
192
+ needsRefresh. wrappedValue = false
193
+ }
194
+
195
+ authController. onStartedLoadingAction = {
171
196
}
172
- . onCancelled {
197
+
198
+ authController. onLoadedAction = {
199
+ isAuthViewLoading = false
200
+
201
+ }
202
+ authController. onCancelledAction = {
173
203
isAuthViewLoading = false
174
204
dismiss ( )
175
205
}
176
- . onAppear ( ) {
177
- columnVisibility. wrappedValue = . detailOnly
178
- if needsRefresh. wrappedValue {
179
- authController. reset ( )
180
- needsRefresh. wrappedValue = false
181
- }
182
-
183
- authController. onStartedLoadingAction = {
184
- }
185
-
186
- authController. onLoadedAction = {
187
- isAuthViewLoading = false
188
206
207
+ authController. onSchemeRedirectAction = {
208
+ isAuthViewLoading = false
209
+ guard let resolve = authController. schemeURL else {
210
+ return
189
211
}
190
- authController. onCancelledAction = {
191
- isAuthViewLoading = false
192
- dismiss ( )
193
- }
194
-
195
- authController. onSchemeRedirectAction = {
196
- isAuthViewLoading = false
197
- guard let resolve = authController. schemeURL else {
198
- return
199
- }
200
- switch resolve{
201
- case " serverlist " :
202
- if UIDevice . current. userInterfaceIdiom == . phone{
203
- self . presentationMode. wrappedValue. dismiss ( )
204
- }
205
- columnVisibility. wrappedValue = . all
206
- break
207
- case " serversettings " :
208
- viewingSettings. wrappedValue = true
209
- break
210
- case " logout " :
211
- selectedServer. auth = false
212
- columnVisibility. wrappedValue = . automatic
213
- modelContext. insert ( selectedServer)
214
- do {
215
- try modelContext. save ( )
216
- } catch {
217
- print ( " Error saving session: \( error) " )
218
- }
212
+ switch resolve {
213
+ case " serverlist " :
214
+ if UIDevice . current. userInterfaceIdiom == . phone
215
+ {
219
216
self . presentationMode. wrappedValue. dismiss ( )
220
- break
221
- default :
222
- return
223
217
}
218
+ columnVisibility. wrappedValue = . all
219
+ break
220
+ case " serversettings " :
221
+ viewingSettings. wrappedValue = true
222
+ break
223
+ case " logout " :
224
+ selectedServer. auth = false
225
+ columnVisibility. wrappedValue = . all
226
+ modelContext. insert ( selectedServer)
227
+ do {
228
+ try modelContext. save ( )
229
+ } catch {
230
+ print ( " Error saving session: \( error) " )
231
+ }
232
+ self . presentationMode. wrappedValue. dismiss ( )
233
+ break
234
+ default :
235
+ return
224
236
}
225
237
}
226
- . overlay {
227
- if isAuthViewLoading {
228
- LoadingView ( ) . frame ( width : 100 , height : 100 )
229
- }
238
+ }
239
+ . overlay {
240
+ if isAuthViewLoading {
241
+ LoadingView ( ) . frame ( width : 100 , height : 100 )
230
242
}
243
+ }
231
244
}
245
+ . ignoresSafeArea ( )
232
246
. edgesIgnoringSafeArea ( . all)
233
247
. frame ( maxWidth: . infinity, maxHeight: . infinity)
234
- }
235
- else {
236
- Text ( " Loading... " )
237
- . onAppear ( ) {
238
- columnVisibility. wrappedValue = . all
239
- }
240
- }
248
+ } else {
249
+ Text ( " Loading... " )
250
+ . onAppear {
251
+ columnVisibility. wrappedValue = . all
252
+ }
253
+ }
241
254
}
242
255
}
243
256
@@ -250,21 +263,25 @@ struct LoadingView: View {
250
263
. stroke ( Color . launchScreenBackground, lineWidth: 5 )
251
264
. rotationEffect ( Angle ( degrees: isLoading ? 360 : 0 ) )
252
265
. opacity ( firstAppear ? 1 : 0 )
253
- . onAppear ( ) {
266
+ . onAppear {
254
267
DispatchQueue . main. async {
255
- if isLoading == false {
256
- withAnimation ( . linear( duration: 1 ) . repeatForever ( autoreverses: false ) ) {
268
+ if isLoading == false {
269
+ withAnimation (
270
+ . linear( duration: 1 ) . repeatForever (
271
+ autoreverses: false
272
+ )
273
+ ) {
257
274
isLoading. toggle ( )
258
275
}
259
276
}
260
- withAnimation ( . easeInOut( duration: 0.25 ) ) {
277
+ withAnimation ( . easeInOut( duration: 0.25 ) ) {
261
278
firstAppear = true
262
279
}
263
280
}
264
281
}
265
- . onDisappear ( ) {
282
+ . onDisappear {
266
283
DispatchQueue . main. async {
267
- withAnimation ( . easeInOut( duration: 0.25 ) ) {
284
+ withAnimation ( . easeInOut( duration: 0.25 ) ) {
268
285
firstAppear = true
269
286
}
270
287
}
0 commit comments