@@ -8,7 +8,7 @@ import SignalUI
88import StoreKit
99import UIKit
1010
11- class BackupEnablingManager {
11+ final class BackupEnablingManager {
1212 struct DisplayableError : Error {
1313 let localizedActionSheetMessage : String
1414
@@ -31,6 +31,7 @@ class BackupEnablingManager {
3131 private let backupIdManager : BackupIdManager
3232 private let backupPlanManager : BackupPlanManager
3333 private let backupSubscriptionManager : BackupSubscriptionManager
34+ private let backupTestFlightEntitlementManager : BackupTestFlightEntitlementManager
3435 private let db : DB
3536 private let tsAccountManager : TSAccountManager
3637
@@ -39,13 +40,15 @@ class BackupEnablingManager {
3940 backupIdManager: BackupIdManager ,
4041 backupPlanManager: BackupPlanManager ,
4142 backupSubscriptionManager: BackupSubscriptionManager ,
43+ backupTestFlightEntitlementManager: BackupTestFlightEntitlementManager ,
4244 db: DB ,
4345 tsAccountManager: TSAccountManager
4446 ) {
4547 self . backupDisablingManager = backupDisablingManager
4648 self . backupIdManager = backupIdManager
4749 self . backupPlanManager = backupPlanManager
4850 self . backupSubscriptionManager = backupSubscriptionManager
51+ self . backupTestFlightEntitlementManager = backupTestFlightEntitlementManager
4952 self . db = db
5053 self . tsAccountManager = tsAccountManager
5154 }
@@ -106,74 +109,105 @@ class BackupEnablingManager {
106109 throw . genericError
107110 }
108111
109- func setBackupPlan( newBackupPlanBlock: ( BackupPlan ) -> BackupPlan ) async throws ( DisplayableError) {
110- do {
111- try await db. awaitableWriteWithRollbackIfThrows { tx in
112- let newBackupPlan = newBackupPlanBlock ( backupPlanManager. backupPlan ( tx: tx) )
113- try backupPlanManager. setBackupPlan ( newBackupPlan, tx: tx)
114- }
115- } catch {
116- owsFailDebug ( " Failed to set BackupPlan! \( error) " )
117- throw . genericError
118- }
119- }
120-
121112 switch planSelection {
122113 case . free:
123114 try await setBackupPlan { _ in . free }
124-
125115 case . paid:
126- let purchaseResult : BackupSubscription . PurchaseResult
116+ if FeatureFlags . Backups. avoidStoreKitForTesters {
117+ try await enablePaidPlanWithoutStoreKit ( )
118+ } else {
119+ try await enablePaidPlanWithStoreKit ( )
120+ }
121+ }
122+ }
123+
124+ // MARK: -
125+
126+ private func enablePaidPlanWithStoreKit( ) async throws ( DisplayableError) {
127+ let purchaseResult : BackupSubscription . PurchaseResult
128+ do {
129+ purchaseResult = try await backupSubscriptionManager. purchaseNewSubscription ( )
130+ } catch StoreKitError . networkError {
131+ throw . networkError
132+ } catch {
133+ owsFailDebug ( " StoreKit purchase unexpectedly failed: \( error) " )
134+ throw DisplayableError ( OWSLocalizedString (
135+ " CHOOSE_BACKUP_PLAN_CONFIRMATION_ERROR_PURCHASE " ,
136+ comment: " Message shown in an action sheet when the user tries to confirm selecting the paid plan, but encountered an error from Apple while purchasing. "
137+ ) )
138+ }
139+
140+ switch purchaseResult {
141+ case . success:
127142 do {
128- purchaseResult = try await backupSubscriptionManager. purchaseNewSubscription ( )
129- } catch StoreKitError . networkError {
130- throw . networkError
143+ try await self . backupSubscriptionManager. redeemSubscriptionIfNecessary ( )
131144 } catch {
132- owsFailDebug ( " StoreKit purchase unexpectedly failed: \( error) " )
145+ owsFailDebug ( " Unexpectedly failed to redeem subscription! \( error) " )
133146 throw DisplayableError ( OWSLocalizedString (
134- " CHOOSE_BACKUP_PLAN_CONFIRMATION_ERROR_PURCHASE " ,
135- comment: " Message shown in an action sheet when the user tries to confirm selecting the paid plan, but encountered an error from Apple while purchasing . "
147+ " CHOOSE_BACKUP_PLAN_CONFIRMATION_ERROR_PURCHASE_REDEMPTION " ,
148+ comment: " Message shown in an action sheet when the user tries to confirm selecting the paid plan, but encountered an error while redeeming their completed purchase . "
136149 ) )
137150 }
138151
139- switch purchaseResult {
140- case . success:
141- do {
142- try await self . backupSubscriptionManager. redeemSubscriptionIfNecessary ( )
143- } catch {
144- owsFailDebug ( " Unexpectedly failed to redeem subscription! \( error) " )
145- throw DisplayableError ( OWSLocalizedString (
146- " CHOOSE_BACKUP_PLAN_CONFIRMATION_ERROR_PURCHASE_REDEMPTION " ,
147- comment: " Message shown in an action sheet when the user tries to confirm selecting the paid plan, but encountered an error while redeeming their completed purchase. "
148- ) )
152+ try await setBackupPlan { currentBackupPlan in
153+ let currentOptimizeLocalStorage = switch currentBackupPlan {
154+ case . disabled, . disabling, . free:
155+ false
156+ case
157+ . paid( let optimizeLocalStorage) ,
158+ . paidExpiringSoon( let optimizeLocalStorage) ,
159+ . paidAsTester( let optimizeLocalStorage) :
160+ optimizeLocalStorage
149161 }
150162
151- try await setBackupPlan { currentBackupPlan in
152- let currentOptimizeLocalStorage = switch currentBackupPlan {
153- case . disabled, . disabling, . free:
154- false
155- case . paid( let optimizeLocalStorage) , . paidExpiringSoon( let optimizeLocalStorage) :
156- optimizeLocalStorage
157- }
163+ return . paid( optimizeLocalStorage: currentOptimizeLocalStorage)
164+ }
158165
159- return . paid( optimizeLocalStorage: currentOptimizeLocalStorage)
160- }
166+ case . pending:
167+ // The subscription won't be redeemed until if/when the purchase
168+ // is approved, but if/when that happens BackupPlan will get set
169+ // set to .paid. For the time being, we can enable Backups as
170+ // a free-tier user!
171+ try await setBackupPlan { _ in . free }
161172
162- case . pending :
163- // The subscription won 't be redeemed until if/when the purchase
164- // is approved, but if/when that happens BackupPlan will get set
165- // set to .paid. For the time being, we can enable Backups as
166- // a free-tier user!
167- try await setBackupPlan { _ in . free }
173+ case . userCancelled :
174+ // Do nothing – don 't even dismiss "choose plan", to give
175+ // the user the chance to try again. We've reserved a Backup
176+ // ID at this point, but that's fine even if they don't end
177+ // up enabling Backups at all.
178+ break
168179
169- case . userCancelled:
170- // Do nothing – don't even dismiss "choose plan", to give
171- // the user the chance to try again. We've reserved a Backup
172- // ID at this point, but that's fine even if they don't end
173- // up enabling Backups at all.
174- break
180+ }
181+ }
175182
183+ private func enablePaidPlanWithoutStoreKit( ) async throws ( DisplayableError) {
184+ do {
185+ try await backupTestFlightEntitlementManager. acquireEntitlement ( )
186+ } catch where error. isNetworkFailureOrTimeout {
187+ throw . networkError
188+ } catch {
189+ owsFailDebug ( " Unexpectedly failed to renew Backup entitlement for tester! \( error) " )
190+ throw . genericError
191+ }
192+
193+ try await setBackupPlan { _ in . paidAsTester( optimizeLocalStorage: false ) }
194+ }
195+
196+ // MARK: -
197+
198+ private func setBackupPlan(
199+ newBackupPlanBlock: ( _ currentBackupPlan: BackupPlan ) -> BackupPlan ,
200+ ) async throws ( DisplayableError) {
201+ do {
202+ try await db. awaitableWriteWithRollbackIfThrows { tx in
203+ let currentBackupPlan = backupPlanManager. backupPlan ( tx: tx)
204+ let newBackupPlan = newBackupPlanBlock ( currentBackupPlan)
205+
206+ try backupPlanManager. setBackupPlan ( newBackupPlan, tx: tx)
176207 }
208+ } catch {
209+ owsFailDebug ( " Failed to set BackupPlan! \( error) " )
210+ throw . genericError
177211 }
178212 }
179213}
0 commit comments