diff --git a/QuickDrop.xcodeproj/project.pbxproj b/QuickDrop.xcodeproj/project.pbxproj index 182a36b..686ce5f 100644 --- a/QuickDrop.xcodeproj/project.pbxproj +++ b/QuickDrop.xcodeproj/project.pbxproj @@ -44,13 +44,13 @@ EB7CD1452D6FB0C300CB0CB5 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */; }; EB7CD1462D6FB0E800CB0CB5 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */; }; EB7CD1472D6FB0E800CB0CB5 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */; }; - EB7F54102D78E6DF00989564 /* Sidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7F540F2D78E6DD00989564 /* Sidebar.swift */; }; EB7F54122D78E96000989564 /* TutorialView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7F54112D78E95C00989564 /* TutorialView.swift */; }; EB7F54142D78E9E700989564 /* LicenseWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7F54132D78E9E400989564 /* LicenseWindow.swift */; }; + EB91F0EB2DEDC741006C1867 /* CableConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB91F0EA2DEDC73D006C1867 /* CableConnectionView.swift */; }; EB9237C42D7CDF8B00CA3A42 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 69D2C32B29E77F2200EC7E30 /* Localizable.strings */; }; EB9237C52D7CDF9000CA3A42 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 69D2C33629E78DF400EC7E30 /* Localizable.stringsdict */; }; - EB96ED8B2D7F7CF7004B3FF1 /* QrCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8A2D7F7CF4004B3FF1 /* QrCodeView.swift */; }; - EB96ED8C2D7F7E7B004B3FF1 /* QrCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8A2D7F7CF4004B3FF1 /* QrCodeView.swift */; }; + EB96ED8B2D7F7CF7004B3FF1 /* SmallSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8A2D7F7CF4004B3FF1 /* SmallSheetView.swift */; }; + EB96ED8C2D7F7E7B004B3FF1 /* SmallSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8A2D7F7CF4004B3FF1 /* SmallSheetView.swift */; }; EB96ED8D2D7F7EA3004B3FF1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 69DA9A1329E0BF5200A442DA /* Assets.xcassets */; }; EB96ED8F2D7F8105004B3FF1 /* Localized.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8E2D7F8103004B3FF1 /* Localized.swift */; }; EB96ED902D7F8114004B3FF1 /* Localized.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8E2D7F8103004B3FF1 /* Localized.swift */; }; @@ -211,9 +211,9 @@ EB6E743D2DD5C76F00331466 /* ConnectionFailureTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionFailureTracker.swift; sourceTree = ""; }; EB6F62D62D91F4AC00534EC2 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; EB7CD1442D6FB0C100CB0CB5 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; }; - EB7F540F2D78E6DD00989564 /* Sidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar.swift; sourceTree = ""; }; EB7F54112D78E95C00989564 /* TutorialView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TutorialView.swift; sourceTree = ""; }; EB7F54132D78E9E400989564 /* LicenseWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicenseWindow.swift; sourceTree = ""; }; + EB91F0EA2DEDC73D006C1867 /* CableConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CableConnectionView.swift; sourceTree = ""; }; EB9237B52D7CDCE700CA3A42 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/ShareViewController.strings; sourceTree = ""; }; EB9237B72D7CDD7200CA3A42 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ShareViewController.strings; sourceTree = ""; }; EB9237B92D7CDE3B00CA3A42 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/ShareViewController.strings; sourceTree = ""; }; @@ -222,7 +222,7 @@ EB9237BF2D7CDE3E00CA3A42 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/ShareViewController.strings"; sourceTree = ""; }; EB9237C12D7CDE4000CA3A42 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/ShareViewController.strings; sourceTree = ""; }; EB9237C32D7CDE4100CA3A42 /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = th; path = th.lproj/ShareViewController.strings; sourceTree = ""; }; - EB96ED8A2D7F7CF4004B3FF1 /* QrCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QrCodeView.swift; sourceTree = ""; }; + EB96ED8A2D7F7CF4004B3FF1 /* SmallSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmallSheetView.swift; sourceTree = ""; }; EB96ED8E2D7F8103004B3FF1 /* Localized.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Localized.swift; sourceTree = ""; }; EBCC27F82D80C9F70079C478 /* Zip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Zip.swift; sourceTree = ""; }; EBD2A2162D2860BE00BCB8E2 /* WelcomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreen.swift; sourceTree = ""; }; @@ -232,7 +232,7 @@ /* Begin PBXFileSystemSynchronizedRootGroup section */ EB1A7E422DD4D8BD00A6D5A3 /* SelfTest */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = SelfTest; sourceTree = ""; }; EB6E743F2DD5CBFB00331466 /* IssueViews */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = IssueViews; sourceTree = ""; }; - EB7CD13B2D6F8B6500CB0CB5 /* IAP */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = IAP; sourceTree = ""; }; + EB7CD13B2D6F8B6500CB0CB5 /* Plus */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Plus; sourceTree = ""; }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ @@ -279,7 +279,7 @@ children = ( 699DEBA52AB0573200115D22 /* ShareViewController.swift */, EBCC27F82D80C9F70079C478 /* Zip.swift */, - EB96ED8A2D7F7CF4004B3FF1 /* QrCodeView.swift */, + EB96ED8A2D7F7CF4004B3FF1 /* SmallSheetView.swift */, 691F53B92ABB70840089FD92 /* DeviceListCell.swift */, 691F53BA2ABB70840089FD92 /* DeviceListCell.xib */, 699DEBA72AB0573200115D22 /* ShareViewController.xib */, @@ -321,12 +321,12 @@ EB7F54112D78E95C00989564 /* TutorialView.swift */, EB1A7E422DD4D8BD00A6D5A3 /* SelfTest */, EB7F54132D78E9E400989564 /* LicenseWindow.swift */, + EB91F0EA2DEDC73D006C1867 /* CableConnectionView.swift */, EB6F62D62D91F4AC00534EC2 /* SettingsView.swift */, EB36435F2D73A29F009CDFF8 /* AudioManager.swift */, EB6E743F2DD5CBFB00331466 /* IssueViews */, EB96ED8E2D7F8103004B3FF1 /* Localized.swift */, - EB7F540F2D78E6DD00989564 /* Sidebar.swift */, - EB7CD13B2D6F8B6500CB0CB5 /* IAP */, + EB7CD13B2D6F8B6500CB0CB5 /* Plus */, 69DA9A1329E0BF5200A442DA /* Assets.xcassets */, 69D2C33629E78DF400EC7E30 /* Localizable.stringsdict */, 69D2C32B29E77F2200EC7E30 /* Localizable.strings */, @@ -431,7 +431,7 @@ fileSystemSynchronizedGroups = ( EB1A7E422DD4D8BD00A6D5A3 /* SelfTest */, EB6E743F2DD5CBFB00331466 /* IssueViews */, - EB7CD13B2D6F8B6500CB0CB5 /* IAP */, + EB7CD13B2D6F8B6500CB0CB5 /* Plus */, ); name = QuickDrop; packageProductDependencies = ( @@ -559,7 +559,7 @@ files = ( EB96ED902D7F8114004B3FF1 /* Localized.swift in Sources */, 699DEBA62AB0573200115D22 /* ShareViewController.swift in Sources */, - EB96ED8B2D7F7CF7004B3FF1 /* QrCodeView.swift in Sources */, + EB96ED8B2D7F7CF7004B3FF1 /* SmallSheetView.swift in Sources */, EBCC27F92D80C9F90079C478 /* Zip.swift in Sources */, EB7CD1462D6FB0E800CB0CB5 /* Logger.swift in Sources */, 691F53BB2ABB70840089FD92 /* DeviceListCell.swift in Sources */, @@ -572,10 +572,10 @@ files = ( EBD2A2172D2860C100BCB8E2 /* WelcomeScreen.swift in Sources */, EB3643602D73A2A2009CDFF8 /* AudioManager.swift in Sources */, - EB96ED8C2D7F7E7B004B3FF1 /* QrCodeView.swift in Sources */, + EB91F0EB2DEDC741006C1867 /* CableConnectionView.swift in Sources */, + EB96ED8C2D7F7E7B004B3FF1 /* SmallSheetView.swift in Sources */, EB7F54142D78E9E700989564 /* LicenseWindow.swift in Sources */, 69DA9A1229E0BF5100A442DA /* AppDelegate.swift in Sources */, - EB7F54102D78E6DF00989564 /* Sidebar.swift in Sources */, EB6F62D72D91F4AF00534EC2 /* SettingsView.swift in Sources */, EB7F54122D78E96000989564 /* TutorialView.swift in Sources */, EB96ED8F2D7F8105004B3FF1 /* Localized.swift in Sources */, @@ -825,8 +825,8 @@ MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; - SHARED_BUILD = 41; - SHARED_VERSION = 1.9.2; + SHARED_BUILD = 42; + SHARED_VERSION = 1.9.3; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; @@ -884,8 +884,8 @@ MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; - SHARED_BUILD = 41; - SHARED_VERSION = 1.9.2; + SHARED_BUILD = 42; + SHARED_VERSION = 1.9.3; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; diff --git a/QuickDrop/AppDelegate.swift b/QuickDrop/AppDelegate.swift index 43b633b..4307ac6 100644 --- a/QuickDrop/AppDelegate.swift +++ b/QuickDrop/AppDelegate.swift @@ -23,7 +23,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele var welcomeWindow: NSWindow? var plusWindow: NSWindow? - private var qrCodeSheetView: NSPanel? = nil + private var sheetView: NSPanel? = nil private var sheetAttachedWindow: NSWindow? = nil var firewallAlertWindow: NSWindow? @@ -35,6 +35,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele var visibleItem: NSMenuItem? = nil let hasConnectionMonitor = NWPathMonitor() + + // MARK: NSApplicationDelegate functions + func applicationDidFinishLaunching(_: Notification) { let menu = NSMenu() @@ -113,20 +116,35 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele let queue2 = DispatchQueue(label: "NetworkConnectionMonitor") hasConnectionMonitor.start(queue: queue2) } + + + func applicationShouldHandleReopen(_: NSApplication, hasVisibleWindows _: Bool) -> Bool { + openWelcomeScreen() + statusItem?.isVisible = true + return true + } + - func performDeviceToDeviceCheck() { - let scanner = DeviceToDeviceHeuristicScanner() - scanner.scan { allowed in - if allowed { - log("✅ Device-to-device likely allowed (peer responded on LAN).") - self.apIsolationAlertWindow?.close() - } else { - log("❌ Device-to-device check failed. Informing user...") - self.openAlert(type: .ApIsolation) - } - } + public func userNotificationCenter(_: UNUserNotificationCenter, + willPresent _: UNNotification, + withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { + completionHandler([.sound, .banner]) + } + + + func applicationWillTerminate(_: Notification) { + UNUserNotificationCenter.current().removeAllDeliveredNotifications() + iapManager?.stopObserving() } + + func applicationSupportsSecureRestorableState(_: NSApplication) -> Bool { + return true + } + + + // MARK: - Button Actions + @objc func sendClipboard() { let pasteboard = NSPasteboard.general @@ -136,11 +154,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele sharingService?.perform(withItems: [clipboardString]) } + @objc func openWelcomeScreen() { - // Create the welcome screen SwiftUI view - let welcomeView = WelcomeScreen(openPlusScreen: openPlusScreen, openAppAdvertisementView: openQrCodeView, checkForNetworkIssues: performDeviceToDeviceCheck) + let welcomeView = WelcomeScreen(openPlusScreen: openPlusScreen, + openAppAdvertisementView: { self.openSheetView(type: .downloadAndroidApp) }, + openCableTransmissionView: { self.openSheetView(type: .downloadCableConnectionApp) }, + checkForNetworkIssues: performDeviceToDeviceCheck) - // Create an NSWindow to host the SwiftUI view + welcomeWindow = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 400, height: 280), styleMask: [.titled, .closable], @@ -162,43 +183,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele welcomeWindow?.makeKeyAndOrderFront(nil) welcomeWindow?.level = .normal } + - private func openQrCodeView() { - if qrCodeSheetView == nil { - let contentView = QrCodeView(advertisesApp: true) { - self.closeQrCodeView() - } - - let hostingView = NSHostingView(rootView: contentView) - - let panel = NSPanel(contentRect: NSRect(x: 0, y: 0, width: qrCodeViewSize.width, height: qrCodeViewSize.height), - styleMask: [.titled, .closable, .utilityWindow], - backing: .buffered, - defer: false) - - panel.contentView = hostingView - - qrCodeSheetView = panel - - if let mainWindow = NSApp.mainWindow { - sheetAttachedWindow = mainWindow - mainWindow.beginSheet(panel) { _ in } - } - } - } - - private func closeQrCodeView() { - if let mainWindow = sheetAttachedWindow, let qrCodeView = qrCodeSheetView { - mainWindow.endSheet(qrCodeView) - - qrCodeSheetView = nil - sheetAttachedWindow = nil - } - } - @objc func openPlusScreen() { // Create the welcome screen SwiftUI view - let plusView = GetPlusView(closeView: { + let plusView = PlusView(closeView: { log("Closing plus screen") self.plusWindow?.close() }) @@ -225,12 +214,51 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele plusWindow?.makeKeyAndOrderFront(nil) plusWindow?.level = .normal } + + + private func openSheetView(type: SheetViewType) { + if sheetView == nil { + let contentView = SmallSheetView(type: type) { + self.closeSheetView() + } + let hostingView = NSHostingView(rootView: contentView) + + let panel = NSPanel(contentRect: NSRect(x: 0, y: 0, width: smallSheetViewSize.width, height: smallSheetViewSize.height), + styleMask: [.titled, .closable, .utilityWindow], + backing: .buffered, + defer: false) + + panel.contentView = hostingView + + sheetView = panel + + if let mainWindow = NSApp.mainWindow { + sheetAttachedWindow = mainWindow + mainWindow.beginSheet(panel) { _ in } + } + } + } + + + private func closeSheetView() { + if let mainWindow = sheetAttachedWindow, let sheetView = sheetView { + mainWindow.endSheet(sheetView) + + self.sheetView = nil + self.sheetAttachedWindow = nil + } + } + + + // MARK: - Alerts and Notifications + enum AlertType: String { case ApIsolation case NetworkFilter case Firewall } + func openAlert(type: AlertType) { log("Opening Alert for \(type)") @@ -266,36 +294,42 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele alertWindow.level = .normal } } - - // Action for "Recommended Apps" menu item - @objc func openRecommendedApps() { - if let url = URL(string: "https://apps.apple.com/de/developer/leon-boettger/id1537384790") { - NSWorkspace.shared.open(url) + + + func showFirewallAlert() { + openAlert(type: .Firewall) + } + + + func showCopiedToClipboardAlert() { + DispatchQueue.main.async { + BezelNotification.show(messageText: "InsertedIntoClipboard".localized(), icon: .clipboard) + } + } + + + func showUnsupportedFileAlert(for device: RemoteDeviceInfo?) { + + DispatchQueue.main.async { + + NSApp.activate(ignoringOtherApps: true) + + let alert = NSAlert() + alert.alertStyle = .critical + + alert.messageText = String(format: NSLocalizedString("TransferError", value: "Failed to receive files from %@", comment: ""), arguments: [device?.name ?? "??"]) + alert.informativeText = "UnsupportedFileType".localized() + + alert.addButton(withTitle: "InformDeveloper".localized()) + alert.addButton(withTitle: "CloseAlert".localized()) + + let _ = alert.runModal() } } - func applicationShouldHandleReopen(_: NSApplication, hasVisibleWindows _: Bool) -> Bool { - openWelcomeScreen() - statusItem?.isVisible = true - return true - } - - public func userNotificationCenter(_: UNUserNotificationCenter, - willPresent _: UNNotification, - withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) - { - completionHandler([.sound, .banner]) - } - - func applicationWillTerminate(_: Notification) { - UNUserNotificationCenter.current().removeAllDeliveredNotifications() - iapManager?.stopObserving() - } - - func applicationSupportsSecureRestorableState(_: NSApplication) -> Bool { - return true - } - + + // MARK: - Transfer Handling + public func continueTransmission(accept: Bool, transferID: String, storeInTemp: Bool = false) { NearbyConnectionManager.shared.submitUserConsent(transferID: transferID, accept: accept, storeInTemp: storeInTemp) @@ -303,6 +337,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele activeIncomingTransfers.removeValue(forKey: transferID) } } + func obtainUserConsent(for transfer: TransferMetadata, from device: RemoteDeviceInfo) { @@ -382,6 +417,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele } } + private func pressAcceptButton(transferID: String) { if isFileTransferRestricted() { continueTransmission(accept: true, transferID: transferID, storeInTemp: true) @@ -392,35 +428,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele continueTransmission(accept: true, transferID: transferID) } } - - func showFirewallAlert() { - openAlert(type: .Firewall) - } - func showCopiedToClipboardAlert() { - DispatchQueue.main.async { - BezelNotification.show(messageText: "InsertedIntoClipboard".localized(), icon: .clipboard) - } - } - - func showUnsupportedFileAlert(for device: RemoteDeviceInfo?) { - - DispatchQueue.main.async { - - NSApp.activate(ignoringOtherApps: true) - - let alert = NSAlert() - alert.alertStyle = .critical - - alert.messageText = String(format: NSLocalizedString("TransferError", value: "Failed to receive files from %@", comment: ""), arguments: [device?.name ?? "??"]) - alert.informativeText = "UnsupportedFileType".localized() - - alert.addButton(withTitle: "InformDeveloper".localized()) - alert.addButton(withTitle: "CloseAlert".localized()) - - let _ = alert.runModal() - } - } func incomingTransfer(id: String, didFinishWith error: Error?) { @@ -490,6 +498,22 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele activeIncomingTransfers.removeValue(forKey: id) } + + + // MARK: - Helper Functions + + private func performDeviceToDeviceCheck() { + let scanner = DeviceToDeviceHeuristicScanner() + scanner.scan { allowed in + if allowed { + log("✅ Device-to-device likely allowed (peer responded on LAN).") + self.apIsolationAlertWindow?.close() + } else { + log("❌ Device-to-device check failed. Informing user...") + self.openAlert(type: .ApIsolation) + } + } + } } struct TransferInfo { diff --git a/QuickDrop/Assets.xcassets/iDroid.imageset/Contents.json b/QuickDrop/Assets.xcassets/iDroid.imageset/Contents.json new file mode 100644 index 0000000..f6d18fc --- /dev/null +++ b/QuickDrop/Assets.xcassets/iDroid.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "FileTransfer Kopie-1024.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/QuickDrop/Assets.xcassets/iDroid.imageset/FileTransfer Kopie-1024.png b/QuickDrop/Assets.xcassets/iDroid.imageset/FileTransfer Kopie-1024.png new file mode 100644 index 0000000..3585b0b Binary files /dev/null and b/QuickDrop/Assets.xcassets/iDroid.imageset/FileTransfer Kopie-1024.png differ diff --git a/QuickDrop/Base.lproj/Localizable.strings b/QuickDrop/Base.lproj/Localizable.strings index 352e2d6..f65e6e2 100644 --- a/QuickDrop/Base.lproj/Localizable.strings +++ b/QuickDrop/Base.lproj/Localizable.strings @@ -196,3 +196,7 @@ Once this is done, your phone will be able to connect to your Mac."; Your Mac may have a faulty packet filter enabled, which might be installed by your antivirus program (e.g., ESET). Open System Preferences > Network > VPN & Filter and disable the content filter. Once this is done, you should be able to transfer files successfully."; + +"TransmitUsingCable" = "Transfer With Cable"; +"DownloadCableConnectionApp" = "Download iDroid"; +"DownloadCableConnectionAppDescription" = "If you want to transfer files and browse the storage of your Android device via USB, you can now do so with the new iDroid app.\n\niDroid supports downloading and uploading files and whole folders using Drag & Drop. iDroid is free for a limited time!"; diff --git a/QuickDrop/CableConnectionView.swift b/QuickDrop/CableConnectionView.swift new file mode 100644 index 0000000..84ed10f --- /dev/null +++ b/QuickDrop/CableConnectionView.swift @@ -0,0 +1,110 @@ +// +// CableConnectionView.swift +// QuickDrop +// +// Created by Leon Böttger on 02.06.25. +// + +//import SwiftUI +// +//struct CableConnectionView: View { +// let closeView: () -> Void +// +// @Environment(\.colorScheme) var colorScheme +// +// var body: some View { +// +// VStack { +// +// HStack { +// +// HStack(spacing: 5) { +// +// let imageSize: CGFloat = advertisesApp ? 20 : 25 +// +// Image(.quickDropIcon) +// .resizable() +// .aspectRatio(contentMode: .fit) +// .frame(width: imageSize, height: imageSize) +// +// if advertisesApp { +// Text("QuickDrop") +// } +// } +// .padding(.leading, 18) +// +// if !advertisesApp { +// Spacer() +// +// HStack { +// Text("ConnectWithQuickDropApp") +// .padding(5) +// .padding(.horizontal, 4) +// .background(Capsule().fill(colorScheme == .light ? .white : .white.opacity(0.15)).opacity(connectWithApp ? 1 : 0)) +// +// Text("ConnectWithoutApp") +// .padding(5) +// .padding(.horizontal, 4) +// .background(Capsule().fill(colorScheme == .light ? .white : .white.opacity(0.15)).opacity(connectWithApp ? 0 : 1)) +// } +// .padding(.horizontal, 1) +// .padding(4) +// .background(Capsule().fill(Color.gray.opacity(colorScheme == .light ? 0.2 : 0.15))) +// .onTapGesture { +// withAnimation { +// connectWithApp.toggle() +// } +// } +// .animation(.smooth, value:connectWithApp) +// } +// +// Spacer() +// +// Button(action: { +// closeView() +// }, label: { +// Image(systemName: "xmark") +// .font(.system(size: 20)) +// .foregroundColor(.gray) +// }) +// .buttonStyle(PlainButtonStyle()) +// } +// .padding(.trailing, 15) +// .padding(.leading, 10) +// .padding(.top, 15) +// .padding(.bottom, advertisesApp ? -10 : 0) +// +// Spacer() +// +// HStack { +// Spacer() +// +// Image(connectWithApp ? .qrApp : .QR) +// .resizable() +// .aspectRatio(1, contentMode: .fit) +// .frame(height: 160) +// +// Spacer() +// +// +// Text(getDescription().localized()) +// .padding(.top, 5) +// .padding(.horizontal) +// .fixedSize(horizontal: false, vertical: true) +// .multilineTextAlignment(.center) +// +// Spacer() +// } +// .padding(.horizontal) +// .padding(.bottom) +// +// Spacer() +// +// } +// .frame(width: qrCodeViewSize.width, height: qrCodeViewSize.height) +// } +//} +// +//#Preview { +// QrCodeView(advertisesApp: false, closeView: {}) +//} diff --git a/QuickDrop/IAP/IAPConverter.swift b/QuickDrop/Plus/Converter.swift similarity index 100% rename from QuickDrop/IAP/IAPConverter.swift rename to QuickDrop/Plus/Converter.swift diff --git a/QuickDrop/IAP/PurchaseHelper.swift b/QuickDrop/Plus/Helper.swift similarity index 100% rename from QuickDrop/IAP/PurchaseHelper.swift rename to QuickDrop/Plus/Helper.swift diff --git a/QuickDrop/IAP/GetPlusView.swift b/QuickDrop/Plus/PlusView.swift similarity index 99% rename from QuickDrop/IAP/GetPlusView.swift rename to QuickDrop/Plus/PlusView.swift index c3171a6..6858df0 100644 --- a/QuickDrop/IAP/GetPlusView.swift +++ b/QuickDrop/Plus/PlusView.swift @@ -1,5 +1,5 @@ // -// GetPlusView.swift +// PlusView.swift // QuickDrop // // Created by Leon Böttger on 23.02.25. @@ -12,7 +12,7 @@ import NearbyShare let plusViewWidth: CGFloat = 440 let plusViewHeight: CGFloat = 200 -struct GetPlusView: View { +struct PlusView: View { @AppStorage(UserDefaultsKeys.plusVersion.rawValue) var isPlusVersion = false @ObservedObject private var iaphelper = IAPManager.sharedInstance @@ -253,5 +253,5 @@ extension SKProduct { #Preview { - GetPlusView(closeView: {}) + PlusView(closeView: {}) } diff --git a/QuickDrop/Sidebar.swift b/QuickDrop/Sidebar.swift deleted file mode 100644 index 3a68e78..0000000 --- a/QuickDrop/Sidebar.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// Sidebar.swift -// QuickDrop -// -// Created by Leon Böttger on 05.03.25. -// - -import SwiftUI - -struct SidebarView: View { - @State private var selection: String? = "Receive Files" - - var body: some View { - HStack { - List(selection: $selection) { - Label("Receive Files", systemImage: "tray.and.arrow.down.fill") - .tag("Receive Files") - Label("Send Files", systemImage: "tray.and.arrow.up.fill") - .tag("Send Files") - Label("Troubleshooting", systemImage: "exclamationmark.triangle.fill") - .tag("Troubleshooting") - } - .frame(minWidth: 200, idealWidth: 250, maxWidth: 300) - .listStyle(SidebarListStyle()) - - Divider() - - if let selection = selection { - DetailView(selection: selection) - } else { - Text("Select an option").frame(maxWidth: .infinity, maxHeight: .infinity) - } - } - } -} - -struct DetailView: View { - let selection: String - - var body: some View { - VStack { - Text(selection) - .font(.largeTitle) - .bold() - Spacer() - } - .frame(maxWidth: .infinity, maxHeight: .infinity) - } -} - - -#Preview { - SidebarView() -} diff --git a/QuickDrop/TutorialView.swift b/QuickDrop/TutorialView.swift index b07ac68..a92ffbb 100644 --- a/QuickDrop/TutorialView.swift +++ b/QuickDrop/TutorialView.swift @@ -15,7 +15,7 @@ struct TutorialView: View { let showsLicense: Bool var showsBetaJoinButton: Bool = false - let openIAP: () -> Void + let openPlus: () -> Void @State private var licenseWindow: NSWindow? @State var taps = 0 @@ -62,7 +62,7 @@ struct TutorialView: View { if !isPlusVersion { Button { - openIAP() + openPlus() } label: { Text("SupportQuickDrop") .underline() @@ -165,5 +165,5 @@ func copyToClipboard(_ text: String) { #Preview { - WelcomeScreen(openPlusScreen: {}, openAppAdvertisementView: {}, checkForNetworkIssues: {}) + WelcomeScreen(openPlusScreen: {}, openAppAdvertisementView: {}, openCableTransmissionView: {}, checkForNetworkIssues: {}) } diff --git a/QuickDrop/WelcomeScreen.swift b/QuickDrop/WelcomeScreen.swift index 9465f25..7950c0f 100644 --- a/QuickDrop/WelcomeScreen.swift +++ b/QuickDrop/WelcomeScreen.swift @@ -15,6 +15,7 @@ struct WelcomeScreen: View { let openPlusScreen: () -> Void let openAppAdvertisementView: () -> Void + let openCableTransmissionView: () -> Void let checkForNetworkIssues: () -> Void @State private var selection: Tabs? = Tabs.receive @@ -23,78 +24,37 @@ struct WelcomeScreen: View { HStack(spacing: 0) { List(selection: $selection) { - ForEach(Tabs.allCases.filter({$0 != .settings && $0 != .app }), id: \.self) { tab in + ForEach(Tabs.allCases.filter({$0 != .settings }), id: \.self) { tab in Label(tab.title, systemImage: tab.systemImage) - // .font(.system(size: 13)) .tag(tab) .frame(height: 30) } Divider() - Button { + ExternalLinkLabel(label: "GetSupport", icon: "questionmark.circle") { getSupport() - } label: { - HStack { - Label("GetSupport", systemImage: "questionmark.circle") - - Spacer() - - Image(systemName: "arrow.up.right") - .opacity(0.3) - } - .frame(height: 32) - .contentShape(Rectangle()) } - .buttonStyle(.plain) - - Button { + ExternalLinkLabel(label: "PrivacyPolicy", icon: "hand.raised") { openPrivacyPolicy() - - } label: { - - HStack { - Label("PrivacyPolicy", systemImage: "hand.raised") - - Spacer() - - Image(systemName: "arrow.up.right") - .opacity(0.3) - } - .frame(height: 32) - .contentShape(Rectangle()) } - .buttonStyle(.plain) - - Button { + ExternalLinkLabel(label: "AndroidApp", icon: "smartphone") { openAppAdvertisementView() - } label: { - - HStack { - Label(Tabs.app.title, systemImage: Tabs.app.systemImage) - - Spacer() - - Image(systemName: "arrow.up.right") - .opacity(0.3) - } - .frame(height: 32) - .contentShape(Rectangle()) } - .buttonStyle(.plain) + + ExternalLinkLabel(label: "TransmitUsingCable", icon: "cable.connector") { + openCableTransmissionView() + } Divider() Label(Tabs.settings.title, systemImage: Tabs.settings.systemImage) .tag(Tabs.settings) .frame(height: 30) - -// Label(Tabs.app.title, systemImage: Tabs.app.systemImage) -// .tag(Tabs.app) -// .frame(height: 30) } + .minimumScaleFactor(0.5) .frame(width: 220) .listStyle(SidebarListStyle()) @@ -107,20 +67,16 @@ struct WelcomeScreen: View { switch selection { case .receive: - TutorialView(title: "WelcomeToQuickDrop", text: "UserManualDescription", showsLicense: true, openIAP: openPlusScreen) + TutorialView(title: "WelcomeToQuickDrop", text: "UserManualDescription", showsLicense: true, openPlus: openPlusScreen) case .send: - TutorialView(title: "SendFiles", text: "SendFilesDescription", showsLicense: false, openIAP: openPlusScreen) + TutorialView(title: "SendFiles", text: "SendFilesDescription", showsLicense: false, openPlus: openPlusScreen) case .troubleshooting: - TutorialView(title: "Troubleshooting", text: "TroubleshootingDescription", showsLicense: false, openIAP: openPlusScreen) + TutorialView(title: "Troubleshooting", text: "TroubleshootingDescription", showsLicense: false, openPlus: openPlusScreen) .onAppear { checkForNetworkIssues() } - -// case .app: -// TutorialView(title: "AndroidApp", text: "AndroidAppDescription", showsLicense: false, showsBetaJoinButton: true, openIAP: openPlusScreen) - default: SettingsView() } @@ -143,11 +99,36 @@ struct WelcomeScreen: View { } +struct ExternalLinkLabel: View { + + let label: String + let icon: String + let action: () -> Void + + var body: some View { + Button { + action() + } label: { + HStack { + Label(label.localized(), systemImage: icon) + + Spacer() + + Image(systemName: "arrow.up.right") + .opacity(0.3) + } + .frame(height: 32) + .contentShape(Rectangle()) + } + .buttonStyle(.plain) + } +} + + enum Tabs: CaseIterable { case receive case send case troubleshooting - case app case settings var title: String { @@ -158,8 +139,6 @@ enum Tabs: CaseIterable { return "SendFiles".localized() case .troubleshooting: return "DeviceNotShown".localized() - case .app: - return "AndroidApp".localized() case .settings: return "Settings".localized() } @@ -175,13 +154,11 @@ enum Tabs: CaseIterable { return "exclamationmark.triangle" case .settings: return "gear" - case .app: - return "smartphone" } } } #Preview { - WelcomeScreen(openPlusScreen: {}, openAppAdvertisementView: {}, checkForNetworkIssues: {}) + WelcomeScreen(openPlusScreen: {}, openAppAdvertisementView: {}, openCableTransmissionView: {}, checkForNetworkIssues: {}) } diff --git a/QuickDrop/ar.lproj/Localizable.strings b/QuickDrop/ar.lproj/Localizable.strings index 7b57202..56aee94 100644 --- a/QuickDrop/ar.lproj/Localizable.strings +++ b/QuickDrop/ar.lproj/Localizable.strings @@ -185,3 +185,7 @@ QuickDrop لنظام Android في المرحلة التجريبية حاليًا قد يكون هناك مرشح حزم معيب مفعل على جهاز Mac، ربما تم تثبيته بواسطة برنامج مكافحة الفيروسات (مثل ESET). افتح تفضيلات النظام > الشبكة > VPN والتصفية، ثم قم بإيقاف تشغيل مرشح المحتوى. بمجرد الانتهاء من ذلك، يجب أن تتمكن من نقل الملفات بنجاح."; + +"TransmitUsingCable" = "النقل باستخدام الكابل"; +"DownloadCableConnectionApp" = "تحميل iDroid"; +"DownloadCableConnectionAppDescription" = "إذا كنت تريد نقل الملفات واستعراض تخزين جهاز Android الخاص بك عبر USB، يمكنك الآن القيام بذلك باستخدام تطبيق iDroid الجديد.\n\niDroid يدعم تنزيل وتحميل الملفات والمجلدات الكاملة باستخدام السحب والإفلات. iDroid مجاني لفترة محدودة!"; diff --git a/QuickDrop/de.lproj/Localizable.strings b/QuickDrop/de.lproj/Localizable.strings index 51b8e12..9490e8d 100644 --- a/QuickDrop/de.lproj/Localizable.strings +++ b/QuickDrop/de.lproj/Localizable.strings @@ -189,3 +189,7 @@ Sobald dies erledigt ist, kann sich dein Telefon mit deinem Mac verbinden."; Möglicherweise ist auf deinem Mac ein fehlerhafter Paketfilter aktiviert, der z. B. von einem Antivirenprogramm (z. B. ESET) stammt. Öffne Systemeinstellungen > Netzwerk > VPN & Filter und deaktiviere den Inhaltsfilter. Danach solltest du Dateien erfolgreich übertragen können."; + +"TransmitUsingCable" = "Mit Kabel übertragen"; +"DownloadCableConnectionApp" = "iDroid herunterladen"; +"DownloadCableConnectionAppDescription" = "Wenn du Dateien übertragen und den Speicher deines Android-Geräts per USB durchsuchen willst, kannst du das jetzt mit der neuen iDroid-App tun.\n\niDroid unterstützt das Herunterladen und Hochladen von Dateien und ganzen Ordnern per Drag & Drop. iDroid ist für begrenzte Zeit kostenlos!"; diff --git a/QuickDrop/es.lproj/Localizable.strings b/QuickDrop/es.lproj/Localizable.strings index 237ec34..9a518d9 100644 --- a/QuickDrop/es.lproj/Localizable.strings +++ b/QuickDrop/es.lproj/Localizable.strings @@ -188,3 +188,6 @@ Es posible que tu Mac tenga habilitado un filtro de paquetes defectuoso, instala Una vez hecho esto, deberías poder transferir archivos correctamente."; +"TransmitUsingCable" = "Transferir con Cable"; +"DownloadCableConnectionApp" = "Descargar iDroid"; +"DownloadCableConnectionAppDescription" = "Si deseas transferir archivos y explorar el almacenamiento de tu dispositivo Android mediante USB, ahora puedes hacerlo con la nueva aplicación iDroid.\n\niDroid admite la descarga y carga de archivos y carpetas completas mediante arrastrar y soltar. ¡iDroid es gratuita por tiempo limitado!"; diff --git a/QuickDrop/fr.lproj/Localizable.strings b/QuickDrop/fr.lproj/Localizable.strings index 51dca71..9a7a9c1 100644 --- a/QuickDrop/fr.lproj/Localizable.strings +++ b/QuickDrop/fr.lproj/Localizable.strings @@ -187,3 +187,7 @@ Une fois cela fait, votre téléphone pourra se connecter à votre Mac."; Votre Mac pourrait avoir un filtre de paquets défectueux activé, installé par exemple par un antivirus (comme ESET). Ouvrez Réglages Système > Réseau > VPN et Filtrage, puis désactivez le filtre de contenu. Une fois cela fait, vous devriez pouvoir transférer des fichiers sans problème."; + +"TransmitUsingCable" = "Transférer avec Câble"; +"DownloadCableConnectionApp" = "Télécharger iDroid"; +"DownloadCableConnectionAppDescription" = "Si vous souhaitez transférer des fichiers et explorer le stockage de votre appareil Android via USB, vous pouvez maintenant le faire avec la nouvelle application iDroid.\n\niDroid prend en charge le téléchargement et l'envoi de fichiers et dossiers entiers avec le glisser-déposer. iDroid est gratuit pour une durée limitée !"; diff --git a/QuickDrop/hu.lproj/Localizable.strings b/QuickDrop/hu.lproj/Localizable.strings index 01092b0..40a53b7 100644 --- a/QuickDrop/hu.lproj/Localizable.strings +++ b/QuickDrop/hu.lproj/Localizable.strings @@ -188,3 +188,7 @@ Ezek után a telefonja csatlakozni tud majd a Mac-hez."; Lehet, hogy a Mac gépén egy hibás csomagszűrő van engedélyezve, amelyet egy antivírus program (pl. ESET) telepített. Nyissa meg a Rendszerbeállítások > Hálózat > VPN és Szűrés menüpontot, és kapcsolja ki a tartalomszűrőt. Ezután a fájlátvitelnek sikeresnek kell lennie."; + +"TransmitUsingCable" = "Átvitel kábellel"; +"DownloadCableConnectionApp" = "iDroid letöltése"; +"DownloadCableConnectionAppDescription" = "Ha fájlokat szeretnél áthelyezni és böngészni Android-eszközöd tárhelyét USB-n keresztül, most megteheted az új iDroid alkalmazással.\n\niDroid támogatja a fájlok és teljes mappák letöltését és feltöltését húzással és ejtéssel. Az iDroid korlátozott ideig ingyenes!"; diff --git a/QuickDrop/it.lproj/Localizable.strings b/QuickDrop/it.lproj/Localizable.strings index 3365832..6817497 100644 --- a/QuickDrop/it.lproj/Localizable.strings +++ b/QuickDrop/it.lproj/Localizable.strings @@ -187,3 +187,7 @@ Una volta fatto ciò, il tuo telefono sarà in grado di connettersi al tuo Mac." È possibile che sul tuo Mac sia attivo un filtro di pacchetti difettoso, installato ad esempio da un antivirus (es. ESET). Apri Preferenze di Sistema > Rete > VPN e Filtro e disattiva il filtro dei contenuti. Una volta fatto, dovresti essere in grado di trasferire i file correttamente."; + +"TransmitUsingCable" = "Trasferisci con Cavo"; +"DownloadCableConnectionApp" = "Scarica iDroid"; +"DownloadCableConnectionAppDescription" = "Se desideri trasferire file e navigare nella memoria del tuo dispositivo Android tramite USB, ora puoi farlo con la nuova app iDroid.\n\niDroid supporta il download e il caricamento di file e cartelle intere tramite Drag & Drop. iDroid è gratuita per un periodo limitato!"; diff --git a/QuickDrop/ja.lproj/Localizable.strings b/QuickDrop/ja.lproj/Localizable.strings index a6df2dd..2bcbfda 100644 --- a/QuickDrop/ja.lproj/Localizable.strings +++ b/QuickDrop/ja.lproj/Localizable.strings @@ -187,3 +187,7 @@ AndroidデバイスからMacにファイルを送信するには、スマート Mac で不具合のあるパケットフィルターが有効になっている可能性があり、これは ESET などのウイルス対策ソフトによってインストールされている場合があります。システム設定 > ネットワーク > VPNとフィルター を開き、コンテンツフィルターを無効にしてください。 これで、ファイルを正常に転送できるはずです。"; + +"TransmitUsingCable" = "ケーブルで転送"; +"DownloadCableConnectionApp" = "iDroidをダウンロード"; +"DownloadCableConnectionAppDescription" = "USB経由でAndroidデバイスのファイルを転送し、ストレージを閲覧したい場合は、新しいiDroidアプリを使って実現できます。\n\niDroidはドラッグ&ドロップによるファイルやフォルダのダウンロードとアップロードをサポートしています。iDroidは期間限定で無料です!"; diff --git a/QuickDrop/ko.lproj/Localizable.strings b/QuickDrop/ko.lproj/Localizable.strings index 00107bc..e3e1e61 100644 --- a/QuickDrop/ko.lproj/Localizable.strings +++ b/QuickDrop/ko.lproj/Localizable.strings @@ -187,3 +187,7 @@ Mac에서 바이러스 백신 프로그램을 사용하고 있을 가능성이 Mac에 문제가 있는 패킷 필터가 활성화되어 있을 수 있으며, 이는 ESET과 같은 백신 프로그램이 설치했을 수 있습니다. 시스템 설정 > 네트워크 > VPN 및 필터로 이동하여 콘텐츠 필터를 비활성화하세요. 이 작업이 완료되면 파일 전송이 정상적으로 이루어질 것입니다."; + +"TransmitUsingCable" = "케이블로 전송"; +"DownloadCableConnectionApp" = "iDroid 다운로드"; +"DownloadCableConnectionAppDescription" = "USB를 통해 Android 기기의 파일을 전송하고 저장소를 탐색하려면, 이제 새롭게 출시된 iDroid 앱을 사용해보세요.\n\niDroid는 드래그 앤 드롭으로 전체 폴더 및 파일의 다운로드와 업로드를 지원합니다. iDroid는 한정된 시간 동안 무료입니다!"; diff --git a/QuickDrop/nl.lproj/Localizable.strings b/QuickDrop/nl.lproj/Localizable.strings index 44155c2..8c2238f 100644 --- a/QuickDrop/nl.lproj/Localizable.strings +++ b/QuickDrop/nl.lproj/Localizable.strings @@ -187,3 +187,7 @@ Zodra dit is gedaan, kan je telefoon verbinding maken met je Mac."; Je Mac heeft mogelijk een defect pakketfilter ingeschakeld, mogelijk geïnstalleerd door antivirussoftware (zoals ESET). Ga naar Systeeminstellingen > Netwerk > VPN en Filter en schakel het inhoudsfilter uit. Daarna zou je bestanden succesvol moeten kunnen overdragen."; + +"TransmitUsingCable" = "Overdragen met Kabel"; +"DownloadCableConnectionApp" = "Download iDroid"; +"DownloadCableConnectionAppDescription" = "Als je bestanden wilt overzetten en de opslag van je Android-apparaat via USB wilt verkennen, kan dat nu met de nieuwe iDroid-app.\n\niDroid ondersteunt het downloaden en uploaden van bestanden en volledige mappen via slepen en neerzetten. iDroid is tijdelijk gratis!"; diff --git a/QuickDrop/pt-BR.lproj/Localizable.strings b/QuickDrop/pt-BR.lproj/Localizable.strings index f02d90b..ddc21f6 100644 --- a/QuickDrop/pt-BR.lproj/Localizable.strings +++ b/QuickDrop/pt-BR.lproj/Localizable.strings @@ -188,3 +188,6 @@ Pode haver um filtro de pacotes com defeito ativado no seu Mac, possivelmente in Depois disso, você deve conseguir transferir arquivos com sucesso."; +"TransmitUsingCable" = "Transferir com Cabo"; +"DownloadCableConnectionApp" = "Baixar iDroid"; +"DownloadCableConnectionAppDescription" = "Se você deseja transferir arquivos e navegar no armazenamento do seu dispositivo Android via USB, agora pode fazer isso com o novo app iDroid.\n\niDroid suporta download e upload de arquivos e pastas inteiras usando Arrastar e Soltar. iDroid é gratuito por tempo limitado!"; diff --git a/QuickDrop/pt-PT.lproj/Localizable.strings b/QuickDrop/pt-PT.lproj/Localizable.strings index e6b4852..7b08a1e 100644 --- a/QuickDrop/pt-PT.lproj/Localizable.strings +++ b/QuickDrop/pt-PT.lproj/Localizable.strings @@ -187,3 +187,7 @@ Depois de feito isto, o seu telefone poderá conectar-se ao seu Mac."; Pode ter um filtro de pacotes com defeito ativado no seu Mac, possivelmente instalado por um antivírus (por exemplo, ESET). Abra Preferências do Sistema > Rede > VPN e Filtro e desative o filtro de conteúdo. Depois disso, deverá conseguir transferir ficheiros com sucesso."; + +"TransmitUsingCable" = "Transferir com Cabo"; +"DownloadCableConnectionApp" = "Descarregar iDroid"; +"DownloadCableConnectionAppDescription" = "Se pretendes transferir ficheiros e explorar o armazenamento do teu dispositivo Android via USB, agora podes fazê-lo com a nova aplicação iDroid.\n\niDroid suporta transferência e envio de ficheiros e pastas inteiras através de arrastar e largar. O iDroid é gratuito por tempo limitado!"; diff --git a/QuickDrop/ro.lproj/Localizable.strings b/QuickDrop/ro.lproj/Localizable.strings index 220e9c9..1961513 100644 --- a/QuickDrop/ro.lproj/Localizable.strings +++ b/QuickDrop/ro.lproj/Localizable.strings @@ -186,3 +186,7 @@ După ce faceți acest lucru, telefonul dvs. va putea să se conecteze la Mac."; Este posibil ca Mac-ul tău să aibă activat un filtru de pachete defect, instalat de un program antivirus (de exemplu, ESET). Deschide Preferințe Sistem > Rețea > VPN și Filtru și dezactivează filtrul de conținut. După ce faci acest lucru, ar trebui să poți transfera fișiere cu succes."; + +"TransmitUsingCable" = "Transferă cu Cablu"; +"DownloadCableConnectionApp" = "Descarcă iDroid"; +"DownloadCableConnectionAppDescription" = "Dacă dorești să transferi fișiere și să explorezi stocarea dispozitivului tău Android prin USB, acum poți face acest lucru cu noua aplicație iDroid.\n\niDroid permite descărcarea și încărcarea fișierelor și folderelor întregi prin tragere și plasare. iDroid este gratuit pentru o perioadă limitată!"; diff --git a/QuickDrop/ru.lproj/Localizable.strings b/QuickDrop/ru.lproj/Localizable.strings index 2dd79c5..a8b8545 100644 --- a/QuickDrop/ru.lproj/Localizable.strings +++ b/QuickDrop/ru.lproj/Localizable.strings @@ -190,3 +190,6 @@ QuickDrop для Android сейчас находится в стадии бет После этого передача файлов должна пройти успешно."; +"TransmitUsingCable" = "Передача через кабель"; +"DownloadCableConnectionApp" = "Скачать iDroid"; +"DownloadCableConnectionAppDescription" = "Если вы хотите передавать файлы и просматривать хранилище вашего Android-устройства через USB, теперь вы можете сделать это с помощью нового приложения iDroid.\n\niDroid поддерживает загрузку и передачу файлов и целых папок с помощью перетаскивания. iDroid бесплатно в течение ограниченного времени!"; diff --git a/QuickDrop/th.lproj/Localizable.strings b/QuickDrop/th.lproj/Localizable.strings index cbef61e..1ca1fbb 100644 --- a/QuickDrop/th.lproj/Localizable.strings +++ b/QuickDrop/th.lproj/Localizable.strings @@ -187,3 +187,7 @@ QuickDrop สำหรับ Android อยู่ในช่วงเบต้ Mac ของคุณอาจเปิดใช้งานตัวกรองแพ็กเก็ตที่มีปัญหา ซึ่งอาจติดตั้งโดยโปรแกรมป้องกันไวรัส (เช่น ESET) ให้เปิดการตั้งค่าระบบ > เครือข่าย > VPN และตัวกรอง แล้วปิดตัวกรองเนื้อหา เมื่อทำเสร็จแล้ว คุณควรสามารถถ่ายโอนไฟล์ได้สำเร็จ"; + +"TransmitUsingCable" = "ถ่ายโอนด้วยสายเคเบิล"; +"DownloadCableConnectionApp" = "ดาวน์โหลด iDroid"; +"DownloadCableConnectionAppDescription" = "หากคุณต้องการถ่ายโอนไฟล์และเรียกดูที่เก็บข้อมูลของอุปกรณ์ Android ผ่าน USB ตอนนี้คุณสามารถทำได้ด้วยแอป iDroid ใหม่\n\niDroid รองรับการดาวน์โหลดและอัปโหลดไฟล์และโฟลเดอร์ทั้งหมดด้วยการลากและวาง iDroid ฟรีในช่วงเวลาจำกัด!"; diff --git a/QuickDrop/uk.lproj/Localizable.strings b/QuickDrop/uk.lproj/Localizable.strings index 00523ae..ea37171 100644 --- a/QuickDrop/uk.lproj/Localizable.strings +++ b/QuickDrop/uk.lproj/Localizable.strings @@ -187,3 +187,7 @@ QuickDrop для Android наразі знаходиться в бета-вер На вашому Mac може бути активований несправний фільтр пакетів, встановлений антивірусною програмою (наприклад, ESET). Відкрийте Системні налаштування > Мережа > VPN і Фільтр та вимкніть фільтр вмісту. Після цього передача файлів має працювати коректно."; + +"TransmitUsingCable" = "Передача через кабель"; +"DownloadCableConnectionApp" = "Завантажити iDroid"; +"DownloadCableConnectionAppDescription" = "Якщо ви хочете передавати файли та переглядати сховище вашого Android-пристрою через USB, тепер це можливо з новим додатком iDroid.\n\niDroid підтримує завантаження та надсилання файлів і цілих папок через перетягування. iDroid безкоштовний протягом обмеженого часу!"; diff --git a/QuickDrop/zh-Hans.lproj/Localizable.strings b/QuickDrop/zh-Hans.lproj/Localizable.strings index 17993e0..e7dceb5 100644 --- a/QuickDrop/zh-Hans.lproj/Localizable.strings +++ b/QuickDrop/zh-Hans.lproj/Localizable.strings @@ -187,3 +187,7 @@ QuickDrop for Android 当前处于测试阶段。要注册测试版,请发送 您的 Mac 上可能启用了有问题的数据包过滤器,该过滤器可能由杀毒软件(如 ESET)安装。请打开系统设置 > 网络 > VPN 与过滤器,并关闭内容过滤器。 完成这些操作后,您应该可以成功传输文件。"; + +"TransmitUsingCable" = "通过数据线传输"; +"DownloadCableConnectionApp" = "下载 iDroid"; +"DownloadCableConnectionAppDescription" = "如果您想通过 USB 传输文件并浏览 Android 设备的存储空间,现在可以使用全新的 iDroid 应用程序。\n\niDroid 支持通过拖放下载和上传文件及整个文件夹。iDroid 限时免费!"; diff --git a/ShareExtension/Base.lproj/ShareViewController.xib b/ShareExtension/Base.lproj/ShareViewController.xib index c094605..2bd3985 100644 --- a/ShareExtension/Base.lproj/ShareViewController.xib +++ b/ShareExtension/Base.lproj/ShareViewController.xib @@ -1,8 +1,8 @@ - + - + diff --git a/ShareExtension/ShareViewController.swift b/ShareExtension/ShareViewController.swift index 5a6336a..5e68fc5 100644 --- a/ShareExtension/ShareViewController.swift +++ b/ShareExtension/ShareViewController.swift @@ -147,13 +147,13 @@ class ShareViewController: NSViewController, ShareExtensionDelegate { private func openQrCodeView() { if qrCodeSheetView == nil { - let contentView = QrCodeView { + let contentView = SmallSheetView(type: .sendToDeviceQrCode) { self.closeQrCodeView() } let hostingView = NSHostingView(rootView: contentView) - let panel = NSPanel(contentRect: NSRect(x: 0, y: 0, width: qrCodeViewSize.width, height: qrCodeViewSize.height), + let panel = NSPanel(contentRect: NSRect(x: 0, y: 0, width: smallSheetViewSize.width, height: smallSheetViewSize.height), styleMask: [.titled, .closable, .utilityWindow], backing: .buffered, defer: false) diff --git a/ShareExtension/QrCodeView.swift b/ShareExtension/SmallSheetView.swift similarity index 51% rename from ShareExtension/QrCodeView.swift rename to ShareExtension/SmallSheetView.swift index bd3455c..e572406 100644 --- a/ShareExtension/QrCodeView.swift +++ b/ShareExtension/SmallSheetView.swift @@ -7,11 +7,12 @@ import SwiftUI -let qrCodeViewSize = CGSize(width: 530.0, height: 270.0) +let smallSheetViewSize = CGSize(width: 530.0, height: 270.0) -struct QrCodeView: View { +struct SmallSheetView: View { @State private var qrCode: String = "" - var advertisesApp = false + + let type: SheetViewType let closeView: () -> Void @Environment(\.colorScheme) var colorScheme @@ -23,7 +24,22 @@ struct QrCodeView: View { HStack { - if !advertisesApp { + HStack(spacing: 5) { + + let imageSize: CGFloat = type == .sendToDeviceQrCode ? 25 : 20 + + Image(.quickDropIcon) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: imageSize, height: imageSize) + + if type != .sendToDeviceQrCode { + Text("QuickDrop") + } + } + .padding(.leading, 18) + + if type == .sendToDeviceQrCode { Spacer() HStack { @@ -45,18 +61,7 @@ struct QrCodeView: View { connectWithApp.toggle() } } - .animation(.smooth, value:connectWithApp) - } - else { - HStack(spacing: 5) { - Image(.quickDropIcon) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 20, height: 20) - - Text("QuickDrop") - } - .padding(.leading, 18) + .animation(.smooth, value: connectWithApp) } Spacer() @@ -73,26 +78,39 @@ struct QrCodeView: View { .padding(.trailing, 15) .padding(.leading, 10) .padding(.top, 15) - .padding(.bottom, advertisesApp ? -10 : 0) + .padding(.bottom, type == .sendToDeviceQrCode ? 0 : -10) Spacer() HStack { Spacer() - Image(connectWithApp ? .qrApp : .QR) + getImage() .resizable() .aspectRatio(1, contentMode: .fit) .frame(height: 160) Spacer() - - Text(getDescription().localized()) - .padding(.top, 5) - .padding(.horizontal) - .fixedSize(horizontal: false, vertical: true) - .multilineTextAlignment(.center) + VStack { + Text(getDescription().localized()) + .padding(.top, 5) + .padding(.horizontal) + .fixedSize(horizontal: false, vertical: true) + .multilineTextAlignment(.center) + + if type == .downloadCableConnectionApp { + Button { + if let url = URL(string: "https://apps.apple.com/de/app/idroid-phone-file-manager/id6746444380") { + NSWorkspace.shared.open(url) + } + } label: { + Text("DownloadCableConnectionApp") + } + .keyboardShortcut(.defaultAction) + .padding() + } + } Spacer() } @@ -102,19 +120,39 @@ struct QrCodeView: View { Spacer() } - .frame(width: qrCodeViewSize.width, height: qrCodeViewSize.height) + .frame(width: smallSheetViewSize.width, height: smallSheetViewSize.height) } func getDescription() -> String { - if advertisesApp { + switch type { + case .sendToDeviceQrCode: + return connectWithApp ? "QrCodeInstructionsApp" : "QrCodeInstructions" + case .downloadAndroidApp: return "QuickDropAndroidAppAdvertisement" + case .downloadCableConnectionApp: + return "DownloadCableConnectionAppDescription" + } + } + + func getImage() -> Image { + switch type { + case .sendToDeviceQrCode: + return connectWithApp ? Image(.qrApp) : Image(.QR) + case .downloadAndroidApp: + return Image(.qrApp) + case .downloadCableConnectionApp: + return Image(.iDroid) } - - return connectWithApp ? "QrCodeInstructionsApp" : "QrCodeInstructions" } } +enum SheetViewType { + case sendToDeviceQrCode + case downloadAndroidApp + case downloadCableConnectionApp +} + #Preview { - QrCodeView(closeView: {}) + SmallSheetView(type: .downloadCableConnectionApp, closeView: {}) }