Skip to content

Commit 5379d06

Browse files
committed
preview refactor, fix tab views and server selection,notify on login
1 parent ccef856 commit 5379d06

File tree

4 files changed

+268
-183
lines changed

4 files changed

+268
-183
lines changed

Django Files/Django_FilesApp.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ struct Django_FilesApp: App {
110110
await MainActor.run {
111111
sessionManager.selectedSession = newSession
112112
hasExistingSessions = true
113+
ToastManager.shared.showToast(message: "Successfully logged into \(newSession.url)")
113114
}
114115
}
115116
} catch {

Django Files/Views/FileList.swift

Lines changed: 6 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ struct FileRowView: View {
6868
}
6969
}
7070
.listRowSeparator(.visible)
71+
7172

7273
VStack(alignment: .leading, spacing: 5) {
7374

@@ -266,106 +267,13 @@ struct FileListView: View {
266267
Spacer()
267268
}
268269
}
269-
.toolbar(showingPreview ? .hidden : .visible, for: .tabBar)
270-
.animation(.easeInOut(duration: 0.3), value: showingPreview)
271270
.fullScreenCover(isPresented: $showingPreview) {
272271
if let file = selectedFile {
273-
ZStack {
274-
if redirectURLs[file.raw] == nil {
275-
ProgressView()
276-
.onAppear {
277-
Task {
278-
await loadRedirectURL(for: file)
279-
}
280-
}
281-
} else {
282-
ContentPreview(mimeType: file.mime, fileURL: URL(string: redirectURLs[file.raw]!)!, file: file, showFileInfo: $showFileInfo)
283-
.onDisappear {
284-
showingPreview = false
285-
}
286-
.gesture(
287-
DragGesture().onEnded { value in
288-
if value.location.y - value.startLocation.y > 150 {
289-
showingPreview = false
290-
}
291-
}
292-
)
293-
294-
ZStack(alignment: .top) {
295-
VStack {
296-
HStack{
297-
Button(action: {
298-
showingPreview = false
299-
}) {
300-
Image(systemName: "xmark")
301-
.font(.system(size: 17))
302-
.foregroundColor(.blue)
303-
.padding()
304-
}
305-
.background(.ultraThinMaterial)
306-
.frame(width: 32, height: 32)
307-
.cornerRadius(8)
308-
.padding(.leading, 20)
309-
Spacer()
310-
Text(file.name)
311-
.font(.headline)
312-
.lineLimit(1)
313-
314-
Spacer()
315-
316-
}
317-
Spacer()
318-
// Bottom Navigation Bar
319-
HStack {
320-
Spacer()
321-
322-
Button(action: {
323-
showFileInfo = true
324-
}) {
325-
Label("", systemImage: "info.circle")
326-
.font(.system(size: 17))
327-
.padding()
328-
.padding(.leading, 8)
329-
}
330-
.menuStyle(.button)
331-
.background(.ultraThinMaterial)
332-
.frame(width: 32, height: 32)
333-
.cornerRadius(8)
334-
335-
Menu {
336-
fileShareMenu(for: file)
337-
} label: {
338-
Image(systemName: "square.and.arrow.up")
339-
.font(.system(size: 17))
340-
.padding()
341-
}
342-
.menuStyle(.button)
343-
.background(.ultraThinMaterial)
344-
.frame(width: 32, height: 32)
345-
.cornerRadius(8)
346-
.padding()
347-
348-
Menu {
349-
fileContextMenu(for: file, isPreviewing: true, isPrivate: file.private, expirationText: $expirationText, passwordText: $passwordText, fileNameText: $fileNameText)
350-
.padding()
351-
} label: {
352-
Image(systemName: "ellipsis.circle")
353-
.font(.system(size: 17))
354-
.padding()
355-
}
356-
.menuStyle(.button)
357-
.background(.ultraThinMaterial)
358-
.frame(width: 32, height: 32)
359-
.cornerRadius(8)
360-
361-
Spacer()
362-
}
363-
364-
}
365-
}
366-
367-
}
368-
}
272+
FilePreviewView(
273+
file: file,
274+
showingPreview: $showingPreview,
275+
showFileInfo: $showFileInfo
276+
)
369277
}
370278
}
371279

