@@ -79,9 +79,9 @@ struct FileListView: View {
79
79
List {
80
80
ForEach ( files, id: \. id) { file in
81
81
NavigationLink ( value: file) {
82
- FileRowView ( file: file, isPrivate: file. private, hasPassword: ( file. password != " " ) , hasExpiration: ( file. expr != " " ) )
82
+ FileRowView ( file: file, isPrivate: file. private, hasPassword: ( file. password != " " ) , hasExpiration: ( file. expr != " " ) , serverURL : URL ( string : server . wrappedValue! . url ) ! )
83
83
. contextMenu {
84
- createFileMenuButtons ( for: file, isPreviewing: false , isPrivate: file. private, expirationText: $expirationText, passwordText: $passwordText, fileNameText: $fileNameText)
84
+ fileContextMenu ( for: file, isPreviewing: false , isPrivate: file. private, expirationText: $expirationText, passwordText: $passwordText, fileNameText: $fileNameText)
85
85
}
86
86
}
87
87
. id ( file. id)
@@ -118,7 +118,14 @@ struct FileListView: View {
118
118
. toolbar {
119
119
ToolbarItem ( placement: . navigationBarTrailing) {
120
120
Menu {
121
- createFileMenuButtons ( for: file, isPreviewing: true , isPrivate: file. private, expirationText: $expirationText, passwordText: $passwordText, fileNameText: $fileNameText)
121
+ fileShareMenu ( for: file)
122
+ } label: {
123
+ Image ( systemName: " square.and.arrow.up " )
124
+ }
125
+ }
126
+ ToolbarItem ( placement: . navigationBarTrailing) {
127
+ Menu {
128
+ fileContextMenu ( for: file, isPreviewing: true , isPrivate: file. private, expirationText: $expirationText, passwordText: $passwordText, fileNameText: $fileNameText)
122
129
} label: {
123
130
Image ( systemName: " ellipsis.circle " )
124
131
}
@@ -255,8 +262,20 @@ struct FileListView: View {
255
262
}
256
263
}
257
264
258
- // Helper function to create consistent FileContextMenuButtons
259
- private func createFileMenuButtons( for file: DFFile , isPreviewing: Bool , isPrivate: Bool , expirationText: Binding < String > , passwordText: Binding < String > , fileNameText: Binding < String > ) -> FileContextMenuButtons {
265
+ private func fileShareMenu( for file: DFFile ) -> FileShareMenu {
266
+ FileShareMenu (
267
+ onCopyShareLink: {
268
+ UIPasteboard . general. string = file. url
269
+ } ,
270
+ onCopyRawLink: {
271
+ UIPasteboard . general. string = file. raw
272
+ } ,
273
+ )
274
+ }
275
+
276
+
277
+
278
+ private func fileContextMenu( for file: DFFile , isPreviewing: Bool , isPrivate: Bool , expirationText: Binding < String > , passwordText: Binding < String > , fileNameText: Binding < String > ) -> FileContextMenuButtons {
260
279
var isPrivate : Bool = isPrivate
261
280
return FileContextMenuButtons (
262
281
isPreviewing: isPreviewing,
@@ -506,52 +525,89 @@ struct FileRowView: View {
506
525
@State var isPrivate : Bool
507
526
@State var hasPassword : Bool
508
527
@State var hasExpiration : Bool
528
+ let serverURL : URL
509
529
510
530
private func getIcon( ) -> String {
511
- switch file. mime {
512
- case " image/jpeg " :
531
+ if file. mime. hasPrefix ( " image/ " ) {
513
532
return " photo.artframe "
514
- default :
533
+ } else if file. mime. hasPrefix ( " video/ " ) {
534
+ return " video.fill "
535
+ } else {
515
536
return " doc.fill "
516
537
}
517
538
}
518
539
540
+ private var thumbnailURL : URL {
541
+ var components = URLComponents ( url: serverURL. appendingPathComponent ( " /raw/ \( file. name) " ) , resolvingAgainstBaseURL: true )
542
+ components? . queryItems = [ URLQueryItem ( name: " thumb " , value: " true " ) ]
543
+ return components? . url ?? serverURL
544
+ }
545
+
546
+ init ( file: DFFile , isPrivate: Bool , hasPassword: Bool , hasExpiration: Bool , serverURL: URL ) {
547
+ self . file = file
548
+ self . isPrivate = isPrivate
549
+ self . hasPassword = hasPassword
550
+ self . hasExpiration = hasExpiration
551
+ self . serverURL = serverURL
552
+ }
553
+
519
554
var body : some View {
520
- VStack ( alignment: . leading, spacing: 2 ) {
521
- Text ( file. name)
522
- . font ( . headline)
523
- . lineLimit ( 1 )
524
- . foregroundColor ( . blue)
555
+ HStack {
556
+ if file. mime. hasPrefix ( " image/ " ) {
557
+ AsyncImage ( url: thumbnailURL) { image in
558
+ image
559
+ . resizable ( )
560
+ . scaledToFill ( )
561
+ } placeholder: {
562
+ ProgressView ( )
563
+ }
564
+ . frame ( width: 64 , height: 64 )
565
+ . clipped ( )
566
+ } else {
567
+ Label ( " " , systemImage: getIcon ( ) )
568
+ . font ( . system( size: 32 ) )
569
+ . frame ( width: 64 , height: 64 )
570
+ . foregroundColor ( . white)
571
+
572
+ }
525
573
526
- HStack ( spacing: 5 ) {
527
- Label ( file. mime, systemImage: getIcon ( ) )
528
- . font ( . caption)
529
- . labelStyle ( CustomLabel ( spacing: 3 ) )
530
-
531
- Label ( file. userUsername!, systemImage: " person " )
532
- . font ( . caption)
533
- . labelStyle ( CustomLabel ( spacing: 3 ) )
534
-
535
- Label ( " " , systemImage: " lock " )
536
- . font ( . caption)
537
- . labelStyle ( CustomLabel ( spacing: 3 ) )
538
- . opacity ( isPrivate ? 1 : 0 )
539
-
540
- Label ( " " , systemImage: " key " )
541
- . font ( . caption)
542
- . labelStyle ( CustomLabel ( spacing: 3 ) )
543
- . opacity ( hasPassword ? 1 : 0 )
574
+ VStack ( alignment: . leading, spacing: 2 ) {
544
575
545
- Label ( " " , systemImage : " calendar.badge.exclamationmark " )
546
- . font ( . caption )
547
- . labelStyle ( CustomLabel ( spacing : 3 ) )
548
- . opacity ( hasExpiration ? 1 : 0 )
576
+ Text ( file . name )
577
+ . font ( . headline )
578
+ . lineLimit ( 1 )
579
+ . foregroundColor ( . blue )
549
580
550
-
551
- Text ( file. formattedDate ( ) )
552
- . font ( . caption)
553
- . foregroundColor ( . secondary)
554
- . frame ( maxWidth: . infinity, alignment: . trailing)
581
+ HStack ( spacing: 5 ) {
582
+ Label ( file. mime, systemImage: getIcon ( ) )
583
+ . font ( . caption)
584
+ . labelStyle ( CustomLabel ( spacing: 3 ) )
585
+
586
+ Label ( file. userUsername!, systemImage: " person " )
587
+ . font ( . caption)
588
+ . labelStyle ( CustomLabel ( spacing: 3 ) )
589
+
590
+ Label ( " " , systemImage: " lock " )
591
+ . font ( . caption)
592
+ . labelStyle ( CustomLabel ( spacing: 3 ) )
593
+ . opacity ( isPrivate ? 1 : 0 )
594
+
595
+ Label ( " " , systemImage: " key " )
596
+ . font ( . caption)
597
+ . labelStyle ( CustomLabel ( spacing: 3 ) )
598
+ . opacity ( hasPassword ? 1 : 0 )
599
+
600
+ Label ( " " , systemImage: " calendar.badge.exclamationmark " )
601
+ . font ( . caption)
602
+ . labelStyle ( CustomLabel ( spacing: 3 ) )
603
+ . opacity ( hasExpiration ? 1 : 0 )
604
+
605
+
606
+ Text ( file. formattedDate ( ) )
607
+ . font ( . caption)
608
+ . foregroundColor ( . secondary)
609
+ . frame ( maxWidth: . infinity, alignment: . trailing)
610
+ }
555
611
}
556
612
}
557
613
}
0 commit comments