taler-ios

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

TransactionsEmptyView.swift (6795B)


      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 /// This view shows hints if a wallet is empty
     12 /// It is the very first thing the user sees after installing the app
     13 
     14 struct TransactionsEmptyView: View {
     15     let stack: CallStack
     16     let currency: String
     17 
     18     @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
     19 
     20     var body: some View {
     21         List {
     22             Section {
     23                 Text("There are no transactions for \(currency).")
     24             }
     25             .talerFont(.title2)
     26         }
     27         .listStyle(myListStyle.style).anyView
     28         .background(FullBackground())
     29         .onAppear() {
     30             DebugViewC.shared.setViewID(VIEW_EMPTY_HISTORY, stack: stack.push())     // 20
     31         }
     32     }
     33 }
     34 
     35 // MARK: -
     36 struct UnconfirmedKeyChangeView: View {
     37     var baseURL: String
     38     var balance: Balance
     39     var isLegacy: Bool
     40 
     41     @Environment(\.dismiss) var dismiss     // pop back once
     42     @EnvironmentObject private var model: WalletModel
     43     @EnvironmentObject private var controller: Controller
     44     @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
     45 
     46     @State private var exchange: Exchange? = nil
     47     @State private var alertAccept: Bool = false
     48     @State private var alertDelete: Bool = false
     49 
     50     func notValid(_ amountString: String) -> String {
     51         String(localized: "Unfortunately this means, that your \(amountString) are not valid anymore, because they were obtained with the old security identity.")
     52     }
     53 
     54     func keep(_ amountString: String) -> String {
     55         String(localized: "Keep the \(amountString)")
     56     }
     57 
     58     func delete(_ amountString: String) -> String {
     59         String(localized: "Delete the \(amountString)")
     60     }
     61 
     62     func acceptAction() {
     63         if let exchange, let masterPub = exchange.masterPub {
     64             Task {
     65                 try? await model.confirmExchangeKeyChange(exchangeBaseUrl: baseURL,
     66                                                          currentMasterPub: masterPub)
     67                 dismiss()
     68             }
     69         } else {
     70             // TODO: Yikes!
     71         }
     72     }
     73 
     74     func deleteAction() {
     75         if let exchange, let masterPub = exchange.masterPub {
     76             Task {
     77                 try? await model.purgeExchangeLegacyKeys(exchangeBaseUrl: baseURL,
     78                                                         currentMasterPub: masterPub)
     79                 dismiss()
     80             }
     81         } else {
     82             // TODO: Yikes!
     83         }
     84     }
     85 
     86     func keepAction() {
     87         withAnimation {
     88             dismiss()
     89         }
     90     }
     91 
     92     private var acceptButton: some View {
     93         Button("Accept") {
     94             alertAccept = false
     95             acceptAction()
     96         }
     97     }
     98     private var deleteButton: some View {
     99         Button("Delete") {
    100             alertDelete = false
    101             deleteAction()
    102         }
    103     }
    104     private var dismissAlertButton: some View {
    105         Button("Cancel", role: .cancel) {
    106             alertAccept = false
    107             alertDelete = false
    108         }
    109     }
    110 
    111     @MainActor
    112     private func viewDidLoad() async {
    113         exchange = await controller.exchange(for: baseURL)
    114     }
    115 
    116     var body: some View {
    117         let scope = balance.scopeInfo
    118         let available = balance.available
    119         let formatted = available.formatted(scope, isNegative: false)
    120         let navTitle = String(localized: "Security Alert!", comment: "ViewTitle of UnconfirmedKeyChangeView")
    121         let warning1 = Text("Only trust the new identity if the payment service has confirmed this change.")
    122         let warning2 = Text("Otherwise, wait and try again later...")
    123         List {
    124             Section {
    125                 Text("The security identity of \(baseURL.trimURL) has changed unexpectedly.")
    126 
    127                 if isLegacy {
    128                     if !available.isZero {
    129                         let sorry = notValid(formatted.0)
    130                         let a11y = notValid(formatted.1)
    131                         Text(sorry)
    132                             .accessibilityLabel(a11y)
    133                         
    134                         warning1
    135                             .talerFont(.body)
    136                         warning2
    137                             .bold()
    138                             .talerFont(.body)
    139                         
    140                         Button(keep(formatted.0), action: keepAction)
    141                             .buttonStyle(TalerButtonStyle(type: .bordered))
    142                             .padding(.horizontal)
    143                             .accessibilityLabel(keep(formatted.1))
    144                         
    145                         Text("If you are sure that the old security identity will not be used anymore, you can delete the invalid money.")
    146                             .talerFont(.body)
    147                         Button(delete(formatted.0), action: { alertDelete = true })
    148                             .buttonStyle(TalerButtonStyle(type: .bordered))
    149                             .padding(.horizontal)
    150                             .accessibilityLabel(delete(formatted.1))
    151                     }
    152                 } else {
    153                     warning1
    154                     warning2
    155                         .bold()
    156                     Text("If you are sure that the old security identity will not be used anymore, you can withdraw new money with the new security identity.")
    157                     Button("Accept new security identity", action: { alertAccept = true })
    158                         .buttonStyle(TalerButtonStyle(type: .bordered))
    159                         .padding(.horizontal)
    160                     Text("Money you obtained with the old security identity will be invalid.")
    161                 }
    162             }
    163             .talerFont(.title2)
    164             .listRowSeparator(.hidden)
    165         }
    166         .listStyle(myListStyle.style).anyView
    167         .background(FullBackground())
    168         .navigationTitle(navTitle)
    169         .task {
    170             await viewDidLoad()
    171         }
    172         .alert("Accept the new payment service security identity.",
    173                isPresented: $alertAccept,
    174                actions: {   acceptButton
    175                             dismissAlertButton },
    176                message: {   Text("Are you sure? Your money obtained with the old security identity will be invalid.") })
    177         .alert("Delete money obtained with the old security identity.",
    178                isPresented: $alertDelete,
    179                actions: {   deleteButton
    180                             dismissAlertButton },
    181                message: {   Text("Are you sure? That money will be lost.") })
    182     }
    183 }
    184 // MARK: -
    185 struct TransactionsEmptyView_Previews: PreviewProvider {
    186     static var previews: some View {
    187         TransactionsEmptyView(stack: CallStack("Preview"), currency: LONGCURRENCY)
    188     }
    189 }