DebugSettingsView.swift (14146B)
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 LocalConsole 12 13 struct DebugSettingsView: View { 14 private let symLog = SymLogV(0) 15 let stack: CallStack 16 let navTitle: String 17 18 @EnvironmentObject private var controller: Controller 19 @EnvironmentObject private var model: WalletModel 20 // @Environment(\.colorSchemeContrast) private var colorSchemeContrast 21 #if DEBUG 22 @AppStorage("developerMode") var developerMode: Bool = true 23 #else 24 @AppStorage("developerMode") var developerMode: Bool = false 25 #endif 26 @AppStorage("logTransactions") var logTransactions: Bool = false 27 @AppStorage("useHaptics") var useHaptics: Bool = true 28 @AppStorage("developDelay") var developDelay: Bool = false 29 @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic 30 @AppStorage("minimalistic") var minimalistic: Bool = false 31 @AppStorage("localConsoleL") var localConsoleL: Bool = false // for Logs 32 @AppStorage("localConsoleO") var localConsoleO: Int = 0 // for Observability 33 34 @State private var checkDisabled = false 35 @State private var withDrawDisabled = false 36 @State private var showDevelopItems = false 37 @State private var showResetAlert: Bool = false 38 @State private var didReset: Bool = false 39 40 private var dismissAlertButton: some View { 41 Button("Cancel", role: .cancel) { 42 showResetAlert = false 43 } 44 } 45 private var resetButton: some View { 46 Button("Reset", role: .destructive) { // TODO: WalletColors().errorColor 47 didReset = true 48 showResetAlert = false 49 Task { // runs on MainActor 50 symLog.log("❗️Reset wallet-core❗️") 51 try? await model.resetWalletCore() 52 } 53 } 54 } 55 @State private var listID = UUID() 56 57 var body: some View { 58 #if PRINT_CHANGES 59 let _ = Self._printChanges() 60 let _ = symLog.vlog() // just to get the # to compare it with .onAppear & onDisappear 61 #endif 62 let walletCore = WalletCore.shared 63 Group { 64 List { 65 SettingsToggle(name: String("Developer Mode"), value: $developerMode, 66 id1: "devMode", 67 description: String("More information intended for debugging")) { newVal in 68 withAnimation(Animation.linear.delay(0.8)) { showDevelopItems = developerMode } 69 } 70 if showDevelopItems { 71 #if DEBUG 72 SettingsToggle(name: String("Log Transactions"), value: $logTransactions.onChange({ isLogging in 73 walletCore.logTransactions = isLogging}), 74 id1: "logTransactions", 75 description: String("full log with all tx")) 76 #endif 77 let localConsStr = String("on LocalConsole") 78 let observability = String("Observe walletCore") 79 SettingsTriState(name: observability, value: $localConsoleO.onChange({ isObserving in 80 walletCore.isObserving = isObserving}), 81 id1: "observe", 82 description: localConsStr) { isObserving in 83 let consoleManager = LCManager.shared 84 consoleManager.isVisible = localConsoleO != 0 || localConsoleL 85 consoleManager.clear() 86 } 87 let showLogs = String("Show logs") 88 SettingsToggle(name: showLogs, value: $localConsoleL.onChange({ isLogging in 89 walletCore.isLogging = isLogging}), 90 id1: "localConsoleL", 91 description: localConsStr) { _ in 92 let consoleManager = LCManager.shared 93 consoleManager.isVisible = localConsoleO != 0 || localConsoleL 94 consoleManager.clear() 95 } 96 #if DEBUG 97 let banks = ["glstest.taler.net", "taler.fdold.eu", "regio-taler.fdold.eu", 98 "taler.grothoff.org", "taler.ar", 99 "head.taler.net", "test.taler.net", "demo.taler.net", "kyctest.taler.net"] 100 ForEach(banks, id: \.self) { bank in 101 let urlStr = "https://bank." + bank 102 Link(bank, destination: URL(string: urlStr)!) 103 } 104 #endif 105 } // showDevelopItems 106 SettingsItem(name: String("DEMO"), id1: "demo1with", 107 description: String("Get money for testing")) { 108 let title = "Withdraw" 109 Button(title) { 110 withDrawDisabled = true // don't run twice 111 Task { // runs on MainActor 112 symLog.log("Withdraw DEMO KUDOS") 113 let amount = Amount(currency: DEMOCURRENCY, cent: 11100) 114 try? await model.loadTestKudos(0, amount: amount) 115 } 116 } 117 .buttonStyle(.bordered) 118 .disabled(withDrawDisabled) 119 }.id("demo1withdraw") 120 SettingsItem(name: String("TEST"), id1: "test1with", 121 description: String("Get money for testing")) { 122 let title = "Withdraw" 123 Button(title) { 124 withDrawDisabled = true // don't run twice 125 Task { // runs on MainActor 126 symLog.log("Withdraw TESTKUDOS") 127 let cent = UInt64.random(in: 110...195) * 100 128 let amount = Amount(currency: TESTCURRENCY, cent: cent) 129 try? await model.loadTestKudos(1, amount: amount) 130 } 131 } 132 .buttonStyle(.bordered) 133 .disabled(withDrawDisabled) 134 }.id("test1withdraw") 135 if showDevelopItems { 136 SettingsItem(name: String("HEAD"), id1: "head1with", 137 description: String("Get money for testing")) { 138 let title = "Withdraw" 139 Button(title) { 140 withDrawDisabled = true // don't run twice 141 Task { // runs on MainActor 142 symLog.log("Withdraw HEAD KUDOS") 143 let amount = Amount(currency: DEMOCURRENCY, cent: 1100) 144 try? await model.loadTestKudos(2, amount: amount) 145 } 146 } 147 .buttonStyle(.bordered) 148 .disabled(withDrawDisabled) 149 }.id("head1withdraw") 150 SettingsToggle(name: String("Set 2 seconds delay"), 151 value: $developDelay.onChange({ delay in 152 walletCore.developDelay = delay}), 153 id1: "delay", 154 description: String("After each wallet-core action")) 155 .id("delay") 156 #if DEBUG 157 SettingsItem(name: String("Run Dev Experiment Refresh"), 158 id1: "applyDevExperiment", 159 description: "dev-experiment/insert-pending-refresh") { 160 let title = "Refresh" 161 Button(title) { 162 Task { // runs on MainActor 163 symLog.log("running applyDevExperiment Refresh") 164 try? await model.setConfig(setTesting: true) 165 try? await model.devExperimentT(talerUri: "taler://dev-experiment/start-block-refresh") 166 try? await model.devExperimentT(talerUri: "taler://dev-experiment/insert-pending-refresh") 167 } 168 } 169 .buttonStyle(.bordered) 170 }.id("Refresh") 171 #endif 172 SettingsItem(name: String("Run Integration Test"), 173 id1: "demo1test", 174 description: String("Perform basic test transactions")) { 175 let title = "Demo 1" 176 Button(title) { 177 checkDisabled = true // don't run twice 178 Task { // runs on MainActor 179 symLog.log("running integration test on demo") 180 try? await model.runIntegrationTest(newVersion: false, test: false) 181 } 182 } 183 .buttonStyle(.bordered) 184 .disabled(checkDisabled) 185 }.id("demo1runTest") 186 SettingsItem(name: String("Run Integration Test"), 187 id1: "test1test", 188 description: "Perform basic test transactions") { 189 let title = "Test 1" 190 Button(title) { 191 checkDisabled = true // don't run twice 192 Task { // runs on MainActor 193 symLog.log("running integration test on test") 194 try? await model.runIntegrationTest(newVersion: false, test: true) 195 } 196 } 197 .buttonStyle(.bordered) 198 .disabled(checkDisabled) 199 }.id("test1runTest") 200 SettingsItem(name: String("Run Integration Test V2"), 201 id1: "demo2test", 202 description: String("Perform more test transactions")) { 203 let title = "Demo 2" 204 Button(title) { 205 checkDisabled = true // don't run twice 206 Task { // runs on MainActor 207 symLog.log("running integration test V2 on demo") 208 try? await model.runIntegrationTest(newVersion: true, test: false) 209 } 210 } 211 .buttonStyle(.bordered) 212 .disabled(checkDisabled) 213 }.id("demo2runTest") 214 SettingsItem(name: String("Run Integration Test V2"), 215 id1: "test2test", 216 description: String("Perform more test transactions")) { 217 let title = "Test 2" 218 Button(title) { 219 checkDisabled = true // don't run twice 220 Task { // runs on MainActor 221 symLog.log("running integration test V2 on test") 222 try? await model.runIntegrationTest(newVersion: true, test: true) 223 } 224 } 225 .buttonStyle(.bordered) 226 .disabled(checkDisabled) 227 }.id("test2runTest") 228 SettingsItem(name: String("Run Infinite Transaction Loop"), 229 id1: "runInfinite", 230 description: String("Check DB in background")) { 231 let title = "Loop" 232 Button(title) { 233 checkDisabled = true // don't run twice 234 Task { // runs on MainActor 235 symLog.log("Running Infinite Transaction Loop") 236 try? await model.testingInfiniteTransaction(delayMs: 10_000, shouldFetch: true) 237 } 238 } 239 .buttonStyle(.bordered) 240 .disabled(checkDisabled) 241 }.id("runInfiniteLoop") 242 SettingsItem(name: String("Save Logfile"), id1: "save", 243 description: String("Help debugging wallet-core")) { 244 Button("Save") { 245 symLog.log("Saving Log") 246 // FIXME: Save Logfile 247 } 248 .buttonStyle(.bordered) 249 .disabled(true) 250 }.id("saveLog") 251 SettingsItem(name: String("Reset Wallet"), id1: "reset", 252 description: String("Throw away all your money")) { 253 Button("Reset") { 254 showResetAlert = true 255 } 256 .buttonStyle(.bordered) 257 // .disabled(didReset) 258 }.id("resetWallet") 259 } 260 } 261 .padding(.bottom) 262 .id(listID) 263 .listStyle(myListStyle.style).anyView 264 } 265 .navigationTitle(navTitle) 266 .onAppear() { 267 showDevelopItems = developerMode 268 DebugViewC.shared.setViewID(VIEW_SETTINGS, stack: stack.push()) 269 } 270 .onDisappear() { 271 checkDisabled = false // reset 272 withDrawDisabled = false 273 } 274 .alert("Reset Wallet", 275 isPresented: $showResetAlert, 276 actions: { dismissAlertButton 277 resetButton }, 278 message: { Text(verbatim: "Are you sure you want to reset your wallet?\nThis cannot be reverted, all money will be lost.") }) 279 280 } // body 281 }