diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-10-27 09:51:27 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-10-31 10:25:09 +0100 |
| commit | 29234543ce8a68bd6e78f5bbb745e54bf81b2f28 (patch) | |
| tree | 63cc8e4bda436642da0260a589bda8926f94d364 /ios | |
| parent | 96526fe223025af0fcb4cc9092e963c5b87f5f20 (diff) | |
| download | mullvadvpn-29234543ce8a68bd6e78f5bbb745e54bf81b2f28.tar.xz mullvadvpn-29234543ce8a68bd6e78f5bbb745e54bf81b2f28.zip | |
Introduce StorePaymentEvent to pass payment related data.
Remove App prefix from AppStore related classes
Diffstat (limited to 'ios')
12 files changed, 293 insertions, 214 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index bf46a635ec..dc134a6eb4 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -116,9 +116,9 @@ 58421032282E42B000F24E46 /* UpdateDeviceDataOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58421031282E42B000F24E46 /* UpdateDeviceDataOperation.swift */; }; 58421034282E4B1500F24E46 /* TunnelSettingsV2+REST.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58421033282E4B1500F24E46 /* TunnelSettingsV2+REST.swift */; }; 584592612639B4A200EF967F /* TermsOfServiceContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 584592602639B4A200EF967F /* TermsOfServiceContentView.swift */; }; - 5846227126E229F20035F7C2 /* AppStoreSubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846227026E229F20035F7C2 /* AppStoreSubscription.swift */; }; - 5846227326E22A160035F7C2 /* AppStorePaymentObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846227226E22A160035F7C2 /* AppStorePaymentObserver.swift */; }; - 5846227726E22A7C0035F7C2 /* AppStorePaymentManagerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846227626E22A7C0035F7C2 /* AppStorePaymentManagerDelegate.swift */; }; + 5846227126E229F20035F7C2 /* StoreSubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846227026E229F20035F7C2 /* StoreSubscription.swift */; }; + 5846227326E22A160035F7C2 /* StorePaymentObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846227226E22A160035F7C2 /* StorePaymentObserver.swift */; }; + 5846227726E22A7C0035F7C2 /* StorePaymentManagerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846227626E22A7C0035F7C2 /* StorePaymentManagerDelegate.swift */; }; 584B17AB27637DE40057F3B8 /* ReconnectTunnelOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 584B17AA27637DE40057F3B8 /* ReconnectTunnelOperation.swift */; }; 584D26C2270C8542004EA533 /* SettingsStaticTextFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 584D26C1270C8542004EA533 /* SettingsStaticTextFooterView.swift */; }; 584D26C4270C855B004EA533 /* PreferencesDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 584D26C3270C855A004EA533 /* PreferencesDataSource.swift */; }; @@ -133,7 +133,7 @@ 585B4B8726D9098900555C4C /* TunnelStatusNotificationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A94AE326CFD945001CB97C /* TunnelStatusNotificationProvider.swift */; }; 585C6F4C28F80745005196BE /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = 585C6F4B28F80745005196BE /* Logging */; }; 585CA70F25F8C44600B47C62 /* UIMetrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585CA70E25F8C44600B47C62 /* UIMetrics.swift */; }; - 585E820327F3285E00939F0E /* SendAppStoreReceiptOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585E820227F3285E00939F0E /* SendAppStoreReceiptOperation.swift */; }; + 585E820327F3285E00939F0E /* SendStoreReceiptOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585E820227F3285E00939F0E /* SendStoreReceiptOperation.swift */; }; 5862805422428EF100F5A6E1 /* TranslucentButtonBlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5862805322428EF100F5A6E1 /* TranslucentButtonBlurView.swift */; }; 5868585524054096000B8131 /* AppButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5868585424054096000B8131 /* AppButton.swift */; }; 5868BD33261DCD2600E6027F /* CustomSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5868BD32261DCD2600E6027F /* CustomSplitViewController.swift */; }; @@ -155,6 +155,8 @@ 587425C12299833500CA2045 /* RootContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 587425C02299833500CA2045 /* RootContainerViewController.swift */; }; 5875960A26F371FC00BF6711 /* Tunnel+Messaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5875960926F371FC00BF6711 /* Tunnel+Messaging.swift */; }; 5877D70F282137E8002FCFC7 /* SettingsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FF2C02281BDE02009EF542 /* SettingsManager.swift */; }; + 5878A27529093A310096FC88 /* StorePaymentEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5878A27429093A310096FC88 /* StorePaymentEvent.swift */; }; + 5878A27729093A4F0096FC88 /* StorePaymentBlockObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5878A27629093A4F0096FC88 /* StorePaymentBlockObserver.swift */; }; 587988C728A2A01F00E3DF54 /* AccountDataThrottling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 587988C628A2A01F00E3DF54 /* AccountDataThrottling.swift */; }; 587A01FC23F1F0BE00B68763 /* SimulatorTunnelProviderHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 587A01FB23F1F0BE00B68763 /* SimulatorTunnelProviderHost.swift */; }; 587AD7C623421D7000E93A53 /* TunnelSettingsV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 587AD7C523421D7000E93A53 /* TunnelSettingsV1.swift */; }; @@ -263,7 +265,7 @@ 58D889C828DDF53500583FA8 /* ResultOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F7D26427EB50A300E4D821 /* ResultOperation.swift */; }; 58D889C928DDF53500583FA8 /* InputOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58DF5B732851FF3F00E92647 /* InputOperation.swift */; }; 58D889CA28DDF53500583FA8 /* ResultOperation+Output.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58059DDF2846823E002B1049 /* ResultOperation+Output.swift */; }; - 58DF28A52417CB4B00E836B0 /* AppStorePaymentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58DF28A42417CB4B00E836B0 /* AppStorePaymentManager.swift */; }; + 58DF28A52417CB4B00E836B0 /* StorePaymentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58DF28A42417CB4B00E836B0 /* StorePaymentManager.swift */; }; 58E0729D28814AAE008902F8 /* PacketTunnelConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E0729C28814AAE008902F8 /* PacketTunnelConfiguration.swift */; }; 58E0729F28814ACC008902F8 /* WireGuardLogLevel+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E0729E28814ACC008902F8 /* WireGuardLogLevel+Logging.swift */; }; 58E072A128814B0E008902F8 /* MullvadEndpoint+WgEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E072A028814B0E008902F8 /* MullvadEndpoint+WgEndpoint.swift */; }; @@ -286,10 +288,10 @@ 58F3C0A4249CB069003E76BE /* HeaderBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F3C0A3249CB069003E76BE /* HeaderBarView.swift */; }; 58F7CA882692E34000FC59FD /* WireguardKeysContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F7CA872692E34000FC59FD /* WireguardKeysContentView.swift */; }; 58F8AC0E25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F8AC0D25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift */; }; - 58FB865526E8BF3100F188BC /* AppStorePaymentManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FB865426E8BF3100F188BC /* AppStorePaymentManagerError.swift */; }; + 58FB865526E8BF3100F188BC /* StorePaymentManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FB865426E8BF3100F188BC /* StorePaymentManagerError.swift */; }; 58FB865A26EA214400F188BC /* RelayCacheTrackerObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FB865926EA214400F188BC /* RelayCacheTrackerObserver.swift */; }; 58FC040A27B3EE03001C21F0 /* TunnelMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FC040927B3EE03001C21F0 /* TunnelMonitor.swift */; }; - 58FD5BE724192A2C00112C88 /* AppStoreReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FD5BE624192A2B00112C88 /* AppStoreReceipt.swift */; }; + 58FD5BE724192A2C00112C88 /* StoreReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FD5BE624192A2B00112C88 /* StoreReceipt.swift */; }; 58FD5BF024238EB300112C88 /* SKProduct+Formatting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FD5BEF24238EB300112C88 /* SKProduct+Formatting.swift */; }; 58FD5BF42428C67600112C88 /* InAppPurchaseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FD5BF32428C67600112C88 /* InAppPurchaseButton.swift */; }; 58FEEB46260A028D00A621A8 /* GeoJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FEEB45260A028D00A621A8 /* GeoJSON.swift */; }; @@ -593,9 +595,9 @@ 58421033282E4B1500F24E46 /* TunnelSettingsV2+REST.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelSettingsV2+REST.swift"; sourceTree = "<group>"; }; 584592602639B4A200EF967F /* TermsOfServiceContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsOfServiceContentView.swift; sourceTree = "<group>"; }; 5846226426E0D9630035F7C2 /* ProductsRequestOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductsRequestOperation.swift; sourceTree = "<group>"; }; - 5846227026E229F20035F7C2 /* AppStoreSubscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStoreSubscription.swift; sourceTree = "<group>"; }; - 5846227226E22A160035F7C2 /* AppStorePaymentObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStorePaymentObserver.swift; sourceTree = "<group>"; }; - 5846227626E22A7C0035F7C2 /* AppStorePaymentManagerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStorePaymentManagerDelegate.swift; sourceTree = "<group>"; }; + 5846227026E229F20035F7C2 /* StoreSubscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreSubscription.swift; sourceTree = "<group>"; }; + 5846227226E22A160035F7C2 /* StorePaymentObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorePaymentObserver.swift; sourceTree = "<group>"; }; + 5846227626E22A7C0035F7C2 /* StorePaymentManagerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorePaymentManagerDelegate.swift; sourceTree = "<group>"; }; 584B17AA27637DE40057F3B8 /* ReconnectTunnelOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReconnectTunnelOperation.swift; sourceTree = "<group>"; }; 584B26F3237434D00073B10E /* RelaySelectorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelaySelectorTests.swift; sourceTree = "<group>"; }; 584D26BE270C550B004EA533 /* AnyIPAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyIPAddress.swift; sourceTree = "<group>"; }; @@ -610,7 +612,7 @@ 585DA87626B024A600B8C587 /* CachedRelays.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedRelays.swift; sourceTree = "<group>"; }; 585DA89226B0323E00B8C587 /* TunnelProviderMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelProviderMessage.swift; sourceTree = "<group>"; }; 585DA89826B0329200B8C587 /* PacketTunnelStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelStatus.swift; sourceTree = "<group>"; }; - 585E820227F3285E00939F0E /* SendAppStoreReceiptOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendAppStoreReceiptOperation.swift; sourceTree = "<group>"; }; + 585E820227F3285E00939F0E /* SendStoreReceiptOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendStoreReceiptOperation.swift; sourceTree = "<group>"; }; 5862805322428EF100F5A6E1 /* TranslucentButtonBlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslucentButtonBlurView.swift; sourceTree = "<group>"; }; 5866F39B2243B82D00168AE5 /* MullvadVPN.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MullvadVPN.entitlements; sourceTree = "<group>"; }; 5868585424054096000B8131 /* AppButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppButton.swift; sourceTree = "<group>"; }; @@ -628,6 +630,8 @@ 5875960926F371FC00BF6711 /* Tunnel+Messaging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tunnel+Messaging.swift"; sourceTree = "<group>"; }; 58781CC822AE7CA8009B9D8E /* RelayConstraints.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayConstraints.swift; sourceTree = "<group>"; }; 58781CD422AFBA39009B9D8E /* RelaySelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelaySelector.swift; sourceTree = "<group>"; }; + 5878A27429093A310096FC88 /* StorePaymentEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorePaymentEvent.swift; sourceTree = "<group>"; }; + 5878A27629093A4F0096FC88 /* StorePaymentBlockObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorePaymentBlockObserver.swift; sourceTree = "<group>"; }; 587988C628A2A01F00E3DF54 /* AccountDataThrottling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDataThrottling.swift; sourceTree = "<group>"; }; 587A01FB23F1F0BE00B68763 /* SimulatorTunnelProviderHost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimulatorTunnelProviderHost.swift; sourceTree = "<group>"; }; 587AD7C523421D7000E93A53 /* TunnelSettingsV1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelSettingsV1.swift; sourceTree = "<group>"; }; @@ -716,7 +720,7 @@ 58D0C79D23F1CEBA00FE9BA7 /* SnapshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapshotHelper.swift; sourceTree = "<group>"; }; 58D0C79F23F1CECF00FE9BA7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 58D0C7A023F1CECF00FE9BA7 /* MullvadVPNScreenshots.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MullvadVPNScreenshots.swift; sourceTree = "<group>"; }; - 58DF28A42417CB4B00E836B0 /* AppStorePaymentManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStorePaymentManager.swift; sourceTree = "<group>"; }; + 58DF28A42417CB4B00E836B0 /* StorePaymentManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorePaymentManager.swift; sourceTree = "<group>"; }; 58DF5B732851FF3F00E92647 /* InputOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputOperation.swift; sourceTree = "<group>"; }; 58DF5B752852108E00E92647 /* InputInjectionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputInjectionBuilder.swift; sourceTree = "<group>"; }; 58DF5B772852178600E92647 /* OperationInputInjectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationInputInjectionTests.swift; sourceTree = "<group>"; }; @@ -752,10 +756,10 @@ 58F7CA872692E34000FC59FD /* WireguardKeysContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireguardKeysContentView.swift; sourceTree = "<group>"; }; 58F7D26427EB50A300E4D821 /* ResultOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultOperation.swift; sourceTree = "<group>"; }; 58F8AC0D25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProblemReportReviewViewController.swift; sourceTree = "<group>"; }; - 58FB865426E8BF3100F188BC /* AppStorePaymentManagerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStorePaymentManagerError.swift; sourceTree = "<group>"; }; + 58FB865426E8BF3100F188BC /* StorePaymentManagerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorePaymentManagerError.swift; sourceTree = "<group>"; }; 58FB865926EA214400F188BC /* RelayCacheTrackerObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayCacheTrackerObserver.swift; sourceTree = "<group>"; }; 58FC040927B3EE03001C21F0 /* TunnelMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelMonitor.swift; sourceTree = "<group>"; }; - 58FD5BE624192A2B00112C88 /* AppStoreReceipt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStoreReceipt.swift; sourceTree = "<group>"; }; + 58FD5BE624192A2B00112C88 /* StoreReceipt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreReceipt.swift; sourceTree = "<group>"; }; 58FD5BEF24238EB300112C88 /* SKProduct+Formatting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SKProduct+Formatting.swift"; sourceTree = "<group>"; }; 58FD5BF32428C67600112C88 /* InAppPurchaseButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppPurchaseButton.swift; sourceTree = "<group>"; }; 58FEEB45260A028D00A621A8 /* GeoJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeoJSON.swift; sourceTree = "<group>"; }; @@ -1036,17 +1040,20 @@ path = MullvadVPN; sourceTree = "<group>"; }; - 5846226F26E229CD0035F7C2 /* AppStorePaymentManager */ = { + 5846226F26E229CD0035F7C2 /* StorePaymentManager */ = { isa = PBXGroup; children = ( - 58DF28A42417CB4B00E836B0 /* AppStorePaymentManager.swift */, - 5846227626E22A7C0035F7C2 /* AppStorePaymentManagerDelegate.swift */, - 58FB865426E8BF3100F188BC /* AppStorePaymentManagerError.swift */, - 5846227226E22A160035F7C2 /* AppStorePaymentObserver.swift */, - 5846227026E229F20035F7C2 /* AppStoreSubscription.swift */, - 585E820227F3285E00939F0E /* SendAppStoreReceiptOperation.swift */, + 5878A27629093A4F0096FC88 /* StorePaymentBlockObserver.swift */, + 585E820227F3285E00939F0E /* SendStoreReceiptOperation.swift */, + 5878A27429093A310096FC88 /* StorePaymentEvent.swift */, + 58DF28A42417CB4B00E836B0 /* StorePaymentManager.swift */, + 5846227626E22A7C0035F7C2 /* StorePaymentManagerDelegate.swift */, + 58FB865426E8BF3100F188BC /* StorePaymentManagerError.swift */, + 5846227226E22A160035F7C2 /* StorePaymentObserver.swift */, + 58FD5BE624192A2B00112C88 /* StoreReceipt.swift */, + 5846227026E229F20035F7C2 /* StoreSubscription.swift */, ); - path = AppStorePaymentManager; + path = StorePaymentManager; sourceTree = "<group>"; }; 584F991F2902CBDD001F858D /* Frameworks */ = { @@ -1201,8 +1208,7 @@ 58CCA01722426713004F3011 /* AccountViewController.swift */, 5868585424054096000B8131 /* AppButton.swift */, 58CE5E63224146200008646E /* AppDelegate.swift */, - 5846226F26E229CD0035F7C2 /* AppStorePaymentManager */, - 58FD5BE624192A2B00112C88 /* AppStoreReceipt.swift */, + 5846226F26E229CD0035F7C2 /* StorePaymentManager */, 58CE5E6A224146210008646E /* Assets.xcassets */, 58FEEB57260B662E00A621A8 /* AutomaticKeyboardResponder.swift */, 5891BF1B25E3E3EB006D6FB0 /* Bundle+ProductVersion.swift */, @@ -2029,7 +2035,7 @@ 587D96742886D87C00CD8F1C /* DeviceManagementContentView.swift in Sources */, 589A454C28DDF5E100565204 /* Swizzle.swift in Sources */, 5857F24724C882D700CF6F47 /* SelectLocationNavigationController.swift in Sources */, - 5846227126E229F20035F7C2 /* AppStoreSubscription.swift in Sources */, + 5846227126E229F20035F7C2 /* StoreSubscription.swift in Sources */, 58421030282D8A3C00F24E46 /* UpdateAccountDataOperation.swift in Sources */, 58FF2C03281BDE02009EF542 /* SettingsManager.swift in Sources */, 587EB672271451E300123C75 /* PreferencesViewModel.swift in Sources */, @@ -2039,6 +2045,7 @@ 58BA693123EADA6A009DC256 /* SimulatorTunnelProvider.swift in Sources */, 587B753B2666467500DEF7E9 /* NotificationBannerView.swift in Sources */, 58B993B12608A34500BA7811 /* LoginContentView.swift in Sources */, + 5878A27529093A310096FC88 /* StorePaymentEvent.swift in Sources */, 58E6771F24ADFE7800AA26E7 /* SettingsNavigationController.swift in Sources */, 58A1AA8C23F5584C009F7EA6 /* ConnectionPanelView.swift in Sources */, 582BB1B3229574F40055B6EF /* SettingsAccountCell.swift in Sources */, @@ -2065,14 +2072,14 @@ 58F2E14C276A61C000A79513 /* RotateKeyOperation.swift in Sources */, 5871FB96254ADE4E0051A0A4 /* ConsolidatedApplicationLog.swift in Sources */, 58FEEB58260B662E00A621A8 /* AutomaticKeyboardResponder.swift in Sources */, - 5846227326E22A160035F7C2 /* AppStorePaymentObserver.swift in Sources */, + 5846227326E22A160035F7C2 /* StorePaymentObserver.swift in Sources */, 58F2E146276A2C9900A79513 /* StopTunnelOperation.swift in Sources */, E1187ABC289BBB850024E748 /* OutOfTimeViewController.swift in Sources */, 58293FB125124117005D0BB5 /* CustomTextField.swift in Sources */, 582AE3102440A6CA00E6733A /* AccountTokenInput.swift in Sources */, 5820EDAB288FF0D2006BF4E4 /* DeviceRowView.swift in Sources */, 75FD0C2128B108570021E33E /* ShortcutsDataSource.swift in Sources */, - 5846227726E22A7C0035F7C2 /* AppStorePaymentManagerDelegate.swift in Sources */, + 5846227726E22A7C0035F7C2 /* StorePaymentManagerDelegate.swift in Sources */, 58EF581125D69DB400AEBA94 /* StatusImageView.swift in Sources */, 58907D9524D17B4E00CFC3F5 /* DisconnectSplitButton.swift in Sources */, 58EE2E3B272FF814003BFF93 /* SettingsDataSourceDelegate.swift in Sources */, @@ -2092,14 +2099,15 @@ 75FD0C2528B117D30021E33E /* ShortcutsViewController.swift in Sources */, 5871FBA0254C26C00051A0A4 /* NSRegularExpression+IPAddress.swift in Sources */, 58F7CA882692E34000FC59FD /* WireguardKeysContentView.swift in Sources */, + 5878A27729093A4F0096FC88 /* StorePaymentBlockObserver.swift in Sources */, 5868585524054096000B8131 /* AppButton.swift in Sources */, 58E25F812837BBBB002CFB2C /* SceneDelegate.swift in Sources */, - 585E820327F3285E00939F0E /* SendAppStoreReceiptOperation.swift in Sources */, + 585E820327F3285E00939F0E /* SendStoreReceiptOperation.swift in Sources */, 584B17AB27637DE40057F3B8 /* ReconnectTunnelOperation.swift in Sources */, 5820676426E771DB00655B05 /* TunnelManagerErrors.swift in Sources */, 585B4B8726D9098900555C4C /* TunnelStatusNotificationProvider.swift in Sources */, 063F026628FFE11C001FA09F /* RESTCreateApplePaymentResponse+Localization.swift in Sources */, - 58DF28A52417CB4B00E836B0 /* AppStorePaymentManager.swift in Sources */, + 58DF28A52417CB4B00E836B0 /* StorePaymentManager.swift in Sources */, 583DA21425FA4B5C00318683 /* LocationDataSource.swift in Sources */, 587EB6742714520600123C75 /* PreferencesDataSourceDelegate.swift in Sources */, 582BB1AF229566420055B6EF /* SettingsCell.swift in Sources */, @@ -2113,7 +2121,7 @@ 5807E2C02432038B00F5FF30 /* String+Split.swift in Sources */, 58CE5E66224146200008646E /* LoginViewController.swift in Sources */, 58EF580B25D69D7A00AEBA94 /* ProblemReportSubmissionOverlayView.swift in Sources */, - 58FD5BE724192A2C00112C88 /* AppStoreReceipt.swift in Sources */, + 58FD5BE724192A2C00112C88 /* StoreReceipt.swift in Sources */, 5892A45E265FABFF00890742 /* EmptyTableViewHeaderFooterView.swift in Sources */, 580909D32876D09A0078138D /* RevokedDeviceViewController.swift in Sources */, 5835B7CC233B76CB0096D79F /* TunnelManager.swift in Sources */, @@ -2131,7 +2139,7 @@ 5872631D283F755900E14ADF /* IntentHandlers.swift in Sources */, 58CCA01222424D11004F3011 /* SettingsViewController.swift in Sources */, 580F8B8628197958002E0998 /* DNSSettings.swift in Sources */, - 58FB865526E8BF3100F188BC /* AppStorePaymentManagerError.swift in Sources */, + 58FB865526E8BF3100F188BC /* StorePaymentManagerError.swift in Sources */, 58FD5BF42428C67600112C88 /* InAppPurchaseButton.swift in Sources */, 587D9676288989DB00CD8F1C /* NSLayoutConstraint+Helpers.swift in Sources */, 58293FAE2510CA58005D0BB5 /* ProblemReportViewController.swift in Sources */, diff --git a/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentManagerError.swift b/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentManagerError.swift deleted file mode 100644 index a57306aba9..0000000000 --- a/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentManagerError.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// AppStorePaymentManagerError.swift -// AppStorePaymentManagerError -// -// Created by pronebird on 08/09/2021. -// Copyright © 2021 Mullvad VPN AB. All rights reserved. -// - -import Foundation -import MullvadREST -import MullvadTypes - -extension AppStorePaymentManager { - /// An error type emitted by `AppStorePaymentManager`. - enum Error: LocalizedError, WrappingError { - /// Failure to find the account token associated with the transaction. - case noAccountSet - - /// Failure to validate the account token. - case validateAccount(REST.Error) - - /// Failure to handle payment transaction. Contains error returned by StoreKit. - case storePayment(Swift.Error) - - /// Failure to read the AppStore receipt. - case readReceipt(Swift.Error) - - /// Failure to send the AppStore receipt to backend. - case sendReceipt(REST.Error) - - var errorDescription: String? { - switch self { - case .noAccountSet: - return "Account is not set." - case .validateAccount: - return "Account validation error." - case .storePayment: - return "Store payment error." - case .readReceipt: - return "Read recept error." - case .sendReceipt: - return "Send receipt error." - } - } - - var underlyingError: Swift.Error? { - switch self { - case .noAccountSet: - return nil - case let .sendReceipt(error): - return error - case let .validateAccount(error): - return error - case let .readReceipt(error): - return error - case let .storePayment(error): - return error - } - } - } -} diff --git a/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentObserver.swift b/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentObserver.swift deleted file mode 100644 index 306f5b3bef..0000000000 --- a/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentObserver.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// AppStorePaymentObserver.swift -// AppStorePaymentObserver -// -// Created by pronebird on 03/09/2021. -// Copyright © 2021 Mullvad VPN AB. All rights reserved. -// - -import Foundation -import MullvadREST -import StoreKit - -protocol AppStorePaymentObserver: AnyObject { - func appStorePaymentManager( - _ manager: AppStorePaymentManager, - transaction: SKPaymentTransaction?, - payment: SKPayment, - accountToken: String?, - didFailWithError error: AppStorePaymentManager.Error - ) - - func appStorePaymentManager( - _ manager: AppStorePaymentManager, - transaction: SKPaymentTransaction, - accountToken: String, - didFinishWithResponse response: REST.CreateApplePaymentResponse - ) -} diff --git a/ios/MullvadVPN/AppStorePaymentManager/SendAppStoreReceiptOperation.swift b/ios/MullvadVPN/StorePaymentManager/SendStoreReceiptOperation.swift index 860111e6f0..0b360a7184 100644 --- a/ios/MullvadVPN/AppStorePaymentManager/SendAppStoreReceiptOperation.swift +++ b/ios/MullvadVPN/StorePaymentManager/SendStoreReceiptOperation.swift @@ -1,5 +1,5 @@ // -// SendAppStoreReceiptOperation.swift +// SendStoreReceiptOperation.swift // MullvadVPN // // Created by pronebird on 29/03/2022. @@ -12,9 +12,9 @@ import MullvadREST import MullvadTypes import Operations -class SendAppStoreReceiptOperation: ResultOperation< +class SendStoreReceiptOperation: ResultOperation< REST.CreateApplePaymentResponse, - AppStorePaymentManager.Error + StorePaymentManagerError > { private let apiProxy: REST.APIProxy private let accountToken: String @@ -23,7 +23,7 @@ class SendAppStoreReceiptOperation: ResultOperation< private var fetchReceiptTask: Cancellable? private var submitReceiptTask: Cancellable? - private let logger = Logger(label: "SendAppStoreReceiptOperation") + private let logger = Logger(label: "SendStoreReceiptOperation") init( apiProxy: REST.APIProxy, @@ -53,7 +53,7 @@ class SendAppStoreReceiptOperation: ResultOperation< } override func main() { - fetchReceiptTask = AppStoreReceipt.fetch( + fetchReceiptTask = StoreReceipt.fetch( forceRefresh: forceRefresh, receiptProperties: receiptProperties ) { completion in @@ -82,10 +82,13 @@ class SendAppStoreReceiptOperation: ResultOperation< ) { result in switch result { case let .success(response): - self.logger - .info( - "AppStore receipt was processed. Time added: \(response.timeAdded), New expiry: \(response.newExpiry.logFormatDate())" - ) + self.logger.info( + """ + AppStore receipt was processed. \ + Time added: \(response.timeAdded), \ + New expiry: \(response.newExpiry.logFormatDate()) + """ + ) self.finish(completion: .success(response)) case let .failure(error): diff --git a/ios/MullvadVPN/StorePaymentManager/StorePaymentBlockObserver.swift b/ios/MullvadVPN/StorePaymentManager/StorePaymentBlockObserver.swift new file mode 100644 index 0000000000..ce3fd61915 --- /dev/null +++ b/ios/MullvadVPN/StorePaymentManager/StorePaymentBlockObserver.swift @@ -0,0 +1,26 @@ +// +// StorePaymentBlockObserver.swift +// MullvadVPN +// +// Created by pronebird on 26/10/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +final class StorePaymentBlockObserver: StorePaymentObserver { + typealias BlockHandler = (StorePaymentManager, StorePaymentEvent) -> Void + + private let blockHandler: BlockHandler + + init(_ blockHandler: @escaping BlockHandler) { + self.blockHandler = blockHandler + } + + func storePaymentManager( + _ manager: StorePaymentManager, + didReceiveEvent event: StorePaymentEvent + ) { + blockHandler(manager, event) + } +} diff --git a/ios/MullvadVPN/StorePaymentManager/StorePaymentEvent.swift b/ios/MullvadVPN/StorePaymentManager/StorePaymentEvent.swift new file mode 100644 index 0000000000..ed03a59121 --- /dev/null +++ b/ios/MullvadVPN/StorePaymentManager/StorePaymentEvent.swift @@ -0,0 +1,38 @@ +// +// StorePaymentEvent.swift +// MullvadVPN +// +// Created by pronebird on 26/10/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadREST +import StoreKit + +enum StorePaymentEvent { + case finished(StorePaymentCompletion) + case failure(StorePaymentFailure) + + var payment: SKPayment { + switch self { + case let .finished(completion): + return completion.transaction.payment + case let .failure(failure): + return failure.payment + } + } +} + +struct StorePaymentCompletion { + let transaction: SKPaymentTransaction + let accountNumber: String + let serverResponse: REST.CreateApplePaymentResponse +} + +struct StorePaymentFailure { + let transaction: SKPaymentTransaction? + let payment: SKPayment + let accountNumber: String? + let error: StorePaymentManagerError +} diff --git a/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentManager.swift b/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift index fcd41595df..53394d5eb1 100644 --- a/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentManager.swift +++ b/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift @@ -1,5 +1,5 @@ // -// AppStorePaymentManager.swift +// StorePaymentManager.swift // MullvadVPN // // Created by pronebird on 10/03/2020. @@ -13,31 +13,27 @@ import MullvadTypes import Operations import StoreKit -class AppStorePaymentManager: NSObject, SKPaymentTransactionObserver { +class StorePaymentManager: NSObject, SKPaymentTransactionObserver { private enum OperationCategory { - static let sendAppStoreReceipt = "AppStorePaymentManager.sendAppStoreReceipt" - static let productsRequest = "AppStorePaymentManager.productsRequest" + static let sendStoreReceipt = "StorePaymentManager.sendStoreReceipt" + static let productsRequest = "StorePaymentManager.productsRequest" } - /// A shared instance of `AppStorePaymentManager` - static let shared = AppStorePaymentManager(queue: SKPaymentQueue.default()) - - private let logger = Logger(label: "AppStorePaymentManager") + private let logger = Logger(label: "StorePaymentManager") private let operationQueue: OperationQueue = { let queue = AsyncOperationQueue() - queue.name = "AppStorePaymentManagerQueue" + queue.name = "StorePaymentManagerQueue" return queue }() - private let apiProxy = REST.ProxyFactory.shared.createAPIProxy() - private let accountsProxy = REST.ProxyFactory.shared.createAccountsProxy() - private let paymentQueue: SKPaymentQueue - private var observerList = ObserverList<AppStorePaymentObserver>() + private let apiProxy: REST.APIProxy + private let accountsProxy: REST.AccountsProxy + private var observerList = ObserverList<StorePaymentObserver>() - private weak var classDelegate: AppStorePaymentManagerDelegate? - weak var delegate: AppStorePaymentManagerDelegate? { + private weak var classDelegate: StorePaymentManagerDelegate? + weak var delegate: StorePaymentManagerDelegate? { get { if Thread.isMainThread { return classDelegate @@ -66,8 +62,10 @@ class AppStorePaymentManager: NSObject, SKPaymentTransactionObserver { return SKPaymentQueue.canMakePayments() } - init(queue: SKPaymentQueue) { + init(queue: SKPaymentQueue, apiProxy: REST.APIProxy, accountsProxy: REST.AccountsProxy) { paymentQueue = queue + self.apiProxy = apiProxy + self.accountsProxy = accountsProxy } func startPaymentQueueMonitoring() { @@ -93,18 +91,18 @@ class AppStorePaymentManager: NSObject, SKPaymentTransactionObserver { // MARK: - Payment observation - func addPaymentObserver(_ observer: AppStorePaymentObserver) { + func addPaymentObserver(_ observer: StorePaymentObserver) { observerList.append(observer) } - func removePaymentObserver(_ observer: AppStorePaymentObserver) { + func removePaymentObserver(_ observer: StorePaymentObserver) { observerList.remove(observer) } // MARK: - Products and payments func requestProducts( - with productIdentifiers: Set<AppStoreSubscription>, + with productIdentifiers: Set<StoreSubscription>, completionHandler: @escaping (OperationCompletion<SKProductsResponse, Swift.Error>) -> Void ) -> Cancellable { let productIdentifiers = productIdentifiers.productIdentifiersSet @@ -139,25 +137,31 @@ class AppStorePaymentManager: NSObject, SKPaymentTransactionObserver { self.paymentQueue.add(payment) case let .failure(error): - self.observerList.forEach { observer in - observer.appStorePaymentManager( - self, + let event = StorePaymentEvent.failure( + StorePaymentFailure( transaction: nil, payment: payment, - accountToken: accountToken, - didFailWithError: .validateAccount(error) + accountNumber: accountToken, + error: .validateAccount(error) ) + ) + + self.observerList.forEach { observer in + observer.storePaymentManager(self, didReceiveEvent: event) } case .cancelled: - self.observerList.forEach { observer in - observer.appStorePaymentManager( - self, + let event = StorePaymentEvent.failure( + StorePaymentFailure( transaction: nil, payment: payment, - accountToken: accountToken, - didFailWithError: .validateAccount(.network(URLError(.cancelled))) + accountNumber: accountToken, + error: .validateAccount(.network(URLError(.cancelled))) ) + ) + + self.observerList.forEach { observer in + observer.storePaymentManager(self, didReceiveEvent: event) } } @@ -169,10 +173,10 @@ class AppStorePaymentManager: NSObject, SKPaymentTransactionObserver { for accountToken: String, completionHandler: @escaping (OperationCompletion< REST.CreateApplePaymentResponse, - AppStorePaymentManager.Error + StorePaymentManagerError >) -> Void ) -> Cancellable { - return sendAppStoreReceipt( + return sendStoreReceipt( accountToken: accountToken, forceRefresh: true, completionHandler: completionHandler @@ -194,17 +198,20 @@ class AppStorePaymentManager: NSObject, SKPaymentTransactionObserver { paymentToAccountToken.removeValue(forKey: payment) return accountToken } else { - return classDelegate?.appStorePaymentManager(self, didRequestAccountTokenFor: payment) + return classDelegate?.storePaymentManager(self, didRequestAccountTokenFor: payment) } } - private func sendAppStoreReceipt( + private func sendStoreReceipt( accountToken: String, forceRefresh: Bool, - completionHandler: @escaping (OperationCompletion<REST.CreateApplePaymentResponse, Error>) + completionHandler: @escaping (OperationCompletion< + REST.CreateApplePaymentResponse, + StorePaymentManagerError + >) -> Void ) -> Cancellable { - let operation = SendAppStoreReceiptOperation( + let operation = SendStoreReceiptOperation( apiProxy: apiProxy, accountToken: accountToken, forceRefresh: forceRefresh, @@ -221,7 +228,7 @@ class AppStorePaymentManager: NSObject, SKPaymentTransactionObserver { ) operation.addCondition( - MutuallyExclusive(category: OperationCategory.sendAppStoreReceipt) + MutuallyExclusive(category: OperationCategory.sendStoreReceipt) ) operationQueue.addOperation(operation) @@ -270,65 +277,76 @@ class AppStorePaymentManager: NSObject, SKPaymentTransactionObserver { paymentQueue.finishTransaction(transaction) if let accountToken = deassociateAccountToken(transaction.payment) { - observerList.forEach { observer in - observer.appStorePaymentManager( - self, + let event = StorePaymentEvent.failure( + StorePaymentFailure( transaction: transaction, payment: transaction.payment, - accountToken: accountToken, - didFailWithError: .storePayment(transaction.error!) + accountNumber: accountToken, + error: .storePayment(transaction.error!) ) + ) + + observerList.forEach { observer in + observer.storePaymentManager(self, didReceiveEvent: event) } } else { - observerList.forEach { observer in - observer.appStorePaymentManager( - self, + let event = StorePaymentEvent.failure( + StorePaymentFailure( transaction: transaction, payment: transaction.payment, - accountToken: nil, - didFailWithError: .noAccountSet + accountNumber: nil, + error: .noAccountSet ) + ) + + observerList.forEach { observer in + observer.storePaymentManager(self, didReceiveEvent: event) } } } private func didFinishOrRestorePurchase(transaction: SKPaymentTransaction) { guard let accountToken = deassociateAccountToken(transaction.payment) else { - observerList.forEach { observer in - observer.appStorePaymentManager( - self, + let event = StorePaymentEvent.failure( + StorePaymentFailure( transaction: transaction, payment: transaction.payment, - accountToken: nil, - didFailWithError: .noAccountSet + accountNumber: nil, + error: .noAccountSet ) + ) + + observerList.forEach { observer in + observer.storePaymentManager(self, didReceiveEvent: event) } return } - _ = sendAppStoreReceipt(accountToken: accountToken, forceRefresh: false) { completion in + _ = sendStoreReceipt(accountToken: accountToken, forceRefresh: false) { completion in switch completion { case let .success(response): self.paymentQueue.finishTransaction(transaction) + let event = StorePaymentEvent.finished(StorePaymentCompletion( + transaction: transaction, + accountNumber: accountToken, + serverResponse: response + )) + self.observerList.forEach { observer in - observer.appStorePaymentManager( - self, - transaction: transaction, - accountToken: accountToken, - didFinishWithResponse: response - ) + observer.storePaymentManager(self, didReceiveEvent: event) } case let .failure(error): + let event = StorePaymentEvent.failure(StorePaymentFailure( + transaction: transaction, + payment: transaction.payment, + accountNumber: accountToken, + error: error + )) + self.observerList.forEach { observer in - observer.appStorePaymentManager( - self, - transaction: transaction, - payment: transaction.payment, - accountToken: accountToken, - didFailWithError: error - ) + observer.storePaymentManager(self, didReceiveEvent: event) } case .cancelled: diff --git a/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentManagerDelegate.swift b/ios/MullvadVPN/StorePaymentManager/StorePaymentManagerDelegate.swift index 8dc848c854..a98a37e8da 100644 --- a/ios/MullvadVPN/AppStorePaymentManager/AppStorePaymentManagerDelegate.swift +++ b/ios/MullvadVPN/StorePaymentManager/StorePaymentManagerDelegate.swift @@ -1,6 +1,6 @@ // -// AppStorePaymentManagerDelegate.swift -// AppStorePaymentManagerDelegate +// StorePaymentManagerDelegate.swift +// MullvadVPN // // Created by pronebird on 03/09/2021. // Copyright © 2021 Mullvad VPN AB. All rights reserved. @@ -9,11 +9,11 @@ import Foundation import StoreKit -protocol AppStorePaymentManagerDelegate: AnyObject { +protocol StorePaymentManagerDelegate: AnyObject { /// Return the account token associated with the payment. /// Usually called for unfinished transactions coming back after the app was restarted. - func appStorePaymentManager( - _ manager: AppStorePaymentManager, + func storePaymentManager( + _ manager: StorePaymentManager, didRequestAccountTokenFor payment: SKPayment ) -> String? } diff --git a/ios/MullvadVPN/StorePaymentManager/StorePaymentManagerError.swift b/ios/MullvadVPN/StorePaymentManager/StorePaymentManagerError.swift new file mode 100644 index 0000000000..83a5508e77 --- /dev/null +++ b/ios/MullvadVPN/StorePaymentManager/StorePaymentManagerError.swift @@ -0,0 +1,59 @@ +// +// StorePaymentManagerError.swift +// MullvadVPN +// +// Created by pronebird on 08/09/2021. +// Copyright © 2021 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadREST +import MullvadTypes + +/// An error type emitted by `StorePaymentManager`. +enum StorePaymentManagerError: LocalizedError, WrappingError { + /// Failure to find the account token associated with the transaction. + case noAccountSet + + /// Failure to validate the account token. + case validateAccount(REST.Error) + + /// Failure to handle payment transaction. Contains error returned by StoreKit. + case storePayment(Swift.Error) + + /// Failure to read the AppStore receipt. + case readReceipt(Swift.Error) + + /// Failure to send the AppStore receipt to backend. + case sendReceipt(REST.Error) + + var errorDescription: String? { + switch self { + case .noAccountSet: + return "Account is not set." + case .validateAccount: + return "Account validation error." + case .storePayment: + return "Store payment error." + case .readReceipt: + return "Read recept error." + case .sendReceipt: + return "Send receipt error." + } + } + + var underlyingError: Swift.Error? { + switch self { + case .noAccountSet: + return nil + case let .sendReceipt(error): + return error + case let .validateAccount(error): + return error + case let .readReceipt(error): + return error + case let .storePayment(error): + return error + } + } +} diff --git a/ios/MullvadVPN/StorePaymentManager/StorePaymentObserver.swift b/ios/MullvadVPN/StorePaymentManager/StorePaymentObserver.swift new file mode 100644 index 0000000000..0d6e3584fc --- /dev/null +++ b/ios/MullvadVPN/StorePaymentManager/StorePaymentObserver.swift @@ -0,0 +1,16 @@ +// +// StorePaymentObserver.swift +// MullvadVPN +// +// Created by pronebird on 03/09/2021. +// Copyright © 2021 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +protocol StorePaymentObserver: AnyObject { + func storePaymentManager( + _ manager: StorePaymentManager, + didReceiveEvent event: StorePaymentEvent + ) +} diff --git a/ios/MullvadVPN/AppStoreReceipt.swift b/ios/MullvadVPN/StorePaymentManager/StoreReceipt.swift index edc20573d8..93731ba7f9 100644 --- a/ios/MullvadVPN/AppStoreReceipt.swift +++ b/ios/MullvadVPN/StorePaymentManager/StoreReceipt.swift @@ -1,5 +1,5 @@ // -// AppStoreReceipt.swift +// StoreReceipt.swift // MullvadVPN // // Created by pronebird on 11/03/2020. @@ -12,17 +12,17 @@ import MullvadTypes import Operations import StoreKit -struct AppStoreReceiptNotFound: LocalizedError { +struct StoreReceiptNotFound: LocalizedError { var errorDescription: String? { return "AppStore receipt file does not exist on disk." } } -enum AppStoreReceipt { +enum StoreReceipt { /// Internal operation queue. private static let operationQueue: OperationQueue = { let queue = AsyncOperationQueue() - queue.name = "AppStoreReceiptQueue" + queue.name = "StoreReceiptQueue" queue.maxConcurrentOperationCount = 1 return queue }() @@ -86,7 +86,7 @@ private class FetchAppStoreReceiptOperation: ResultOperation<Data, Error>, SKReq let data = try readReceiptFromDisk() finish(completion: .success(data)) - } catch is AppStoreReceiptNotFound { + } catch is StoreReceiptNotFound { // Pull receipt from AppStore if it's not cached locally. startRefreshRequest() } catch { @@ -139,7 +139,7 @@ private class FetchAppStoreReceiptOperation: ResultOperation<Data, Error>, SKReq private func readReceiptFromDisk() throws -> Data { guard let appStoreReceiptURL = Bundle.main.appStoreReceiptURL else { - throw AppStoreReceiptNotFound() + throw StoreReceiptNotFound() } do { @@ -147,7 +147,7 @@ private class FetchAppStoreReceiptOperation: ResultOperation<Data, Error>, SKReq } catch let error as CocoaError where error.code == .fileReadNoSuchFile || error.code == .fileNoSuchFile { - throw AppStoreReceiptNotFound() + throw StoreReceiptNotFound() } catch { throw error } diff --git a/ios/MullvadVPN/AppStorePaymentManager/AppStoreSubscription.swift b/ios/MullvadVPN/StorePaymentManager/StoreSubscription.swift index 37fa3342cb..105ae4425f 100644 --- a/ios/MullvadVPN/AppStorePaymentManager/AppStoreSubscription.swift +++ b/ios/MullvadVPN/StorePaymentManager/StoreSubscription.swift @@ -1,6 +1,6 @@ // -// AppStoreSubscription.swift -// AppStoreSubscription +// StoreSubscription.swift +// MullvadVPN // // Created by pronebird on 03/09/2021. // Copyright © 2021 Mullvad VPN AB. All rights reserved. @@ -9,7 +9,7 @@ import Foundation import StoreKit -enum AppStoreSubscription: String { +enum StoreSubscription: String { /// Thirty days non-renewable subscription case thirtyDays = "net.mullvad.MullvadVPN.subscription.30days" @@ -17,8 +17,8 @@ enum AppStoreSubscription: String { switch self { case .thirtyDays: return NSLocalizedString( - "APPSTORE_SUBSCRIPTION_TITLE_ADD_30_DAYS", - tableName: "AppStoreSubscriptions", + "STORE_SUBSCRIPTION_TITLE_ADD_30_DAYS", + tableName: "StoreSubscriptions", value: "Add 30 days time", comment: "" ) @@ -28,12 +28,12 @@ enum AppStoreSubscription: String { extension SKProduct { var customLocalizedTitle: String? { - return AppStoreSubscription(rawValue: productIdentifier)?.localizedTitle + return StoreSubscription(rawValue: productIdentifier)?.localizedTitle } } -extension Set where Element == AppStoreSubscription { +extension Set where Element == StoreSubscription { var productIdentifiersSet: Set<String> { - Set<String>(map { $0.rawValue }) + return Set<String>(map { $0.rawValue }) } } |
