Skip to content

Commit 8480842

Browse files
Move viewModel state updates while loading BackupSubscription into VC
1 parent 33a8457 commit 8480842

File tree

1 file changed

+66
-72
lines changed

1 file changed

+66
-72
lines changed

Signal/Backups/BackupSettingsViewController.swift

Lines changed: 66 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import SignalUI
99
import StoreKit
1010
import SwiftUI
1111

12-
class BackupSettingsViewController: HostingController<BackupSettingsView> {
12+
class BackupSettingsViewController:
13+
HostingController<BackupSettingsView>,
14+
BackupSettingsViewModel.ActionsDelegate
15+
{
1316
enum OnLoadAction {
1417
case none
1518
case presentWelcomeToBackupsSheet
@@ -95,11 +98,11 @@ class BackupSettingsViewController: HostingController<BackupSettingsView> {
9598
self.onLoadAction = onLoadAction
9699
self.viewModel = db.read { tx in
97100
let viewModel = BackupSettingsViewModel(
98-
backupSubscriptionLoadingState: .loading, // Default, loaded after init
101+
backupSubscriptionLoadingState: .loading, // Default, loaded async
99102
backupPlan: backupPlanManager.backupPlan(tx: tx),
100103
failedToDisableBackupsRemotely: backupDisablingManager.disableRemotelyFailed(tx: tx),
101-
latestBackupAttachmentDownloadUpdate: nil, // Default, loaded after init
102-
latestBackupAttachmentUploadUpdate: nil, // Default, loaded after init
104+
latestBackupAttachmentDownloadUpdate: nil, // Default, loaded async
105+
latestBackupAttachmentUploadUpdate: nil, // Default, loaded async
103106
lastBackupDate: backupSettingsStore.lastBackupDate(tx: tx),
104107
lastBackupSizeBytes: backupSettingsStore.lastBackupSizeBytes(tx: tx),
105108
shouldAllowBackupUploadsOnCellular: backupSettingsStore.shouldAllowBackupUploadsOnCellular(tx: tx)
@@ -117,8 +120,8 @@ class BackupSettingsViewController: HostingController<BackupSettingsView> {
117120
OWSTableViewController2.removeBackButtonText(viewController: self)
118121

119122
viewModel.actionsDelegate = self
120-
// Run as soon as we've set the actionDelegate.
121-
viewModel.loadBackupSubscription()
123+
124+
loadBackupSubscription()
122125

123126
eventObservationTasks = [
124127
Task { [weak self, backupAttachmentDownloadTracker] in
@@ -176,13 +179,11 @@ class BackupSettingsViewController: HostingController<BackupSettingsView> {
176179
break
177180
}
178181

179-
viewModel.loadBackupSubscription()
182+
loadBackupSubscription()
180183
}
181-
}
182184

183-
// MARK: - BackupSettingsViewModel.ActionsDelegate
185+
// MARK: - BackupSettingsViewModel.ActionsDelegate
184186

185-
extension BackupSettingsViewController: BackupSettingsViewModel.ActionsDelegate {
186187
fileprivate func enableBackups(
187188
implicitPlanSelection: ChooseBackupPlanViewController.PlanSelection?
188189
) {
@@ -379,7 +380,31 @@ extension BackupSettingsViewController: BackupSettingsViewModel.ActionsDelegate
379380

380381
// MARK: -
381382

382-
fileprivate func loadBackupSubscription() async throws -> BackupSettingsViewModel.BackupSubscriptionLoadingState.LoadedBackupSubscription {
383+
private lazy var loadBackupSubscriptionQueue = SerialTaskQueue()
384+
385+
fileprivate func loadBackupSubscription() {
386+
loadBackupSubscriptionQueue.enqueue { @MainActor [self] in
387+
withAnimation {
388+
viewModel.backupSubscriptionLoadingState = .loading
389+
}
390+
391+
let newLoadingState: BackupSettingsViewModel.BackupSubscriptionLoadingState
392+
do {
393+
let backupSubscription = try await _loadBackupSubscription()
394+
newLoadingState = .loaded(backupSubscription)
395+
} catch let error where error.isNetworkFailureOrTimeout {
396+
newLoadingState = .networkError
397+
} catch {
398+
newLoadingState = .genericError
399+
}
400+
401+
withAnimation {
402+
viewModel.backupSubscriptionLoadingState = newLoadingState
403+
}
404+
}
405+
}
406+
407+
private func _loadBackupSubscription() async throws -> BackupSettingsViewModel.BackupSubscriptionLoadingState.LoadedBackupSubscription {
383408
var currentBackupPlan = db.read { backupPlanManager.backupPlan(tx: $0) }
384409

385410
switch currentBackupPlan {
@@ -447,7 +472,7 @@ extension BackupSettingsViewController: BackupSettingsViewModel.ActionsDelegate
447472

448473
// Reload the BackupPlan, since our subscription may now be in a
449474
// different state (e.g., set to not renew).
450-
viewModel.loadBackupSubscription()
475+
loadBackupSubscription()
451476
}
452477
}
453478

@@ -723,7 +748,7 @@ private class BackupSettingsViewModel: ObservableObject {
723748

724749
func disableBackups()
725750

726-
func loadBackupSubscription() async throws -> BackupSubscriptionLoadingState.LoadedBackupSubscription
751+
func loadBackupSubscription()
727752
func upgradeFromFreeToPaidPlan()
728753
func manageOrCancelPaidPlan()
729754
func managePaidPlanAsTester()
@@ -767,8 +792,6 @@ private class BackupSettingsViewModel: ObservableObject {
767792

768793
weak var actionsDelegate: ActionsDelegate?
769794

770-
private let loadBackupSubscriptionQueue: SerialTaskQueue
771-
772795
init(
773796
backupSubscriptionLoadingState: BackupSubscriptionLoadingState,
774797
backupPlan: BackupPlan,
@@ -789,8 +812,6 @@ private class BackupSettingsViewModel: ObservableObject {
789812
self.lastBackupDate = lastBackupDate
790813
self.lastBackupSizeBytes = lastBackupSizeBytes
791814
self.shouldAllowBackupUploadsOnCellular = shouldAllowBackupUploadsOnCellular
792-
793-
self.loadBackupSubscriptionQueue = SerialTaskQueue()
794815
}
795816

796817
// MARK: -
@@ -814,28 +835,10 @@ private class BackupSettingsViewModel: ObservableObject {
814835
}
815836
}
816837

817-
func loadBackupSubscription() {
818-
guard let actionsDelegate else { return }
819-
820-
loadBackupSubscriptionQueue.enqueue { @MainActor [self, actionsDelegate] in
821-
withAnimation {
822-
backupSubscriptionLoadingState = .loading
823-
}
824-
825-
let newLoadingState: BackupSubscriptionLoadingState
826-
do {
827-
let backupSubscription = try await actionsDelegate.loadBackupSubscription()
828-
newLoadingState = .loaded(backupSubscription)
829-
} catch let error where error.isNetworkFailureOrTimeout {
830-
newLoadingState = .networkError
831-
} catch {
832-
newLoadingState = .genericError
833-
}
838+
// MARK: -
834839

835-
withAnimation {
836-
backupSubscriptionLoadingState = newLoadingState
837-
}
838-
}
840+
func loadBackupSubscription() {
841+
actionsDelegate?.loadBackupSubscription()
839842
}
840843

841844
func upgradeFromFreeToPaidPlan() {
@@ -1678,21 +1681,13 @@ private extension BackupSettingsViewModel {
16781681
failedToDisableBackupsRemotely: Bool = false,
16791682
latestBackupAttachmentDownloadUpdateState: BackupSettingsAttachmentDownloadTracker.DownloadUpdate.State? = nil,
16801683
latestBackupAttachmentUploadUpdateState: BackupSettingsAttachmentUploadTracker.UploadUpdate.State? = nil,
1681-
backupPlanLoadResult: Result<BackupSubscriptionLoadingState.LoadedBackupSubscription, Error>,
1684+
backupSubscriptionLoadingState: BackupSubscriptionLoadingState,
16821685
) -> BackupSettingsViewModel {
16831686
class PreviewActionsDelegate: ActionsDelegate {
1684-
private let backupPlanLoadResult: Result<BackupSubscriptionLoadingState.LoadedBackupSubscription, Error>
1685-
init(backupPlanLoadResult: Result<BackupSubscriptionLoadingState.LoadedBackupSubscription, Error>) {
1686-
self.backupPlanLoadResult = backupPlanLoadResult
1687-
}
1688-
16891687
func enableBackups(implicitPlanSelection: ChooseBackupPlanViewController.PlanSelection?) { print("Enabling! implicitPlanSelection: \(implicitPlanSelection as Any)") }
16901688
func disableBackups() { print("Disabling!") }
16911689

1692-
func loadBackupSubscription() async throws -> BackupSettingsViewModel.BackupSubscriptionLoadingState.LoadedBackupSubscription {
1693-
try! await Task.sleep(nanoseconds: 2.clampedNanoseconds)
1694-
return try backupPlanLoadResult.get()
1695-
}
1690+
func loadBackupSubscription() { print("Loading BackupSubscription!") }
16961691
func upgradeFromFreeToPaidPlan() { print("Upgrading!") }
16971692
func manageOrCancelPaidPlan() { print("Managing or canceling!") }
16981693
func managePaidPlanAsTester() { print("Managing as tester!") }
@@ -1709,7 +1704,7 @@ private extension BackupSettingsViewModel {
17091704
}
17101705

17111706
let viewModel = BackupSettingsViewModel(
1712-
backupSubscriptionLoadingState: .loading,
1707+
backupSubscriptionLoadingState: backupSubscriptionLoadingState,
17131708
backupPlan: backupPlan,
17141709
failedToDisableBackupsRemotely: failedToDisableBackupsRemotely,
17151710
latestBackupAttachmentDownloadUpdate: latestBackupAttachmentDownloadUpdateState.map {
@@ -1730,43 +1725,42 @@ private extension BackupSettingsViewModel {
17301725
lastBackupSizeBytes: 2_400_000_000,
17311726
shouldAllowBackupUploadsOnCellular: false
17321727
)
1733-
let actionsDelegate = PreviewActionsDelegate(backupPlanLoadResult: backupPlanLoadResult)
1728+
let actionsDelegate = PreviewActionsDelegate()
17341729
viewModel.actionsDelegate = actionsDelegate
17351730
ObjectRetainer.retainObject(actionsDelegate, forLifetimeOf: viewModel)
17361731

1737-
viewModel.loadBackupSubscription()
17381732
return viewModel
17391733
}
17401734
}
17411735

17421736
#Preview("Plan: Paid") {
17431737
BackupSettingsView(viewModel: .forPreview(
17441738
backupPlan: .paid(optimizeLocalStorage: false),
1745-
backupPlanLoadResult: .success(.paid(
1739+
backupSubscriptionLoadingState: .loaded(.paid(
17461740
price: FiatMoney(currencyCode: "USD", value: 1.99),
17471741
renewalDate: Date().addingTimeInterval(.week)
1748-
))
1742+
)),
17491743
))
17501744
}
17511745

17521746
#Preview("Plan: Free") {
17531747
BackupSettingsView(viewModel: .forPreview(
17541748
backupPlan: .free,
1755-
backupPlanLoadResult: .success(.free)
1749+
backupSubscriptionLoadingState: .loaded(.free)
17561750
))
17571751
}
17581752

17591753
#Preview("Plan: Free For Testers") {
17601754
BackupSettingsView(viewModel: .forPreview(
17611755
backupPlan: .paidAsTester(optimizeLocalStorage: false),
1762-
backupPlanLoadResult: .success(.paidButFreeForTesters)
1756+
backupSubscriptionLoadingState: .loaded(.paidButFreeForTesters)
17631757
))
17641758
}
17651759

17661760
#Preview("Plan: Expiring") {
17671761
BackupSettingsView(viewModel: .forPreview(
17681762
backupPlan: .paidExpiringSoon(optimizeLocalStorage: false),
1769-
backupPlanLoadResult: .success(.paidButExpiring(
1763+
backupSubscriptionLoadingState: .loaded(.paidButExpiring(
17701764
expirationDate: Date().addingTimeInterval(.week)
17711765
))
17721766
))
@@ -1775,7 +1769,7 @@ private extension BackupSettingsViewModel {
17751769
#Preview("Plan: Expired") {
17761770
BackupSettingsView(viewModel: .forPreview(
17771771
backupPlan: .paidExpiringSoon(optimizeLocalStorage: false),
1778-
backupPlanLoadResult: .success(.paidButExpired(
1772+
backupSubscriptionLoadingState: .loaded(.paidButExpired(
17791773
expirationDate: Date().addingTimeInterval(-1 * .week)
17801774
))
17811775
))
@@ -1784,22 +1778,22 @@ private extension BackupSettingsViewModel {
17841778
#Preview("Plan: Network Error") {
17851779
BackupSettingsView(viewModel: .forPreview(
17861780
backupPlan: .paid(optimizeLocalStorage: false),
1787-
backupPlanLoadResult: .failure(OWSHTTPError.networkFailure(.genericTimeout))
1781+
backupSubscriptionLoadingState: .networkError
17881782
))
17891783
}
17901784

17911785
#Preview("Plan: Generic Error") {
17921786
BackupSettingsView(viewModel: .forPreview(
17931787
backupPlan: .paid(optimizeLocalStorage: false),
1794-
backupPlanLoadResult: .failure(OWSGenericError(""))
1788+
backupSubscriptionLoadingState: .genericError
17951789
))
17961790
}
17971791

17981792
#Preview("Downloads: Suspended") {
17991793
BackupSettingsView(viewModel: .forPreview(
18001794
backupPlan: .paid(optimizeLocalStorage: false),
18011795
latestBackupAttachmentDownloadUpdateState: .suspended,
1802-
backupPlanLoadResult: .success(.paid(
1796+
backupSubscriptionLoadingState: .loaded(.paid(
18031797
price: FiatMoney(currencyCode: "USD", value: 1.99),
18041798
renewalDate: Date().addingTimeInterval(.week)
18051799
))
@@ -1810,93 +1804,93 @@ private extension BackupSettingsViewModel {
18101804
BackupSettingsView(viewModel: .forPreview(
18111805
backupPlan: .free,
18121806
latestBackupAttachmentDownloadUpdateState: .suspended,
1813-
backupPlanLoadResult: .success(.free)
1807+
backupSubscriptionLoadingState: .loaded(.free)
18141808
))
18151809
}
18161810

18171811
#Preview("Downloads: Running") {
18181812
BackupSettingsView(viewModel: .forPreview(
18191813
backupPlan: .free,
18201814
latestBackupAttachmentDownloadUpdateState: .running,
1821-
backupPlanLoadResult: .success(.free)
1815+
backupSubscriptionLoadingState: .loaded(.free)
18221816
))
18231817
}
18241818

18251819
#Preview("Downloads: Paused (Battery)") {
18261820
BackupSettingsView(viewModel: .forPreview(
18271821
backupPlan: .free,
18281822
latestBackupAttachmentDownloadUpdateState: .pausedLowBattery,
1829-
backupPlanLoadResult: .success(.free)
1823+
backupSubscriptionLoadingState: .loaded(.free)
18301824
))
18311825
}
18321826

18331827
#Preview("Downloads: Paused (WiFi)") {
18341828
BackupSettingsView(viewModel: .forPreview(
18351829
backupPlan: .free,
18361830
latestBackupAttachmentDownloadUpdateState: .pausedNeedsWifi,
1837-
backupPlanLoadResult: .success(.free)
1831+
backupSubscriptionLoadingState: .loaded(.free)
18381832
))
18391833
}
18401834

18411835
#Preview("Downloads: Paused (Internet)") {
18421836
BackupSettingsView(viewModel: .forPreview(
18431837
backupPlan: .free,
18441838
latestBackupAttachmentDownloadUpdateState: .pausedNeedsInternet,
1845-
backupPlanLoadResult: .success(.free)
1839+
backupSubscriptionLoadingState: .loaded(.free)
18461840
))
18471841
}
18481842

18491843
#Preview("Downloads: Disk Space Error") {
18501844
BackupSettingsView(viewModel: .forPreview(
18511845
backupPlan: .free,
18521846
latestBackupAttachmentDownloadUpdateState: .outOfDiskSpace(bytesRequired: 200_000_000),
1853-
backupPlanLoadResult: .success(.free)
1847+
backupSubscriptionLoadingState: .loaded(.free)
18541848
))
18551849
}
18561850

18571851
#Preview("Uploads: Running") {
18581852
BackupSettingsView(viewModel: .forPreview(
18591853
backupPlan: .free,
18601854
latestBackupAttachmentUploadUpdateState: .running,
1861-
backupPlanLoadResult: .success(.free)
1855+
backupSubscriptionLoadingState: .loaded(.free)
18621856
))
18631857
}
18641858

18651859
#Preview("Uploads: Paused (WiFi)") {
18661860
BackupSettingsView(viewModel: .forPreview(
18671861
backupPlan: .free,
18681862
latestBackupAttachmentUploadUpdateState: .pausedNeedsWifi,
1869-
backupPlanLoadResult: .success(.free)
1863+
backupSubscriptionLoadingState: .loaded(.free)
18701864
))
18711865
}
18721866

18731867
#Preview("Uploads: Paused (Battery)") {
18741868
BackupSettingsView(viewModel: .forPreview(
18751869
backupPlan: .free,
18761870
latestBackupAttachmentUploadUpdateState: .pausedLowBattery,
1877-
backupPlanLoadResult: .success(.free)
1871+
backupSubscriptionLoadingState: .loaded(.free)
18781872
))
18791873
}
18801874

18811875
#Preview("Disabling: Success") {
18821876
BackupSettingsView(viewModel: .forPreview(
18831877
backupPlan: .disabled,
1884-
backupPlanLoadResult: .success(.free),
1878+
backupSubscriptionLoadingState: .loaded(.free),
18851879
))
18861880
}
18871881

18881882
#Preview("Disabling: Remotely") {
18891883
BackupSettingsView(viewModel: .forPreview(
18901884
backupPlan: .disabling,
1891-
backupPlanLoadResult: .success(.free),
1885+
backupSubscriptionLoadingState: .loaded(.free),
18921886
))
18931887
}
18941888

18951889
#Preview("Disabling: Remotely Failed") {
18961890
BackupSettingsView(viewModel: .forPreview(
18971891
backupPlan: .disabled,
18981892
failedToDisableBackupsRemotely: true,
1899-
backupPlanLoadResult: .success(.free),
1893+
backupSubscriptionLoadingState: .loaded(.free),
19001894
))
19011895
}
19021896

0 commit comments

Comments
 (0)