taler-ios

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

LoadingView.swift (5350B)


      1 /*
      2  * This file is part of GNU Taler, ©2022-25 Taler Systems S.A.
      3  * See LICENSE.md
      4  */
      5 /**
      6  * @author Marc Stibane
      7  */
      8 import SwiftUI
      9 import SymLog
     10 
     11 struct LoadingView: View {
     12     private let symLog = SymLogV(0)
     13     let stack: CallStack
     14     let scopeInfo: ScopeInfo?
     15     let message: String?
     16 
     17 //    let backButtonHidden: Bool
     18     let navTitle = String(localized: "Loading…")
     19 
     20     @EnvironmentObject private var controller: Controller
     21     @EnvironmentObject private var model: WalletModel
     22 
     23     @State private var rotationEnabled = true
     24     @State private var showAlert: Bool = false
     25     @State private var disabled: Bool = false
     26     @State private var isFinished: Bool? = false
     27 
     28     private var dismissButton: some View {
     29         Button("Cancel", role: .cancel) {
     30             showAlert = false
     31             if let lastError = controller.lastProgressError {
     32                 controller.lastProgressError = nil
     33                 Task {
     34                     try await model.cancelProgressToken(lastError.operation,
     35                                                  token: lastError.progressToken)
     36             }   }
     37         }
     38             .buttonStyle(TalerButtonStyle(type: .bordered, disabled: false))
     39             .padding(.horizontal)
     40     }
     41 
     42     @ViewBuilder
     43     func retryButton(disabled: Bool) -> some View {
     44         Button("Retry now") {
     45             withAnimation {
     46                 showAlert = false
     47             }
     48             if let lastError = controller.lastProgressError {
     49                 controller.lastProgressError = nil
     50                 Task {
     51                     try await model.retryProgressTokenNow(lastError.operation,
     52                                                    token: lastError.progressToken)
     53             }   }
     54         }
     55             .buttonStyle(TalerButtonStyle(type: .prominent, disabled: disabled))
     56             .padding(.horizontal)
     57     }
     58 
     59     var body: some View {
     60         let view = VStack(alignment: .center) {
     61             if showAlert {
     62                 let lastError = controller.lastProgressError
     63                 let fallback = String(localized: "It seems that there is a problem with the network.")
     64                 Text("Couldn't establish a connection")
     65                     .talerFont(.title2)
     66                     .padding(.vertical)
     67                 Text(lastError?.error.hint ?? fallback)
     68                     .talerFont(.body)
     69                 Spacer()
     70                 if let lastPhase = controller.lastProgressPhase {
     71                     if lastPhase.phase == .stalled {
     72                         if let lastError, let delay = lastError.nextRetryDelay {
     73                             if isFinished == false {
     74                                 TimeView("Next retry in:", seconds: Int(delay.toSeconds()), isFinished: $isFinished)
     75                                     .talerFont(.title3)
     76                                     .padding(.vertical)
     77                             } else if isFinished == true {
     78                                 Text("Retrying…")
     79                                     .talerFont(.title3)
     80                             } else {
     81                                 Text("Waiting for response…")
     82                                     .talerFont(.title3)
     83                             }
     84                         }
     85 //                        Spacer()
     86                         retryButton(disabled: isFinished ?? false)
     87                     }
     88                 }
     89             } else {
     90                 Spacer()
     91                 RotatingTaler(size: 100,
     92                           progress: true,                 // VoiceOver "In progress"
     93                               once: false,
     94                    rotationEnabled: $rotationEnabled)
     95                     .onTapGesture(count: 1) {
     96                         rotationEnabled.toggle()
     97                     }
     98                 Spacer()
     99                 if let scopeInfo {
    100                     if let urlStr = scopeInfo.url {
    101                         Text(urlStr.trimURL)
    102                             .talerFont(.title2)
    103                     } else {
    104                         Text(scopeInfo.currency)
    105                             .talerFont(.title2)
    106                     }
    107                     Spacer()
    108                 }
    109                 Text(message ?? EMPTYSTRING)
    110                     .talerFont(.title2)
    111                 Spacer()
    112             }
    113             dismissButton
    114         }
    115         .frame(maxWidth: .infinity)
    116         .talerFont(.title)
    117         .navigationTitle(navTitle)
    118         .background(FullBackground())
    119         .onChange(of: controller.stalledConnection) { isStalled in
    120             showAlert = isStalled
    121         }
    122         .onChange(of: controller.errorConnection) { isError in
    123             if isError {
    124 //                print("❗️❗️❗️ error arrived, idle waiting starts")
    125                 isFinished = false
    126                 controller.errorConnection = false
    127             }
    128         }
    129 
    130         if #available(iOS 17.0, *) {
    131             view.toolbarTitleDisplayMode(.inlineLarge)
    132         } else {
    133             view
    134         }
    135     }
    136 }
    137 // MARK: -
    138 struct LoadingView_Previews: PreviewProvider {
    139     static var previews: some View {
    140         NavigationView {
    141             LoadingView(stack: CallStack("Loading"), scopeInfo: nil, message: "test message")  // , backButtonHidden: true)
    142                 .navigationBarTitleDisplayMode(.automatic)
    143         }.navigationViewStyle(.stack)
    144     }
    145 }