diff --git a/Passepartout.xcodeproj/project.pbxproj b/Passepartout.xcodeproj/project.pbxproj index 6384610c..54cf3034 100644 --- a/Passepartout.xcodeproj/project.pbxproj +++ b/Passepartout.xcodeproj/project.pbxproj @@ -492,6 +492,7 @@ 0ED89C1627DE0E05008B36D6 /* IntentEditView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentEditView.swift; sourceTree = ""; }; 0ED89C1B27DE3ABC008B36D6 /* ShortcutsView+Add.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ShortcutsView+Add.swift"; sourceTree = ""; }; 0ED89C1D27DE3F8D008B36D6 /* IntentAddView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentAddView.swift; sourceTree = ""; }; + 0EDCEF692B337BEB0023A7FF /* PassepartoutLibrary.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = PassepartoutLibrary.xctestplan; sourceTree = ""; }; 0EDDEC7C28D0DC130017802E /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 0EDE02C127F61C79000FBE3C /* EditableTextList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditableTextList.swift; sourceTree = ""; }; 0EDE8DBF20C86910004C739C /* PassepartoutOpenVPNTunnel.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = PassepartoutOpenVPNTunnel.appex; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -804,6 +805,7 @@ children = ( 0EE315DB2733104700F5D461 /* Packages */, 0E23B4A12298559800304C30 /* Config.xcconfig */, + 0EDCEF692B337BEB0023A7FF /* PassepartoutLibrary.xctestplan */, 0E9AA982259F7674003FAFF1 /* Passepartout */, 0E57F63920C83FC5008323CF /* Products */, 374B9F085E1148C37CF9117A /* Frameworks */, @@ -1131,7 +1133,7 @@ attributes = { BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1510; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = "Davide De Rosa"; TargetAttributes = { 0E41BD96286711C3006346B4 = { diff --git a/Passepartout.xcodeproj/xcshareddata/xcschemes/Passepartout.xcscheme b/Passepartout.xcodeproj/xcshareddata/xcschemes/Passepartout.xcscheme index f03ed8c6..fe233326 100644 --- a/Passepartout.xcodeproj/xcshareddata/xcschemes/Passepartout.xcscheme +++ b/Passepartout.xcodeproj/xcshareddata/xcschemes/Passepartout.xcscheme @@ -1,6 +1,6 @@ ) { - switch result { - case .success(let value): - if case .done = value { - alertType = .thankYou - isAlertPresented = true - } else { - // cancelled - } - - case .failure(let error): - ErrorHandler.shared.handle( - title: L10n.Donate.title, - message: L10n.Donate.Alerts.Purchase.Failure.message(AppError(error).localizedDescription) - ) + func handlePurchaseResult(_ result: InAppPurchaseResult) { + if case .done = result { + alertType = .thankYou + isAlertPresented = true + } else { + // cancelled } pendingDonationIdentifier = nil } + + func handlePurchaseError(_ error: Error) { + ErrorHandler.shared.handle( + title: L10n.Donate.title, + message: L10n.Donate.Alerts.Purchase.Failure.message(AppError(error).localizedDescription) + ) + pendingDonationIdentifier = nil + } + } diff --git a/Passepartout/App/Views/PaywallView+Purchase.swift b/Passepartout/App/Views/PaywallView+Purchase.swift index 1eb89b0b..a46d5b95 100644 --- a/Passepartout/App/Views/PaywallView+Purchase.swift +++ b/Passepartout/App/Views/PaywallView+Purchase.swift @@ -57,13 +57,17 @@ extension PaywallView { }.navigationTitle(Unlocalized.appName) // reloading - .onAppear { - productManager.refreshProducts() - }.onChange(of: scenePhase) { newValue in + .task { + await productManager.refreshProducts() + } + .onChange(of: scenePhase) { newValue in if newValue == .active { - productManager.refreshProducts() + Task { + await productManager.refreshProducts() + } } - }.themeAnimation(on: productManager.isRefreshingProducts) + } + .themeAnimation(on: productManager.isRefreshingProducts) } } } @@ -247,9 +251,9 @@ private extension PaywallView.PurchaseView { func purchaseProduct(_ product: InAppProduct) { purchaseState = .purchasing(product) - productManager.purchase(product) { - switch $0 { - case .success(let result): + Task { + do { + let result = try await productManager.purchase(product) switch result { case .done: isPresented = false @@ -258,8 +262,7 @@ private extension PaywallView.PurchaseView { break } purchaseState = nil - - case .failure(let error): + } catch { pp_log.error("Unable to purchase: \(error)") ErrorHandler.shared.handle( title: product.localizedTitle, @@ -274,8 +277,12 @@ private extension PaywallView.PurchaseView { func restorePurchases() { purchaseState = .restoring - productManager.restorePurchases { - if let error = $0 { + Task { + do { + try await productManager.restorePurchases() + isPresented = false + purchaseState = nil + } catch { pp_log.error("Unable to restore purchases: \(error)") ErrorHandler.shared.handle( title: L10n.Paywall.Items.Restore.title, @@ -283,10 +290,7 @@ private extension PaywallView.PurchaseView { ) { purchaseState = nil } - return } - isPresented = false - purchaseState = nil } } } diff --git a/Passepartout/App/Views/PaywallView.swift b/Passepartout/App/Views/PaywallView.swift index f0553420..cd65bc5c 100644 --- a/Passepartout/App/Views/PaywallView.swift +++ b/Passepartout/App/Views/PaywallView.swift @@ -23,8 +23,8 @@ // along with Passepartout. If not, see . // -import SwiftUI import PassepartoutLibrary +import SwiftUI struct PaywallView: View { @ObservedObject private var productManager: ProductManager diff --git a/PassepartoutLibrary.xctestplan b/PassepartoutLibrary.xctestplan new file mode 100644 index 00000000..dd24e3db --- /dev/null +++ b/PassepartoutLibrary.xctestplan @@ -0,0 +1,45 @@ +{ + "configurations" : [ + { + "id" : "848BBF4E-F054-4BFC-A034-AD5C49863245", + "name" : "Test Scheme Action", + "options" : { + + } + } + ], + "defaultOptions" : { + "codeCoverage" : false + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:", + "identifier" : "PassepartoutCoreTests", + "name" : "PassepartoutCoreTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "PassepartoutFrontendTests", + "name" : "PassepartoutFrontendTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "PassepartoutProvidersTests", + "name" : "PassepartoutProvidersTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "PassepartoutServicesTests", + "name" : "PassepartoutServicesTests" + } + } + ], + "version" : 1 +} diff --git a/PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/OpenVPNAppExtension.xcscheme b/PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/OpenVPNAppExtension.xcscheme index 7c2cb106..d4b422fe 100644 --- a/PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/OpenVPNAppExtension.xcscheme +++ b/PassepartoutLibrary/.swiftpm/xcode/xcshareddata/xcschemes/OpenVPNAppExtension.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> + + + + ) -> Void) { + public func purchase(_ product: InAppProduct) async throws -> InAppPurchaseResult { guard let pid = LocalProduct(rawValue: product.productIdentifier) else { + assertionFailure("Unrecognized product: \(product)") pp_log.warning("Unrecognized product: \(product)") - return - } - Task { - do { - let result = try await inApp.purchase(productWithIdentifier: pid) - reloadReceipt() - completionHandler(.success(result)) - } catch { - completionHandler(.failure(error)) - } + return .cancelled } + let result = try await inApp.purchase(productWithIdentifier: pid) + reloadReceipt() + return result } - public func restorePurchases(completionHandler: @escaping (Error?) -> Void) { - Task { - do { - try await inApp.restorePurchases() - completionHandler(nil) - } catch { - completionHandler(error) - } - } + public func restorePurchases() async throws { + try await inApp.restorePurchases() } }