BalancesListView.swift (6026B)
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 taler_swift 10 import SymLog 11 import AVFoundation 12 13 /// This view shows the list of balances / currencies, each in its own section 14 struct BalancesListView: View { 15 private let symLog = SymLogV(0) 16 let stack: CallStack 17 let title: String 18 @Binding var selectedBalance: Balance? // set in TransactionsListView 19 @Binding var reloadTransactions: Int 20 @Binding var qrButtonTapped: Bool 21 22 @EnvironmentObject private var model: WalletModel 23 @EnvironmentObject private var controller: Controller 24 @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic 25 @AppStorage("oimEuro") var oimEuro: Bool = false 26 27 @State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING) // Update currency when used 28 @State private var summary = EMPTYSTRING 29 30 @State private var historyTapped: Int? = nil 31 @Namespace var namespace 32 33 private static func className() -> String {"\(self)"} 34 35 func refresh() async { 36 controller.hapticNotification(.success) 37 symLog.log("refreshing balances") 38 await controller.loadBalances(stack.push("refreshing balances"), model) 39 } 40 41 var body: some View { 42 #if PRINT_CHANGES 43 let _ = Self._printChanges() 44 let _ = symLog.vlog() // just to get the # to compare it with .onAppear & onDisappear 45 #endif 46 // Group { 47 if controller.balances.isEmpty { 48 let talerLogo = HStack(spacing: 2) { 49 Image(TALER_LOGO_FULL) 50 // .border(Color.gray, width: 1) 51 // Text("TALER Wallet") 52 Text("Wallet") 53 // .font(.logo(27, weight: .medium)) 54 .font(.logo("Atkinson Hyperlegible Next", size: 27, weight: .medium)) 55 .kerning(1.0) 56 } 57 .accessibilityElement(children: .combine) 58 .accessibilityAddTraits(.isHeader) 59 .accessibilityLabel(Text("Taler Wallet", comment: "a11y")) 60 61 WalletEmptyView(stack: stack.push("isEmpty")) 62 // .navigationTitle("Taler Wallet") 63 .toolbar { 64 ToolbarItem(placement: .principal) { 65 talerLogo 66 .padding(.top, 10) 67 } 68 } 69 .refreshable { 70 await refresh() 71 } 72 } else { 73 /// In standard mode, selectedBalance just sets a "preference" which balance to pre-select for Actions. 74 /// However, the user can select another balance (with the picker) in each action 75 /// In OIM mode, the user selects a balance 'here' (in OIMView) when tapping on a savings box (representing the balance) 76 let count = controller.balances.count 77 Group { 78 List { 79 if !controller.haveProdBalance && !controller.defaultExchanges.isEmpty { 80 ProdSectionView(stack: stack.push(), isEmpty: false, disabled: false) 81 } 82 ForEach(Array(controller.balances.enumerated()), id: \.element) { index, balance in 83 BalancesSectionView(stack: stack.push("\(balance.scopeInfo.currency)"), 84 balance: balance, // this is the currency to be used 85 selectedBalance: $selectedBalance, // set in TransactionsListView 86 balanceIndex: index, 87 sectionCount: count, 88 amountToTransfer: $amountToTransfer, // does still have the wrong currency 89 summary: $summary, 90 historyTapped: $historyTapped, 91 reloadTransactions: $reloadTransactions) 92 } 93 } 94 .onAppear() { 95 DebugViewC.shared.setViewID(VIEW_BALANCES, stack: stack.push("onAppear")) 96 if !controller.oimModeActive { 97 print("🚩BalancesListView.onAppear() reset selectedBalance") 98 // if count > 1 { 99 selectedBalance = nil // reset 100 // } 101 } 102 } 103 .listStyle(myListStyle.style).anyView 104 .refreshable { 105 await refresh() 106 } 107 }.navigationTitle(title) 108 .onChange(of: controller.oimModeActive) { oimModeActive in 109 if !oimModeActive { 110 print("🚩BalancesListView.onChange(of: oimModeActive) reset selectedBalance") 111 // if count > 1 { 112 selectedBalance = nil // reset 113 // } 114 } 115 } 116 #if OIM 117 .overlay { if #available(iOS 16.4, *) { 118 if controller.oimModeActive { 119 OIMbalances(stack: stack.push(), 120 selectedBalance: $selectedBalance, // set to user choice 121 qrButtonTapped: $qrButtonTapped, 122 historyTapped: $historyTapped, 123 oimEuro: oimEuro) 124 .environmentObject(NamespaceWrapper(namespace)) // keep OIMviews apart 125 } 126 } } 127 #endif 128 } // not empty 129 // } 130 } 131 }