taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

commit 014cd87bd7e2012ebb732145ebc0676f66c69b7c
parent d56caf945891c91d76f4f3385bdbb9fa55f666ef
Author: Marc Stibane <marc@taler.net>
Date:   Wed,  2 Sep 2026 14:40:34 +0200

progress for restore

Diffstat:
MTalerWallet1/Views/Main/MigrationView.swift | 16+++++++++-------
MTalerWallet1/Views/Settings/BackupView.swift | 95++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 84 insertions(+), 27 deletions(-)

diff --git a/TalerWallet1/Views/Main/MigrationView.swift b/TalerWallet1/Views/Main/MigrationView.swift @@ -38,7 +38,10 @@ struct MigrationView: View { Task { let result = try? await model.migrateDatabase() if let migrated = result?.migrated { - isFinished = migrated + withAnimation { + isFinished = migrated + self.progress = 1 + } } } } @@ -81,13 +84,15 @@ struct MigrationView: View { Text("Faking migration") .talerFont(.title) .task { - for x in 0...100 { + for x in 0...90 { await Task.sleep(20_000_000) self.progress = Double(x) / 100 } withAnimation { isFinished = true + self.progress = 1 } + controller.hapticFeedback(.medium) } } else { Text("Updating the database:") @@ -139,11 +144,8 @@ struct MigrationView: View { if let error = payload.error { self.error2 = WalletBackendError.walletCoreError(error) } else if let percent = payload.completionPercent { - progress = Double(percent) / 100 - if percent == 100 { - withAnimation { - isFinished = true - } + withAnimation { + progress = Double(percent) / 100 } } } diff --git a/TalerWallet1/Views/Settings/BackupView.swift b/TalerWallet1/Views/Settings/BackupView.swift @@ -24,16 +24,29 @@ struct BackupView: View { @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic @State private var created: Bool = false - @State private var restored: Bool = false @State private var backups: [String] = [] @State private var filename: String = EMPTYSTRING @State private var selectedBackup: String? = nil @State private var showRestoreAlert: Bool = false + @State private var progress: Double = 0 + @State private var isRestoring: Bool = false + @State private var isFinished: Bool = false + @State private var finishedMS: Int = 0 + @State private var isCancelled: Bool = false private func restoreBackup(_ path: String) { - restored = true Task { - try? await model.importDbFromFile(path: path) + do { + let sendTime = Date.now + try await model.importDbFromFile(path: path) + let timeUsed = Date.now - sendTime + self.finishedMS = timeUsed.milliseconds + withAnimation { + self.isFinished = true + self.progress = 1 + } + controller.hapticFeedback(.medium) + } catch {} } } @@ -45,6 +58,7 @@ struct BackupView: View { if let backupFile = try? await model.exportDbToFile(stem: stem, asJSON: asJSON) { filename = backupFile await viewDidLoad() + controller.hapticFeedback(.medium) } } } @@ -55,12 +69,17 @@ struct BackupView: View { withAnimation { selectedBackup = nil } } } - private var resetButton: some View { + private var restoreButton: some View { Button("Restore", role: .destructive) { // TODO: WalletColors().errorColor // didReset = true - if let selectedBackup, let docDirUrl = URL.docDirUrl { + if !isRestoring, + let selectedBackup, + let docDirUrl = URL.docDirUrl { showRestoreAlert = false + withAnimation { + self.isRestoring = true + } // symLog.log("❗️Restore \(selectedBackup)❗️") // if #available(iOS 16.0, *) { // backupPath = docDirUrl.appending(component: selectedBackup) @@ -74,6 +93,12 @@ struct BackupView: View { } } + func finishAction() { +// withAnimation { +// _ = dismissTop(stack.push()) +// } + } + @MainActor private func viewDidLoad() async { let fm = FileManager.default @@ -101,23 +126,41 @@ struct BackupView: View { let restoreHint2 = Text("To restore on a different iPhone, first install the Taler Wallet app there. Then connect it to your computer, and use the Files dialog to copy a previously saved backup into the Taler Wallet. Finally open the Backup/Restore dialog there, and select the backup you just copied.") let hasBackups = !backups.isEmpty + let busyRestore = isRestoring || isFinished || isCancelled List { - Section { - backupHint - .listRowSeparator(.hidden) - FeedbackButton(buttonTitle1, disabled: created) { createBackup(asJSON: true) } - .padding(.horizontal) - .listRowSeparator(.hidden) - FeedbackButton(buttonTitle2, disabled: created) { createBackup(asJSON: false) } - .padding(.horizontal) - .listRowSeparator(.hidden) - restoreHint - restoreHint2 + if !busyRestore { + Section { + backupHint + .listRowSeparator(.hidden) + FeedbackButton(buttonTitle1, disabled: created) { createBackup(asJSON: true) } + .padding(.horizontal) + .listRowSeparator(.hidden) + FeedbackButton(buttonTitle2, disabled: created) { createBackup(asJSON: false) } + .padding(.horizontal) + .listRowSeparator(.hidden) + restoreHint + restoreHint2 + } + .talerFont(.body) } - .talerFont(.body) - Section { - if hasBackups { + if busyRestore { + Text("Restoring the backup:") + .talerFont(.title) + ProgressView(value: progress) + if isFinished || isCancelled { + Text(isCancelled ? "Cancelled" : "Finished after \(finishedMS) ms.") + .talerFont(.title) + .task { + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + finishAction() + } + } + } else { + Text("Please don't close the app now, or we need to start over next time.") + .talerFont(.body) + } + } else if hasBackups { ForEach(backups, id: \.self) { file in let isSelected = file == selectedBackup HStack { @@ -137,6 +180,7 @@ struct BackupView: View { Text("No backups yet...") .talerFont(.body) } + } header: { Text("Available for restore:") .talerFont(.title3) @@ -153,10 +197,21 @@ struct BackupView: View { .alert("Overwrite Wallet", isPresented: $showRestoreAlert, actions: { dismissAlertButton - resetButton }, + restoreButton }, message: { Text("Are you sure you want to overwrite your wallet with this backup?\nThis cannot be reverted, all money which is now still in your wallet will be lost.") }) .onAppear() { DebugViewC.shared.setViewID(VIEW_BACKUP, stack: stack.push()) } + .onNotification(.DatabaseMaintenance) { notification in + if let payload = notification.userInfo?[NOTIFICATIONPAYLOAD] as? WalletCore.Payload { + if let error = payload.error { + model.setError(WalletBackendError.walletCoreError(error)) + } else if let percent = payload.completionPercent { + withAnimation { + progress = Double(percent) / 100 + } + } + } + } } // body }