commit 027354fc9edf655f48a45dd7d599e3a88715881b
parent 5360255a8e9c51c22ba5bc7a655dc935bd4bd7f3
Author: Marc Stibane <marc@taler.net>
Date: Mon, 18 Sep 2023 09:15:33 +0200
CallStack
Diffstat:
8 files changed, 119 insertions(+), 16 deletions(-)
diff --git a/TalerWallet.xcodeproj/project.pbxproj b/TalerWallet.xcodeproj/project.pbxproj
@@ -229,6 +229,8 @@
4ECB62802A0BA6DF004ABBB7 /* Model+P2P.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ECB627F2A0BA6DF004ABBB7 /* Model+P2P.swift */; };
4ECB62822A0BB01D004ABBB7 /* SelectDays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ECB62812A0BB01D004ABBB7 /* SelectDays.swift */; };
4ED2F94B2A278F5100453B40 /* ThreeAmounts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ED2F94A2A278F5100453B40 /* ThreeAmounts.swift */; };
+ 4EDBDCD92AB787CB00925C02 /* CallStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EDBDCD82AB787CB00925C02 /* CallStack.swift */; };
+ 4EDBDCDA2AB787CB00925C02 /* CallStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EDBDCD82AB787CB00925C02 /* CallStack.swift */; };
4EEC157329F8242800D46A03 /* QRGeneratorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EEC157229F8242800D46A03 /* QRGeneratorView.swift */; };
4EEC157629F8ECBF00D46A03 /* CodeScanner in Frameworks */ = {isa = PBXBuildFile; productRef = 4EEC157529F8ECBF00D46A03 /* CodeScanner */; };
4EEC157829F9032900D46A03 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EEC157729F9032900D46A03 /* Sheet.swift */; };
@@ -392,6 +394,7 @@
4ECB627F2A0BA6DF004ABBB7 /* Model+P2P.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Model+P2P.swift"; sourceTree = "<group>"; };
4ECB62812A0BB01D004ABBB7 /* SelectDays.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectDays.swift; sourceTree = "<group>"; };
4ED2F94A2A278F5100453B40 /* ThreeAmounts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreeAmounts.swift; sourceTree = "<group>"; };
+ 4EDBDCD82AB787CB00925C02 /* CallStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallStack.swift; sourceTree = "<group>"; };
4EEC157229F8242800D46A03 /* QRGeneratorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRGeneratorView.swift; sourceTree = "<group>"; };
4EEC157729F9032900D46A03 /* Sheet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = "<group>"; };
4EEC157929F9427F00D46A03 /* QRSheet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRSheet.swift; sourceTree = "<group>"; };
@@ -555,6 +558,7 @@
isa = PBXGroup;
children = (
4E363CBD2A23CB2100D7E98C /* AnyTransition+backslide.swift */,
+ 4EDBDCD82AB787CB00925C02 /* CallStack.swift */,
4E16E12229F3BB99008B9C86 /* CurrencyFormatter.swift */,
4EAD117529F672FA008EDD0B /* KeyboardResponder.swift */,
4E363CC12A2621C200D7E98C /* LocalizedAlertError.swift */,
@@ -1097,6 +1101,7 @@
4E3EAE6F2A990778009F1BE8 /* TalerStrings.swift in Sources */,
4E3EAE702A990778009F1BE8 /* CurrencyInputView.swift in Sources */,
4E3EAE712A990778009F1BE8 /* URL+id+iban.swift in Sources */,
+ 4EDBDCD92AB787CB00925C02 /* CallStack.swift in Sources */,
4E3EAE722A990778009F1BE8 /* RequestPayment.swift in Sources */,
4E3EAE732A990778009F1BE8 /* SettingsItem.swift in Sources */,
4E3EAE742A990778009F1BE8 /* BalanceRowView.swift in Sources */,
@@ -1198,6 +1203,7 @@
4EB0950A2989CB7C0043A8A1 /* TalerStrings.swift in Sources */,
4EA551252A2C923600FEC9A8 /* CurrencyInputView.swift in Sources */,
4E363CBC2A237E0900D7E98C /* URL+id+iban.swift in Sources */,
+ 4EDBDCDA2AB787CB00925C02 /* CallStack.swift in Sources */,
4E9320452A1645B600A87B0E /* RequestPayment.swift in Sources */,
4EB095502989CBFE0043A8A1 /* SettingsItem.swift in Sources */,
4EB0955C2989CBFE0043A8A1 /* BalanceRowView.swift in Sources */,
diff --git a/TalerWallet1/Controllers/TalerWallet1App.swift b/TalerWallet1/Controllers/TalerWallet1App.swift
@@ -37,7 +37,7 @@ struct TalerWallet1App: App {
var body: some Scene {
WindowGroup {
- MainView(soundPlayed: $soundPlayed)
+ MainView(stack: CallStack("App"), soundPlayed: $soundPlayed)
.environmentObject(debugViewC) // change viewID / sheetID
.environmentObject(viewState) // popToRoot
.environmentObject(controller)
diff --git a/TalerWallet1/Helper/CallStack.swift b/TalerWallet1/Helper/CallStack.swift
@@ -0,0 +1,89 @@
+//
+// Copyright © 2018-2023 Marc Stibane
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+// and associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+import Foundation
+
+struct CallStackItem {
+#if DEBUG
+ let file: String
+ let function: String
+#endif
+ let message: String
+}
+
+#if DEBUG
+extension CallStackItem: Identifiable {
+ var id: String { file }
+}
+extension CallStackItem: Equatable {
+ static func == (lhs: CallStackItem, rhs: CallStackItem) -> Bool {
+ lhs.file == rhs.file
+ }
+}
+#endif
+
+
+struct CallStack {
+ private var storage = [CallStackItem]()
+ func peek() -> CallStackItem? { storage.first }
+ func push(item: CallStackItem) -> CallStack {
+ return CallStack(storage: [item] + storage)
+ }
+}
+
+#if DEBUG
+fileprivate func filePath2Name(_ file: String) -> String {
+ let filePath = NSString(string: file)
+ return filePath.lastPathComponent
+}
+#endif
+
+extension CallStack {
+#if DEBUG
+ init(_ message: String = "",
+ funcName: String = #function,
+ filePath: String = #file,
+ line: UInt = #line) {
+ let item = CallStackItem(file: filePath2Name(filePath) + ":\(line)", function: funcName, message: message)
+ self.storage = [item]
+ }
+#else
+ init(_ message: String = "") {
+ let item = CallStackItem(message: message)
+ self.storage = [item]
+ }
+#endif
+#if DEBUG
+ public func push(_ message: String = "",
+ funcName: String = #function,
+ filePath: String = #file,
+ line: UInt = #line) -> CallStack {
+ let item = CallStackItem(file: filePath2Name(filePath) + ":\(line)", function: funcName, message: message)
+ return push(item: item)
+ }
+#else
+ public func push(_ message: String = "") -> CallStack {
+ let item = CallStackItem(message: message)
+ return push(item: item)
+ }
+#endif
+}
+
+//extension CallStack: Equatable {
+// static func == (lhs: CallStack, rhs: CallStack) -> Bool { lhs.storage == rhs.storage }
+//}
diff --git a/TalerWallet1/Model/Model+Balances.swift b/TalerWallet1/Model/Model+Balances.swift
@@ -43,7 +43,7 @@ fileprivate struct Balances: WalletBackendFormattedRequest {
// MARK: -
extension WalletModel {
/// fetch Balances from Wallet-Core. No networking involved
- @MainActor func balancesM()
+ @MainActor func balancesM(_ stack: CallStack)
async -> [Balance] { // M for MainActor
do {
let request = Balances()
diff --git a/TalerWallet1/Views/Balances/BalancesListView.swift b/TalerWallet1/Views/Balances/BalancesListView.swift
@@ -11,6 +11,7 @@ import AVFoundation
struct BalancesListView: View {
private let symLog = SymLogV()
let navTitle: String
+ let stack: CallStack
let hamburgerAction: () -> Void
@EnvironmentObject private var model: WalletModel
@@ -70,8 +71,8 @@ struct BalancesListView: View {
}
/// runs on MainActor if called in some Task {}
- private func reloadAction() async -> Int {
- let reloaded = await model.balancesM()
+ private func reloadAction(_ stack: CallStack) async -> Int {
+ let reloaded = await model.balancesM(stack.push())
let count = reloaded.count
balances = reloaded
return count
@@ -82,7 +83,7 @@ struct BalancesListView: View {
let _ = Self._printChanges()
let _ = symLog.vlog() // just to get the # to compare it with .onAppear & onDisappear
#endif
- Content(symLog: symLog, balances: $balances,
+ Content(symLog: symLog, stack: stack.push(), balances: $balances,
centsToTransfer: $centsToTransfer, summary: $summary,
reloadAction: reloadAction)
.navigationTitle(navTitle)
@@ -93,13 +94,12 @@ struct BalancesListView: View {
WalletEmptyView()
.refreshable { // already async
symLog.log("refreshing")
- let count = await reloadAction()
+ let count = await reloadAction(stack.push())
if count > 0 {
// postNotificationM(.BalanceReloaded)
NotificationCenter.default.post(name: .BalanceReloaded, object: nil)
}
}
-
}
}
.alert("Scanning QR-codes requires access to the camera",
@@ -116,7 +116,7 @@ struct BalancesListView: View {
} // sheet
.task {
symLog.log(".task getBalances")
- _ = await reloadAction()
+ _ = await reloadAction(stack.push(".task getBalances"))
} // task
}
}
@@ -124,11 +124,12 @@ struct BalancesListView: View {
extension BalancesListView {
struct Content: View {
let symLog: SymLogV?
+ let stack: CallStack
@AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
@Binding var balances: [Balance]
@Binding var centsToTransfer: UInt64
@Binding var summary: String
- var reloadAction: () async -> Int
+ var reloadAction: (_ stack: CallStack) async -> Int
@State private var isActive = true
@State private var shouldReload = false
@@ -141,14 +142,15 @@ extension BalancesListView {
Group { // necessary for .backslide transition (bug in SwiftUI)
let count = balances.count
List(balances, id: \.self) { balance in
- BalancesSectionView(balance: balance,
+ BalancesSectionView(stack: stack.push(),
+ balance: balance,
sectionCount: count,
centsToTransfer: $centsToTransfer,
summary: $summary)
}
.refreshable { // already async
symLog?.log("refreshing")
- let count = await reloadAction()
+ let count = await reloadAction(stack.push())
if count > 0 {
// postNotificationM(.BalanceReloaded)
NotificationCenter.default.post(name: .BalanceReloaded, object: nil)
@@ -161,7 +163,7 @@ extension BalancesListView {
if shouldReload {
shouldReload = false
symLog?.log(".onAppear ==> shouldReload was true, reloading now")
- Task { await reloadAction() } // runs on MainActor
+ Task { await reloadAction(stack.push()) } // runs on MainActor
}
}
.onDisappear() {
@@ -172,7 +174,7 @@ extension BalancesListView {
// doesn't need to be received on main thread because we just reload in a background task anyway
if isActive {
symLog?.log(".onNotification(.BalanceChange) ==> reload")
- Task { await reloadAction() }
+ Task { await reloadAction(stack.push()) }
} else {
symLog?.log(".onNotification(.BalanceChange) ==> reload postponed, shouldReload = true")
shouldReload = true
diff --git a/TalerWallet1/Views/Balances/BalancesSectionView.swift b/TalerWallet1/Views/Balances/BalancesSectionView.swift
@@ -16,6 +16,7 @@ import SymLog
struct BalancesSectionView: View {
private let symLog = SymLogV()
+ let stack: CallStack
let balance: Balance
let sectionCount: Int
@Binding var centsToTransfer: UInt64
diff --git a/TalerWallet1/Views/Main/MainView.swift b/TalerWallet1/Views/Main/MainView.swift
@@ -15,6 +15,7 @@ struct LazyView<Content: View>: View {
struct MainView: View {
private let symLog = SymLogV(0)
+ let stack: CallStack
@EnvironmentObject private var viewState: ViewState // popToRootView()
@EnvironmentObject private var controller: Controller
@State private var sheetPresented = false
@@ -32,7 +33,7 @@ struct MainView: View {
#endif
Group {
if controller.backendState == .ready {
- Content(symLog: symLog, talerFont: $talerFont)
+ Content(symLog: symLog, stack: stack.push(), talerFont: $talerFont)
// any change to rootViewId triggers popToRootView behaviour
.id(viewState.rootViewId)
.onAppear() {
@@ -68,6 +69,7 @@ struct MainView: View {
extension MainView {
struct Content: View {
let symLog: SymLogV?
+ let stack: CallStack
@Binding var talerFont: Int
@State var sidebarVisible: Bool = false
func hamburgerAction() {
@@ -83,6 +85,7 @@ extension MainView {
SidebarItem(name: balances,
sysImage: "creditcard.fill", // TODO: Wallet Icon
view: AnyView(BalancesListView(navTitle: balances,
+ stack: stack.push(),
hamburgerAction: hamburgerAction)
)),
SidebarItem(name: exchanges,
@@ -124,7 +127,8 @@ extension MainView {
.talerNavBar(talerFont: talerFont)
// The side view is above (Z-Axis) the current view
- SideBarView(views: views,
+ SideBarView(stack: stack.push(),
+ views: views,
currentView: $currentView,
sidebarVisible: sidebarVisible,
hamburgerAction: hamburgerAction)
diff --git a/TalerWallet1/Views/Main/SideBarView.swift b/TalerWallet1/Views/Main/SideBarView.swift
@@ -15,6 +15,7 @@ struct SidebarItem {
struct SideBarView: View {
private let symLog = SymLogV(0)
+ let stack: CallStack
let views: [SidebarItem]
@Binding var currentView: Int
let sidebarVisible: Bool
@@ -85,7 +86,7 @@ fileprivate struct BindingViewContainer : View {
ZStack(alignment: .leading) {
views[currentView].view
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
- SideBarView(views: views, currentView: $currentView,
+ SideBarView(stack: CallStack("Preview"), views: views, currentView: $currentView,
sidebarVisible: sidebarVisible,
hamburgerAction: { sidebarVisible = !sidebarVisible })
}