diff --git a/NearbyShare/Connection/InboundNearbyConnection.swift b/NearbyShare/Connection/InboundNearbyConnection.swift index d923fef..7ca21c2 100644 --- a/NearbyShare/Connection/InboundNearbyConnection.swift +++ b/NearbyShare/Connection/InboundNearbyConnection.swift @@ -589,6 +589,13 @@ class InboundNearbyConnection: NearbyConnection { if storeInTemp { log("[InboundNearbyConnection \(self.id)] File transfer restrictions detected, storing files in temporary directory.") delegate?.showPlusScreen() + + #if os(iOS) + // Continue transfer for macOS only + // On iOS, the transfer should be cancelled by user + rejectTransfer() + return + #endif } do { diff --git a/NearbyShare/Util/Helpers.swift b/NearbyShare/Util/Helpers.swift index 13c426a..cba44c2 100644 --- a/NearbyShare/Util/Helpers.swift +++ b/NearbyShare/Util/Helpers.swift @@ -111,14 +111,8 @@ extension String { public func fullVersion() -> Bool { - - #if os(macOS) // Enable full functionality if app distributed directly - return Settings.shared.gotPlus || DistributionDetector.isDirectDistributionEnabled - #else - // iOS - return true - #endif + return Settings.shared.gotPlus || DistributionDetector.isDirectDistributionEnabled } diff --git a/QuickDrop.xcodeproj/project.pbxproj b/QuickDrop.xcodeproj/project.pbxproj index 9635f88..c22040e 100644 --- a/QuickDrop.xcodeproj/project.pbxproj +++ b/QuickDrop.xcodeproj/project.pbxproj @@ -45,6 +45,7 @@ EB16B77A2E59BAA1007D9792 /* AppGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB16B7762E59BA9F007D9792 /* AppGroup.swift */; }; EB2F9BFE2DA05F48004010A2 /* BezelNotification in Frameworks */ = {isa = PBXBuildFile; productRef = EB2F9BFD2DA05F48004010A2 /* BezelNotification */; }; EB3643602D73A2A2009CDFF8 /* AudioManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB36435F2D73A29F009CDFF8 /* AudioManager.swift */; }; + EB4F9D1D2EC113EA00A74A0F /* DistributionDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB704A812E4A7BAE008E608F /* DistributionDetector.swift */; }; EB5C36932E34EBBD0052EFD7 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = EB5C36922E34EBBD0052EFD7 /* Localizable.xcstrings */; }; EB5C36942E34EBBD0052EFD7 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = EB5C36922E34EBBD0052EFD7 /* Localizable.xcstrings */; }; EB5C36E42E34EC0E0052EFD7 /* License.txt in Resources */ = {isa = PBXBuildFile; fileRef = EB5C36E32E34EC0E0052EFD7 /* License.txt */; }; @@ -1098,6 +1099,7 @@ EB950B6F2E5206E2002D68FA /* ShareViewController.swift in Sources */, EB950B432E52038A002D68FA /* ContentView.swift in Sources */, EB950B442E520414002D68FA /* License.swift in Sources */, + EB4F9D1D2EC113EA00A74A0F /* DistributionDetector.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/QuickDrop.xcodeproj/xcshareddata/xcschemes/QuickDropiOS.xcscheme b/QuickDrop.xcodeproj/xcshareddata/xcschemes/QuickDropiOS.xcscheme index 6d9a4e8..dacdd71 100644 --- a/QuickDrop.xcodeproj/xcshareddata/xcschemes/QuickDropiOS.xcscheme +++ b/QuickDrop.xcodeproj/xcshareddata/xcschemes/QuickDropiOS.xcscheme @@ -32,8 +32,8 @@ Void - init(controlPlusScreen: @escaping (Bool) -> Void = { _ in }) { + + init(controlPlusScreen: @escaping (Bool) -> Void) { self.controlPlusScreen = controlPlusScreen NearbyConnectionManager.shared.addInboundAppDelegate(self) NearbyConnectionManager.shared.becomeVisible() @@ -103,8 +103,6 @@ class ReceiveModel: ObservableObject, InboundAppDelegate { case .Decline: secondaryButtonAction() } - } onCancel: { - NearbyConnectionManager.shared.cancelTransfer(id: transferID) } #endif } @@ -146,11 +144,6 @@ class ReceiveModel: ObservableObject, InboundAppDelegate { if transfer.type == .text { showAlert(title: "QuickDrop", message: mainMessage) } - else { - ProgressAlert.shared.showProgressAlert(onCancel: { - NearbyConnectionManager.shared.cancelTransfer(id: transfer.id) - }) - } #endif } @@ -165,7 +158,9 @@ class ReceiveModel: ObservableObject, InboundAppDelegate { let averageProgress = totalProgress / Double(processes.count) #if os(iOS) - ProgressAlert.shared.updateProgress(averageProgress) + ProgressAlert.shared.updateProgress(averageProgress, onCancel: { + NearbyConnectionManager.shared.cancelTransfer(id: connectionID) + }) #else DispatchQueue.main.async { self.progress = averageProgress diff --git a/QuickDropiOS/View/ContentView.swift b/QuickDropiOS/View/ContentView.swift index 789c032..8f9e98e 100644 --- a/QuickDropiOS/View/ContentView.swift +++ b/QuickDropiOS/View/ContentView.swift @@ -41,9 +41,14 @@ struct DeviceListView: View { @State private var qrCode: Image? = nil @StateObject var sendModel = SendModel() -#if !EXTENSION - @StateObject var receiveModel = ReceiveModel() -#endif + #if !EXTENSION + @StateObject var receiveModel = ReceiveModel(controlPlusScreen: { show in + log("[DeviceListView] Setting showPlusScreen to \(show)") + DeviceListViewModel.sharedInstance.showPlusScreen = show + }) + #endif + + @ObservedObject var model = DeviceListViewModel.sharedInstance @Environment(\.scenePhase) var scenePhase @Environment(\.sheetActive) var sheetActive @@ -54,7 +59,7 @@ struct DeviceListView: View { let showsLoadingIndicator = nearbyConnectionManager.hasLocalNetworkPermission && nearbyConnectionManager.isConnectedToLocalNetwork - BottomBarView(header: "QuickDrop ", navigationBarLayout: isShareExtension() ? .SmallOnlyAlways : .Default, bottomViewHeight: 30) { + BottomBarView(header: "QuickDrop", navigationBarLayout: isShareExtension() ? .SmallOnlyAlways : .Default, bottomViewHeight: 30) { VStack { VStack(alignment: .leading, spacing: 8) { @@ -185,7 +190,7 @@ struct DeviceListView: View { log("[ScenePhase] App became active") NearbyConnectionManager.shared.startDeviceDiscovery() -#if !EXTENSION + #if !EXTENSION NearbyConnectionManager.shared.becomeVisible() if Settings.shared.incomingTransmissionCount > 0 { @@ -193,18 +198,21 @@ struct DeviceListView: View { requestReviewOnce() } } -#endif + #endif } if newValue == .background { log("[ScenePhase] App went to background") -#if !EXTENSION + #if !EXTENSION NearbyConnectionManager.shared.becomeInvisible() -#endif + #endif NearbyConnectionManager.shared.stopDeviceDiscovery() } } + #if !EXTENSION + .modifier(PlusVersionSheetModifier(sheetActive: $model.showPlusScreen, isPlusVersion: $settings.gotPlus)) + #endif .animation(.smooth, value: nearbyConnectionManager.hasLocalNetworkPermission) .animation(.smooth, value: nearbyConnectionManager.isConnectedToLocalNetwork) .navigationBarItems(trailing: ZStack { @@ -218,6 +226,12 @@ struct DeviceListView: View { } } +final class DeviceListViewModel: SharedInstance { + static var sharedInstance = DeviceListViewModel() + + @Published var showPlusScreen = false +} + struct DeviceFilePickerButton: View { @@ -297,11 +311,11 @@ struct DeviceButtonLabel: View { func isShareExtension() -> Bool { -#if EXTENSION + #if EXTENSION return true -#else + #else return false -#endif + #endif } diff --git a/QuickDropiOS/View/UIAlert.swift b/QuickDropiOS/View/UIAlert.swift index 24dcfa9..acc7cf4 100644 --- a/QuickDropiOS/View/UIAlert.swift +++ b/QuickDropiOS/View/UIAlert.swift @@ -18,7 +18,7 @@ final class ProgressAlert { private weak var progressView: UIProgressView? // MARK: - Initial Accept / Decline - func askForUserPermission(title: String, message: String, acceptLabel: String, acceptAlwaysLabel: String?, rejectLabel: String, onAccept: @escaping (AcceptAction) -> Void, onCancel: @escaping () -> Void) { + func askForUserPermission(title: String, message: String, acceptLabel: String, acceptAlwaysLabel: String?, rejectLabel: String, onAccept: @escaping (AcceptAction) -> Void) { guard let vc = topMostViewController() else { return } let alert = UIAlertController(title: title, @@ -31,28 +31,23 @@ final class ProgressAlert { alert.addAction(UIAlertAction(title: acceptLabel, style: .default, handler: { _ in onAccept(.Accept) - self.showProgressAlert(on: vc, onCancel: onCancel) })) if let acceptAlways = acceptAlwaysLabel { alert.addAction(UIAlertAction(title: acceptAlways, style: .default, handler: { _ in onAccept(.AcceptAlways) - self.showProgressAlert(on: vc, onCancel: onCancel) })) } vc.present(alert, animated: true) } - - func showProgressAlert(onCancel: @escaping () -> Void) { - guard let vc = topMostViewController() else { return } - self.showProgressAlert(on: vc, onCancel: onCancel) - } - // MARK: - Progress Alert - private func showProgressAlert(on vc: UIViewController, onCancel: @escaping () -> Void) { + private func showProgressAlert(onCancel: @escaping () -> Void) { + + guard let vc = topMostViewController() else { return } + let alert = UIAlertController(title: "Receiving".localized(), message: "\n\n", preferredStyle: .alert) @@ -77,11 +72,25 @@ final class ProgressAlert { vc.present(alert, animated: true) } + // MARK: - Update Progress // progress: 0…1 → update progress, nil → finished - func updateProgress(_ progress: Double?, completion: @escaping () -> Void = {}) { + func updateProgress(_ progress: Double?, onCancel: @escaping () -> Void, completion: @escaping () -> Void = {}) { + + // No progress to show, nothing shown currently → just complete + if progressAlert == nil && progress == nil { + completion() + return + } + DispatchQueue.main.async { + + // Show progress if not shown yet + if self.progressAlert == nil { + self.showProgressAlert(onCancel: onCancel) + } + if let p = progress { self.progressView?.setProgress(Float(p), animated: true) completion()