BalancesListView.swift (5232B)
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("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 @ViewBuilder 42 func balancesList() -> some View { 43 let count = controller.balances.count 44 let list = List { 45 if !controller.haveProdBalance && !controller.defaultExchanges.isEmpty { 46 ProdSectionView(stack: stack.push(), isEmpty: false, disabled: false) 47 } 48 ForEachWithIndex(data: controller.balances) { index, balance in 49 BalancesSectionView(stack: stack.push("\(balance.scopeInfo.currency)"), 50 balance: balance, // this is the currency to be used 51 selectedBalance: $selectedBalance, // set in TransactionsListView 52 balanceIndex: index, 53 sectionCount: count, 54 amountToTransfer: $amountToTransfer, // does still have the wrong currency 55 summary: $summary, 56 historyTapped: $historyTapped, 57 reloadTransactions: $reloadTransactions) 58 } 59 #if DEBUG || TALER_NIGHTLY 60 if count > 1 { // otherwise it comes before recentTransactions 61 DiscountPassesSection(stack: stack.push()) 62 } 63 #endif 64 } 65 .listStyle(myListStyle.style).anyView 66 .background(FullBackground()) 67 .onAppear() { 68 DebugViewC.shared.setViewID(VIEW_BALANCES, stack: stack.push("onAppear")) 69 if !controller.oimModeActive { 70 print("🚩BalancesListView.onAppear() reset selectedBalance") 71 // if count > 1 { 72 selectedBalance = nil // reset 73 // } 74 } 75 } 76 .refreshable { 77 await refresh() 78 } 79 .navigationTitle(title) 80 if #available(iOS 26.0, *) { 81 let list26 = list 82 .toolbar { 83 ToolbarItem(placement: .topBarTrailing) { //secondaryAction 84 SettingsButton26(sortPriority: 0) 85 } 86 } 87 #if OIM 88 if controller.oimModeActive || voiceOverEnabled { 89 list // hide SettingsButton (in Toolbar) 90 } else { 91 list26 92 } 93 #else 94 list26 95 #endif 96 } else { 97 list 98 } 99 } 100 101 var body: some View { 102 #if PRINT_CHANGES 103 let _ = Self._printChanges() 104 let _ = symLog.vlog() // just to get the # to compare it with .onAppear & onDisappear 105 #endif 106 /// In standard mode, selectedBalance just sets a "preference" which balance to pre-select for Actions. 107 /// However, the user can select another balance (with the picker) in each action 108 /// In OIM mode, the user selects a balance 'here' (in OIMView) when tapping on a savings box (representing the balance) 109 110 balancesList() 111 .onChange(of: controller.oimModeActive) { oimModeActive in 112 if !oimModeActive { 113 print("🚩BalancesListView.onChange(of: oimModeActive) reset selectedBalance") 114 // if count > 1 { 115 selectedBalance = nil // reset 116 // } 117 } 118 } 119 .overlay { if #available(iOS 16.4, *) { 120 if controller.oimModeActive { 121 #if OIM 122 OIMbalances(stack: stack.push(), 123 selectedBalance: $selectedBalance, // set to user choice 124 historyTapped: $historyTapped, 125 oimEuro: oimEuro) 126 .environmentObject(NamespaceWrapper(namespace)) // keep OIMviews apart 127 #endif // OIM 128 } 129 } } 130 } 131 }