Skip to content

Commit 61edf8f

Browse files
committed
feat: add files from the pasteboard on iOS
Signed-off-by: Tommy van der Vorst <tommy@pixelspark.nl>
1 parent 92f7be0 commit 61edf8f

File tree

1 file changed

+84
-17
lines changed

1 file changed

+84
-17
lines changed

Sushitrain/BrowserView.swift

Lines changed: 84 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,13 @@ struct BrowserView: View {
178178
Log.warn("failed to access security scoped URL from file importer: \(url)")
179179
}
180180
}
181-
try? self.dropFiles(fu)
181+
do {
182+
try self.dropFiles(fu)
183+
}
184+
catch {
185+
Log.warn("failed to drop file: \(error)")
186+
self.error = error
187+
}
182188
for url in fu {
183189
url.stopAccessingSecurityScopedResource()
184190
}
@@ -321,6 +327,25 @@ struct BrowserView: View {
321327
}
322328
}
323329

330+
@ViewBuilder private func addMenu() -> some View {
331+
Menu {
332+
Button("Select files...", systemImage: "plus") {
333+
showAddFilePicker = true
334+
}
335+
336+
#if os(iOS)
337+
Button("Paste files...", systemImage: "document.on.clipboard") {
338+
Task {
339+
await self.dropItemProviders(UIPasteboard.general.itemProviders)
340+
}
341+
}.disabled(UIPasteboard.general.itemProviders.isEmpty)
342+
#endif
343+
} label: {
344+
Label("Add...", systemImage: "plus")
345+
}.disabled(
346+
!folderExists || !self.folder.isRegularFolder || self.folder.folderType() == SushitrainFolderTypeReceiveOnly)
347+
}
348+
324349
@ViewBuilder private func folderMenu() -> some View {
325350
Menu {
326351
#if os(iOS)
@@ -339,17 +364,11 @@ struct BrowserView: View {
339364
NavigationLink(destination: FileView(file: entry, showPath: false, siblings: nil)) {
340365
Label("Subdirectory properties...", systemImage: "folder.badge.gearshape")
341366
}
342-
343-
Divider()
344367
}
345368
}
346369

347370
if folderExists {
348-
if self.folder.isRegularFolder && self.folder.folderType() != SushitrainFolderTypeReceiveOnly {
349-
Button("Add files...", systemImage: "plus") {
350-
showAddFilePicker = true
351-
}
352-
}
371+
self.addMenu()
353372

354373
#if os(iOS)
355374
Button(openInFilesAppLabel, systemImage: "arrow.up.forward.app") {
@@ -419,6 +438,43 @@ struct BrowserView: View {
419438
try self.dropFiles(urls)
420439
}
421440

441+
private func dropItemProviders(_ items: [NSItemProvider]) async {
442+
var urls: [URL] = []
443+
444+
for item in items {
445+
do {
446+
let tempURL: URL? = try await withCheckedThrowingContinuation { cont in
447+
// TODO: add file coordination
448+
let _ = item.loadFileRepresentation(for: UTType.data, openInPlace: true) { tempURL, wasOpenedInPlace, err in
449+
if let err = err {
450+
cont.resume(throwing: err)
451+
return
452+
}
453+
else {
454+
cont.resume(returning: tempURL)
455+
}
456+
}
457+
}
458+
459+
if let tempURL = tempURL {
460+
urls.append(tempURL)
461+
}
462+
}
463+
catch {
464+
Log.warn("failed to load file representation for item: \(error)")
465+
}
466+
}
467+
468+
// Process the files
469+
do {
470+
try self.dropFiles(urls)
471+
}
472+
catch {
473+
Log.warn("failed to drop files: \(error)")
474+
self.error = error
475+
}
476+
}
477+
422478
private func dropFiles(_ urls: [URL]) throws {
423479
// Find out the native location of our folder
424480
var error: NSError? = nil
@@ -444,16 +500,23 @@ struct BrowserView: View {
444500
var pathsToSelect: [String] = []
445501

446502
if FileManager.default.fileExists(atPath: localNativeURL.path) {
503+
var retainedError: Error? = nil
447504
for url in urls {
448-
// Copy source to folder
449-
let targetURL = localNativeURL.appendingPathComponent(
450-
url.lastPathComponent, isDirectory: false)
451-
try FileManager.default.copyItem(at: url, to: targetURL)
452-
453-
// Select the dropped file
454-
if folder.isSelective() {
455-
let localURL = (self.prefix.withoutEndingSlash + "/" + url.lastPathComponent).withoutStartingSlash
456-
pathsToSelect.append(localURL)
505+
do {
506+
// Copy source to folder
507+
let targetURL = localNativeURL.appendingPathComponent(
508+
url.lastPathComponent, isDirectory: false)
509+
try FileManager.default.copyItem(at: url, to: targetURL)
510+
511+
// Select the dropped file
512+
if folder.isSelective() {
513+
let localURL = (self.prefix.withoutEndingSlash + "/" + url.lastPathComponent).withoutStartingSlash
514+
pathsToSelect.append(localURL)
515+
}
516+
}
517+
catch {
518+
Log.warn("failed to copy a dropped file: \(error)")
519+
retainedError = error
457520
}
458521
}
459522

@@ -462,6 +525,10 @@ struct BrowserView: View {
462525
}
463526

464527
try self.folder.rescanSubdirectory(self.prefix)
528+
529+
if let re = retainedError {
530+
throw re
531+
}
465532
}
466533
}
467534

0 commit comments

Comments
 (0)