Django Files/Views/Preview.swift

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,3 +692,164 @@ class AudioPlayerViewModel: ObservableObject {
692692
return String(format: "%02d:%02d", minutes, seconds)
693693
}
694694
}
695+
696+
struct FilePreviewView: View {
697+
let file: DFFile
698+
@Binding var showingPreview: Bool
699+
@Binding var showFileInfo: Bool
700+
@State private var redirectURLs: [String: String] = [:]
701+
702+
var body: some View {
703+
ZStack {
704+
if redirectURLs[file.raw] == nil {
705+
ProgressView()
706+
.onAppear {
707+
Task {
708+
await loadRedirectURL(for: file)
709+
}
710+
}
711+
} else {
712+
ContentPreview(mimeType: file.mime, fileURL: URL(string: redirectURLs[file.raw]!)!, file: file, showFileInfo: $showFileInfo)
713+
.onDisappear {
714+
showingPreview = false
715+
}
716+
.gesture(
717+
DragGesture().onEnded { value in
718+
if value.location.y - value.startLocation.y > 150 {
719+
showingPreview = false
720+
}
721+
}
722+
)
723+
724+
ZStack(alignment: .top) {
725+
VStack {
726+
HStack{
727+
Button(action: {
728+
showingPreview = false
729+
}) {
730+
Image(systemName: "xmark")
731+
.font(.system(size: 17))
732+
.foregroundColor(.blue)
733+
.padding()
734+
}
735+
.background(.ultraThinMaterial)
736+
.frame(width: 32, height: 32)
737+
.cornerRadius(8)
738+
.padding(.leading, 20)
739+
Spacer()
740+
Text(file.name)
741+
.font(.headline)
742+
.lineLimit(1)
743+
Spacer()
744+
}
745+
Spacer()
746+
HStack {
747+
Spacer()
748+
Button(action: {
749+
showFileInfo = true
750+
}) {
751+
Image(systemName: "info.circle")
752+
.font(.system(size: 20))
753+
.padding()
754+
}
755+
.buttonStyle(.borderless)
756+
757+
Menu {
758+
fileShareMenu(for: file)
759+
} label: {
760+
Image(systemName: "square.and.arrow.up")
761+
.font(.system(size: 20))
762+
.offset(y: -3)
763+
.padding()
764+
}
765+
.menuStyle(.button)
766+
767+
Menu {
768+
fileContextMenu(for: file, isPreviewing: true, isPrivate: file.private, expirationText: .constant(""), passwordText: .constant(""), fileNameText: .constant(""))
769+
.padding()
770+
} label: {
771+
Image(systemName: "ellipsis.circle")
772+
.font(.system(size: 20))
773+
.padding()
774+
}
775+
.menuStyle(.button)
776+
Spacer()
777+
}
778+
.background(.ultraThinMaterial)
779+
.frame(width: 200, height: 44)
780+
.cornerRadius(22)
781+
}
782+
783+
}
784+
}
785+
786+
}
787+
}
788+
789+
@MainActor
790+
private func loadRedirectURL(for file: DFFile) async {
791+
guard redirectURLs[file.raw] == nil,
792+
let serverURL = URL(string: file.url)?.host else {
793+
return
794+
}
795+
796+
let baseURL = URL(string: "https://\(serverURL)")!
797+
let api = DFAPI(url: baseURL, token: "") // Token will be handled by cookies
798+
799+
if let redirectURL = await api.checkRedirect(url: file.raw) {
800+
redirectURLs[file.raw] = redirectURL
801+
} else {
802+
// If redirect fails, use the original URL
803+
redirectURLs[file.raw] = file.raw
804+
}
805+
}
806+
807+
private func fileShareMenu(for file: DFFile) -> FileShareMenu {
808+
FileShareMenu(
809+
onCopyShareLink: {
810+
UIPasteboard.general.string = file.url
811+
},
812+
onCopyRawLink: {
813+
UIPasteboard.general.string = file.raw
814+
}
815+
)
816+
}
817+
818+
private func fileContextMenu(for file: DFFile, isPreviewing: Bool, isPrivate: Bool, expirationText: Binding<String>, passwordText: Binding<String>, fileNameText: Binding<String>) -> FileContextMenuButtons {
819+
FileContextMenuButtons(
820+
isPreviewing: isPreviewing,
821+
isPrivate: isPrivate,
822+
onPreview: {
823+
// No-op since we're already previewing
824+
},
825+
onCopyShareLink: {
826+
UIPasteboard.general.string = file.url
827+
},
828+
onCopyRawLink: {
829+
UIPasteboard.general.string = file.raw
830+
},
831+
openRawBrowser: {
832+
if let url = URL(string: file.raw), UIApplication.shared.canOpenURL(url) {
833+
UIApplication.shared.open(url)
834+
}
835+
},
836+
onTogglePrivate: {
837+
// We'll handle this in the parent view
838+
},
839+
setExpire: {
840+
// We'll handle this in the parent view
841+
},
842+
setPassword: {
843+
// We'll handle this in the parent view
844+
},
845+
renameFile: {
846+
// We'll handle this in the parent view
847+
},
848+
deleteFile: {
849+
// We'll handle this in the parent view
850+
}
851+
)
852+
}
853+
}
854+
855+

0 commit comments

Comments
 (0)