BalancesListView.swift (5810B)
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 21 @EnvironmentObject private var model: WalletModel 22 @EnvironmentObject private var controller: Controller 23 @Environment(\.accessibilityVoiceOverEnabled) private var voiceOverEnabled 24 @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic 25 @AppStorage("demoHints") var demoHints: Bool = true 26 @AppStorage("preferredColorScheme") var preferredColorScheme: Int = 0 27 @AppStorage("oimEuro") var oimEuro: Bool = false 28 29 @State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING) // Update currency when used 30 @State private var summary = EMPTYSTRING 31 @State private var showRealCashHint = true 32 33 @State private var historyTapped: Int? = nil 34 @Namespace var namespace 35 36 private static func className() -> String {"\(self)"} 37 38 func refresh() async { 39 controller.hapticNotification(.success) 40 symLog.log("refreshing balances") 41 await controller.loadBalances(stack.push("refreshing balances"), model) 42 } 43 44 @ViewBuilder 45 func balancesList() -> some View { 46 let count = controller.balances.count 47 let list = List { 48 if !controller.haveProdBalance && !controller.defaultExchanges.isEmpty && demoHints { 49 ProdSectionView(stack: stack.push(), 50 showRealCashHint: $showRealCashHint, 51 isEmpty: false, 52 disabled: false) 53 } 54 ForEachWithIndex(array: controller.balances) { index, balance in 55 BalancesSectionView(stack: stack.push("\(balance.scopeInfo.currency)"), 56 balance: balance, // this is the currency to be used 57 selectedBalance: $selectedBalance, // set in TransactionsListView 58 balanceIndex: index, 59 sectionCount: count, 60 amountToTransfer: $amountToTransfer, // does still have the wrong currency 61 summary: $summary, 62 historyTapped: $historyTapped, 63 reloadTransactions: $reloadTransactions) 64 } 65 #if DEBUG || TALER_NIGHTLY 66 if count > 1 { // otherwise it comes before recentTransactions 67 DiscountPassesSection(stack: stack.push()) 68 } 69 #endif 70 } 71 .listStyle(myListStyle.style).anyView 72 .background(FullBackground()) 73 .onAppear() { 74 DebugViewC.shared.setViewID(VIEW_BALANCES, stack: stack.push("onAppear")) 75 if !controller.oimModeActive { 76 print("🚩BalancesListView.onAppear() reset selectedBalance") 77 // if count > 1 { 78 selectedBalance = nil // reset 79 // } 80 } 81 } 82 .refreshable { 83 await refresh() 84 } 85 .navigationTitle(title) 86 if voiceOverEnabled { 87 list 88 } else if #available(iOS 26.0, *) { 89 let list26 = list 90 .toolbar { 91 ToolbarItem(placement: .topBarTrailing) { //secondaryAction 92 SettingsButton26(sortPriority: 0) 93 } 94 } 95 #if OIM 96 if controller.oimModeActive || voiceOverEnabled { 97 list // hide SettingsButton (in Toolbar) 98 } else { 99 list26 100 } 101 #else 102 list26 103 #endif 104 } else { 105 list 106 } 107 } 108 109 var body: some View { 110 #if PRINT_CHANGES 111 let _ = Self._printChanges() 112 let _ = symLog.vlog() // just to get the # to compare it with .onAppear & onDisappear 113 #endif 114 /// In standard mode, selectedBalance just sets a "preference" which balance to pre-select for Actions. 115 /// However, the user can select another balance (with the picker) in each action 116 /// In OIM mode, the user selects a balance 'here' (in OIMView) when tapping on a savings box (representing the balance) 117 118 let list = balancesList() 119 .onChange(of: controller.oimModeActive) { oimModeActive in 120 if !oimModeActive { 121 print("🚩BalancesListView.onChange(of: oimModeActive) reset selectedBalance") 122 // if count > 1 { 123 selectedBalance = nil // reset 124 // } 125 } 126 } 127 ZStack { 128 if preferredColorScheme == 3, #available(iOS 17.0, *) { 129 list.scrollContentBackground(.hidden) 130 } else { 131 list 132 } 133 } 134 .overlay { if #available(iOS 16.4, *) { 135 if controller.oimModeActive { 136 #if OIM 137 OIMbalances(stack: stack.push(), 138 selectedBalance: $selectedBalance, // set to user choice 139 historyTapped: $historyTapped, 140 oimEuro: oimEuro) 141 .environmentObject(NamespaceWrapper(namespace)) // keep OIMviews apart 142 #endif // OIM 143 } 144 } } 145 } 146 }