Add drag-out export from item list
This commit is contained in:
parent
d1c7d1de73
commit
f6ab43833c
@ -37,6 +37,7 @@ struct ItemListColumnView<MenuContent: View>: View {
|
|||||||
let searchPrompt: String
|
let searchPrompt: String
|
||||||
let chooseFolderAction: () -> Void
|
let chooseFolderAction: () -> Void
|
||||||
let dropAction: ([NSItemProvider]) -> Bool
|
let dropAction: ([NSItemProvider]) -> Bool
|
||||||
|
let dragProvider: (MinecraftContentItem) -> NSItemProvider
|
||||||
let itemContextMenu: (MinecraftContentItem) -> MenuContent
|
let itemContextMenu: (MinecraftContentItem) -> MenuContent
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@ -51,6 +52,9 @@ struct ItemListColumnView<MenuContent: View>: View {
|
|||||||
List(items, selection: $selectedItemID) { item in
|
List(items, selection: $selectedItemID) { item in
|
||||||
ContentRowView(item: item)
|
ContentRowView(item: item)
|
||||||
.tag(item.id)
|
.tag(item.id)
|
||||||
|
.onDrag {
|
||||||
|
dragProvider(item)
|
||||||
|
}
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
itemContextMenu(item)
|
itemContextMenu(item)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -321,6 +321,7 @@ struct ItemListColumnPreviewContainer: View {
|
|||||||
searchPrompt: "Search Worlds",
|
searchPrompt: "Search Worlds",
|
||||||
chooseFolderAction: {},
|
chooseFolderAction: {},
|
||||||
dropAction: { _ in false },
|
dropAction: { _ in false },
|
||||||
|
dragProvider: { _ in NSItemProvider() },
|
||||||
itemContextMenu: { item in
|
itemContextMenu: { item in
|
||||||
Button("Reveal \(item.displayName)") {}
|
Button("Reveal \(item.displayName)") {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,6 +74,7 @@ struct ContentView: View {
|
|||||||
searchPrompt: searchPrompt,
|
searchPrompt: searchPrompt,
|
||||||
chooseFolderAction: pickFolder,
|
chooseFolderAction: pickFolder,
|
||||||
dropAction: handleDroppedProviders(_:),
|
dropAction: handleDroppedProviders(_:),
|
||||||
|
dragProvider: dragProvider(for:),
|
||||||
itemContextMenu: itemContextMenu(for:)
|
itemContextMenu: itemContextMenu(for:)
|
||||||
)
|
)
|
||||||
.navigationSplitViewColumnWidth(min: 340, ideal: 400, max: 460)
|
.navigationSplitViewColumnWidth(min: 340, ideal: 400, max: 460)
|
||||||
@ -653,7 +654,13 @@ struct ContentView: View {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return source.availability == .available
|
return source.availability == .available && source.capabilities.canExportPortablePackages
|
||||||
|
}
|
||||||
|
|
||||||
|
private func sourceForItem(_ item: MinecraftContentItem) -> MinecraftSource? {
|
||||||
|
library.visibleSources.first(where: { source in
|
||||||
|
source.items.contains(where: { $0.id == item.id })
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private func saveItem(_ item: MinecraftContentItem) {
|
private func saveItem(_ item: MinecraftContentItem) {
|
||||||
@ -791,6 +798,44 @@ struct ContentView: View {
|
|||||||
private func archiveType(for item: MinecraftContentItem) -> UTType {
|
private func archiveType(for item: MinecraftContentItem) -> UTType {
|
||||||
UTType(filenameExtension: item.contentType.archiveExtension) ?? .data
|
UTType(filenameExtension: item.contentType.archiveExtension) ?? .data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func dragProvider(for item: MinecraftContentItem) -> NSItemProvider {
|
||||||
|
let provider = NSItemProvider()
|
||||||
|
let contentType = archiveType(for: item)
|
||||||
|
provider.suggestedName = itemActionService.suggestedArchiveFilename(for: item)
|
||||||
|
|
||||||
|
provider.registerFileRepresentation(
|
||||||
|
forTypeIdentifier: contentType.identifier,
|
||||||
|
fileOptions: [],
|
||||||
|
visibility: .all
|
||||||
|
) { completion in
|
||||||
|
guard let source = sourceForItem(item), areFileActionsEnabled(for: item) else {
|
||||||
|
completion(nil, false, SourceAccessError.accessFailed(reason: "This item is not currently available for export."))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let task = Task {
|
||||||
|
do {
|
||||||
|
let representation = try await library.externalRepresentation(
|
||||||
|
for: item,
|
||||||
|
in: source,
|
||||||
|
preferredKind: .portablePackage
|
||||||
|
)
|
||||||
|
completion(representation.url, representation.isTemporary, nil)
|
||||||
|
} catch {
|
||||||
|
completion(nil, false, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let progress = Progress(totalUnitCount: 1)
|
||||||
|
progress.cancellationHandler = {
|
||||||
|
task.cancel()
|
||||||
|
}
|
||||||
|
return progress
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ContentView_Previews: PreviewProvider {
|
struct ContentView_Previews: PreviewProvider {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user