mirror of
https://github.com/leonboe1/QuickDrop.git
synced 2026-11-11 19:11:10 +00:00
Add preparing label when sending large files from within app
This commit is contained in:
1 parent
7d6d0f3482
commit
c7a3635689
6 files changed
+347
-40
No files matched your search
@@ -43,7 +43,7 @@
|
||||
"location" : "https://github.com/leonboe1/LUI.git",
|
||||
"state" : {
|
||||
"branch" : "main",
|
||||
"revision" : "0fa79d937a5948c59f44c64b12af21c7d3b408e5"
|
||||
"revision" : "dc041b1fee0be5a8546044b219ac03d7580da6ad"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1640"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
buildArchitectures = "Automatic">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "EB5C37E12E377C2E0052EFD7"
|
||||
BuildableName = "QuickDropiOS.app"
|
||||
BlueprintName = "QuickDropiOS"
|
||||
ReferencedContainer = "container:QuickDrop.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "EB5C37E12E377C2E0052EFD7"
|
||||
BuildableName = "QuickDropiOS.app"
|
||||
BlueprintName = "QuickDropiOS"
|
||||
ReferencedContainer = "container:QuickDrop.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "EB5C37E12E377C2E0052EFD7"
|
||||
BuildableName = "QuickDropiOS.app"
|
||||
BlueprintName = "QuickDropiOS"
|
||||
ReferencedContainer = "container:QuickDrop.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1640"
|
||||
wasCreatedForAppExtension = "YES"
|
||||
version = "2.0">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
buildArchitectures = "Automatic">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "EB950B2C2E52027F002D68FA"
|
||||
BuildableName = "iOSShareExtension.appex"
|
||||
BlueprintName = "iOSShareExtension"
|
||||
ReferencedContainer = "container:QuickDrop.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "EB5C37E12E377C2E0052EFD7"
|
||||
BuildableName = "QuickDropiOS.app"
|
||||
BlueprintName = "QuickDropiOS"
|
||||
ReferencedContainer = "container:QuickDrop.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = ""
|
||||
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||
launchStyle = "0"
|
||||
askForAppToLaunch = "Yes"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<RemoteRunnable
|
||||
runnableDebuggingMode = "0"
|
||||
BundleIdentifier = "com.apple.mobileslideshow"
|
||||
RemotePath = "/var/containers/Bundle/Application/3D45D27D-5ADC-417F-B4DE-19000341E9B7/Photos.app">
|
||||
</RemoteRunnable>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "EB5C37E12E377C2E0052EFD7"
|
||||
BuildableName = "QuickDropiOS.app"
|
||||
BlueprintName = "QuickDropiOS"
|
||||
ReferencedContainer = "container:QuickDrop.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
askForAppToLaunch = "Yes"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "EB5C37E12E377C2E0052EFD7"
|
||||
BuildableName = "QuickDropiOS.app"
|
||||
BlueprintName = "QuickDropiOS"
|
||||
ReferencedContainer = "container:QuickDrop.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -6094,6 +6094,113 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Preparing" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"ar" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "جارٍ التحضير..."
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Bereite vor..."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Preparing..."
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Preparando..."
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Préparation..."
|
||||
}
|
||||
},
|
||||
"hu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Előkészítés folyamatban..."
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Preparazione in corso..."
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "準備中..."
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "준비 중..."
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Voorbereiden..."
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Preparando..."
|
||||
}
|
||||
},
|
||||
"pt-PT" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "A preparar..."
|
||||
}
|
||||
},
|
||||
"ro" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Se pregătește..."
|
||||
}
|
||||
},
|
||||
"ru" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Подготовка..."
|
||||
}
|
||||
},
|
||||
"th" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "กำลังเตรียม..."
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Підготовка..."
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "准备中…"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PrivacyPolicy" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
|
||||
@@ -112,17 +112,11 @@ struct DeviceListView: View {
|
||||
sendModel.textToSend = attachments.textToSend
|
||||
sendModel.selectDevice(device: device)
|
||||
} label: {
|
||||
DeviceButton(device: device, isSelected: isSelected, progress: sendModel.progressState, progressValue: sendModel.progressValue)
|
||||
DeviceButtonLabel(device: device, isSelected: isSelected, progress: sendModel.progressState, progressValue: sendModel.progressValue)
|
||||
}
|
||||
}
|
||||
else {
|
||||
SendPickerButton {
|
||||
DeviceButton(device: device, isSelected: isSelected, progress: sendModel.progressState, progressValue: sendModel.progressValue)
|
||||
} onResult: { urls, text in
|
||||
sendModel.urls = urls ?? []
|
||||
sendModel.textToSend = text
|
||||
sendModel.selectDevice(device: device)
|
||||
}
|
||||
DeviceFilePickerButton(device: device, isSelected: isSelected, progressState: sendModel.progressState, progressValue: sendModel.progressValue, sendModel: sendModel)
|
||||
}
|
||||
}
|
||||
.animation(.easeInOut, value: sendModel.progressValue)
|
||||
@@ -153,7 +147,32 @@ struct DeviceListView: View {
|
||||
}
|
||||
|
||||
|
||||
struct DeviceButton: View {
|
||||
struct DeviceFilePickerButton: View {
|
||||
|
||||
let device: RemoteDeviceInfo
|
||||
let isSelected: Bool
|
||||
let progressState: String?
|
||||
let progressValue: Double?
|
||||
let sendModel: SendModel
|
||||
|
||||
@State private var isPreparing = false
|
||||
|
||||
var body: some View {
|
||||
SendPickerButton {
|
||||
DeviceButtonLabel(device: device, isSelected: isPreparing || isSelected, progress: isPreparing ? "Preparing".localized() : progressState, progressValue: progressValue)
|
||||
} onResult: { urls, text in
|
||||
isPreparing = false
|
||||
sendModel.urls = urls ?? []
|
||||
sendModel.textToSend = text
|
||||
sendModel.selectDevice(device: device)
|
||||
} onPrepare: {
|
||||
isPreparing = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct DeviceButtonLabel: View {
|
||||
|
||||
let device: RemoteDeviceInfo
|
||||
let isSelected: Bool
|
||||
|
||||
@@ -13,6 +13,7 @@ import UniformTypeIdentifiers
|
||||
struct SendPickerButton<Label: View>: View {
|
||||
var label: () -> Label
|
||||
var onResult: (_ urls: [URL]?, _ text: String?) -> Void
|
||||
var onPrepare: (() -> Void)? = nil
|
||||
|
||||
@State private var showPhotoPicker = false
|
||||
@State private var selectedPhotoItems: [PhotosPickerItem] = []
|
||||
@@ -45,6 +46,7 @@ struct SendPickerButton<Label: View>: View {
|
||||
)
|
||||
.onChange(of: selectedPhotoItems) { newItems in
|
||||
guard !newItems.isEmpty else { return }
|
||||
onPrepare?()
|
||||
updatedPhotoSelection(content: newItems)
|
||||
}
|
||||
// File picker
|
||||
@@ -83,37 +85,37 @@ struct SendPickerButton<Label: View>: View {
|
||||
if let dataUrl = try await item.loadTransferable(type: Data.self) {
|
||||
|
||||
if let contentType = item.supportedContentTypes.first {
|
||||
// Step 2: make the URL file name and a get a file extention.
|
||||
// Step 2: make the URL file name and a get a file extention.
|
||||
let url = fileManager.temporaryDirectory.appendingPathComponent("\(UUID().uuidString).\(contentType.preferredFilenameExtension ?? "")")
|
||||
|
||||
do {
|
||||
// Step 3: write to temp App file directory and return in completionHandler
|
||||
try dataUrl.write(to: url)
|
||||
return url
|
||||
} catch {
|
||||
log("Faied to write data to file: \(error)")
|
||||
throw error
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
do {
|
||||
// Step 3: write to temp App file directory and return in completionHandler
|
||||
try dataUrl.write(to: url)
|
||||
return url
|
||||
} catch {
|
||||
log("Failed to write data to file: \(error)")
|
||||
throw error
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// let destination = fileManager.temporaryDirectory.appendingPathComponent(dataUrl.url.lastPathComponent)
|
||||
//
|
||||
// // overwrite if file exists
|
||||
// if fileManager.fileExists(atPath: destination.path) {
|
||||
// try fileManager.removeItem(at: destination)
|
||||
// }
|
||||
//
|
||||
// log("Copying photo at \(dataUrl.url) to \(destination)")
|
||||
//
|
||||
// do {
|
||||
// try fileManager.copyItem(at: dataUrl.url, to: destination)
|
||||
// }
|
||||
// catch {
|
||||
// log("Failed to copy photo: \(error)")
|
||||
// throw error
|
||||
// }
|
||||
// return destination
|
||||
// let destination = fileManager.temporaryDirectory.appendingPathComponent(dataUrl.url.lastPathComponent)
|
||||
//
|
||||
// // overwrite if file exists
|
||||
// if fileManager.fileExists(atPath: destination.path) {
|
||||
// try fileManager.removeItem(at: destination)
|
||||
// }
|
||||
//
|
||||
// log("Copying photo at \(dataUrl.url) to \(destination)")
|
||||
//
|
||||
// do {
|
||||
// try fileManager.copyItem(at: dataUrl.url, to: destination)
|
||||
// }
|
||||
// catch {
|
||||
// log("Failed to copy photo: \(error)")
|
||||
// throw error
|
||||
// }
|
||||
// return destination
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -135,7 +137,7 @@ struct SendPickerButton<Label: View>: View {
|
||||
/// File representation
|
||||
fileprivate struct DataUrl: Transferable {
|
||||
let url: URL
|
||||
|
||||
|
||||
static var transferRepresentation: some TransferRepresentation {
|
||||
FileRepresentation(contentType: .data) { data in
|
||||
|
||||
|
||||
Reference in new issue
Block a user