taler-ios

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

MigrationView.swift (6677B)


      1 /*
      2  * This file is part of GNU Taler, ©2022-26 Taler Systems S.A.
      3  * See LICENSE.md
      4  */
      5 /**
      6  * @author Marc Stibane
      7  */
      8 import SwiftUI
      9 import SymLog
     10 import taler_swift
     11 
     12 struct MigrationView: View {
     13 
     14     @Environment(\.colorScheme) private var colorScheme
     15     @Environment(\.colorSchemeContrast) private var colorSchemeContrast
     16     @EnvironmentObject private var controller: Controller
     17     @EnvironmentObject private var model: WalletModel
     18 #if DEBUG
     19     @AppStorage("developerMode") var developerMode: Bool = true
     20 #else
     21     @AppStorage("developerMode") var developerMode: Bool = false
     22 #endif
     23     @AppStorage("preferredColorScheme") var preferredColorScheme: Int = 0
     24     @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
     25 
     26     @State private var isMigrating: Bool = false
     27     @State private var fakeMigration: Bool = false
     28     @State private var isFinished: Bool = false
     29     @State private var isCancelled: Bool = false
     30     @State private var progress: Double = 0
     31     @State private var error2: Error? = nil
     32 
     33     func buttonAction() {
     34         if !isMigrating {
     35             withAnimation {
     36                 self.isMigrating = true
     37             }
     38             Task {
     39                 let result = try? await model.migrateDatabase()
     40                 if let migrated = result?.migrated {
     41                     withAnimation {
     42                         isFinished = migrated
     43                         self.progress = 1
     44                     }
     45                 }
     46             }
     47         }
     48     }
     49 
     50     func fakeAction() {
     51         if !isMigrating {
     52             fakeMigration = true
     53             withAnimation {
     54                 self.isMigrating = true
     55             }
     56         }
     57     }
     58 
     59     // Too much hassle for wallet-core to check this everywhere
     60 //    func cancelAction() {
     61 //        self.isMigrating = false
     62 //        self.isCancelled = true
     63 //        if let operation = controller.progressOperation,
     64 //           let token = controller.progressToken {
     65 //            Task {
     66 //                try? await model.cancelProgressToken(operation, token: token)
     67 //                controller.progressOperation = nil
     68 //                controller.progressToken = nil
     69 //            }
     70 //        }
     71 //    }
     72 
     73     func finishAction() {
     74         withAnimation {
     75             controller.backendState = .ready
     76         }
     77     }
     78 
     79     var body: some View {
     80         let list = List {
     81             Section(header: Text("Update database")) {
     82                 if isMigrating || isFinished || isCancelled {
     83                     if fakeMigration {
     84                         Text("Faking migration")
     85                             .talerFont(.title)
     86                             .task {
     87                                 for x in 0...90 {
     88                                     await Task.sleep(20_000_000)
     89                                     self.progress = Double(x) / 100
     90                                 }
     91                                 withAnimation {
     92                                     isFinished = true
     93                                     self.progress = 1
     94                                 }
     95                                 controller.hapticFeedback(.medium)
     96                             }
     97                     } else {
     98                         Text("Updating the database:")
     99                             .talerFont(.title)
    100                     }
    101                     ProgressView(value: progress)
    102 //                    Button("Cancel", action: cancelAction)
    103 //                        .buttonStyle(TalerButtonStyle(type: .bordered))
    104 //                        .padding()
    105                     if isFinished || isCancelled {
    106                         Text(isCancelled ? "Cancelled" : "Finished")
    107                             .talerFont(.title)
    108                             .task {
    109                                 DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    110                                     finishAction()
    111                                 }
    112                             }
    113                     } else {
    114                         Text("Please don't close the app now, or we need to start over next time.")
    115                             .talerFont(.body)
    116                     }
    117                 } else {
    118                     Text("The \(controller.localizedAppName) database needs to be updated.")
    119                         .talerFont(.title)
    120                     Text("This might take from a few seconds to a minute or two, depending on how many transactions you made.")
    121                         .talerFont(.body)
    122 
    123                     Button("Update now", action: buttonAction)
    124                         .buttonStyle(TalerButtonStyle(type: .bordered, disabled: isMigrating))
    125                         .disabled(isMigrating)
    126                         .padding()
    127                     if developerMode {
    128                         Button("Fake update", action: fakeAction)
    129                             .buttonStyle(TalerButtonStyle(type: .bordered, disabled: isMigrating))
    130                             .disabled(isMigrating)
    131                             .padding()
    132                     }
    133                     Button("Update later", action: finishAction)
    134                         .buttonStyle(TalerButtonStyle(type: .bordered))
    135                         .padding()
    136                 }
    137             }
    138             .listRowSeparator(.hidden)
    139         }.id("list")
    140         .listStyle(myListStyle.style).anyView
    141         .talerFont(.title2)
    142         .onNotification(.DatabaseMaintenance) { notification in
    143             if let payload = notification.userInfo?[NOTIFICATIONPAYLOAD] as? WalletCore.Payload {
    144                 if let error = payload.error {
    145                     self.error2 = WalletBackendError.walletCoreError(error)
    146                 } else if let percent = payload.completionPercent {
    147                     withAnimation {
    148                         progress = Double(percent) / 100
    149                     }
    150                 }
    151             }
    152         }
    153         let stack = ZStack {
    154             if preferredColorScheme == 3, #available(iOS 17.0, *) {
    155                 list.scrollContentBackground(.hidden)
    156             } else {
    157                 list
    158             }
    159             if let error2 {
    160                 ErrorView(nil, error: error2, devMode: developerMode) {
    161                     self.error2 = nil
    162                 }.interactiveDismissDisabled()
    163             }
    164         }.id("stack")
    165         NavigationView {
    166             ZStack {
    167                 WalletHeader(showSettings: false, content: stack)
    168             }.frame(maxWidth: .infinity, maxHeight: .infinity)
    169                 .background(FullBackground())
    170         }.navigationViewStyle(.stack)
    171     }
    172 }
    173 // MARK: -
    174 struct MigrationView_Previews: PreviewProvider {
    175     static var previews: some View {
    176         MigrationView()
    177     }
    178 }