taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

commit b9d642b272dc82677a0445bbb53f9789966c58b9
parent a3b54011507b499934efc935b23e7372a11ec390
Author: Marc Stibane <marc@taler.net>
Date:   Sat, 12 Sep 2026 09:18:09 +0200

StalledView

Diffstat:
MTalerWallet1/Controllers/PublicConstants.swift | 2+-
MTalerWallet1/Views/HelperViews/LoadingView.swift | 165+++++++++++++++++++++++++++++++++++++++++--------------------------------------
2 files changed, 87 insertions(+), 80 deletions(-)

diff --git a/TalerWallet1/Controllers/PublicConstants.swift b/TalerWallet1/Controllers/PublicConstants.swift @@ -43,7 +43,7 @@ public let ICONLEADING = CGFloat(-8) public let HSPACING = CGFloat(10) // space between items in HStack public let LAUNCHDURATION: Double = 1.60 -public let BANNERDURATION: Double = 0.666 +public let BANNERDURATION: Double = 0.5 public let ONEDAY: UInt = 1 // 1..3 public let SEVENDAYS: UInt = 7 // 3..9 diff --git a/TalerWallet1/Views/HelperViews/LoadingView.swift b/TalerWallet1/Views/HelperViews/LoadingView.swift @@ -8,6 +8,90 @@ import SwiftUI import SymLog +struct StalledView: View { + + @EnvironmentObject private var controller: Controller + @EnvironmentObject private var model: WalletModel + + @State private var isFinished: Bool? = false + + @ViewBuilder + func retryButton(disabled: Bool) -> some View { + Button("Retry now") { + if let token = controller.progressToken { + if let operation = controller.progressOperation { + controller.lastProgressError = nil + Task { + try await model.retryProgressTokenNow(operation, token: token) + } + } + } + } + .buttonStyle(TalerButtonStyle(type: .prominent, disabled: disabled)) + .padding(.horizontal) + } + + fileprivate func toJSON(_ lastError: RequestProgressError?) -> String? { + if let lastError { + do { + let jsonData = try JSONEncoder().encode(lastError) + if let jsonString = String(data: jsonData, encoding: .utf8) { + return jsonString + } + } catch { // JSON encoding of error failed / should never happen + return "Couldn't encode error" + } + } + return nil + } + + var body: some View { + Group { + let lastError = controller.lastProgressError + let fallback = String(localized: "It seems that there is a problem with the network.") + Text("Couldn't establish a connection") + .talerFont(.title2) + .padding(.vertical) + let hint = lastError?.error.hint + ?? lastError?.error.errorResponse?.hint + Text(hint ?? fallback) + .talerFont(.body) + if let jsonString = toJSON(lastError) { + CopyButton(jsonString, title: "Copy Details") + .padding(.vertical) + } + Spacer() + if let lastPhase = controller.lastProgressPhase { + if lastPhase.phase == .stalled { + if let lastError, let delay = lastError.nextRetryDelay { + if isFinished == false { + TimeView("Next retry in:", seconds: Int(delay.toSeconds()), isFinished: $isFinished) + .talerFont(.title3) + .padding(.vertical) + } else if isFinished == true { + Text("Retrying…") + .talerFont(.title3) + } else { + Text("Waiting for response…") + .talerFont(.title3) + } + } + // Spacer() + retryButton(disabled: isFinished ?? false) + } + } + } + .listRowSeparator(.hidden) + .onChange(of: controller.errorConnection) { isError in + if isError { +// print("❗️❗️❗️ error arrived, idle waiting starts") + isFinished = false + controller.errorConnection = false + } + } + } +} + struct LoadingView: View { private let symLog = SymLogV(0) let stack: CallStack @@ -26,13 +110,10 @@ struct LoadingView: View { #endif @State private var rotationEnabled = true - @State private var showAlert: Bool = false @State private var disabled: Bool = false - @State private var isFinished: Bool? = false private var dismissButton: some View { Button("Cancel", role: .cancel) { - showAlert = false if let token = controller.progressToken { controller.progressToken = nil if let operation = controller.progressOperation { @@ -56,75 +137,11 @@ struct LoadingView: View { .padding(.horizontal) } - @ViewBuilder - func retryButton(disabled: Bool) -> some View { - Button("Retry now") { - withAnimation { - showAlert = false - } - if let token = controller.progressToken { - if let operation = controller.progressOperation { - controller.lastProgressError = nil - Task { - try await model.retryProgressTokenNow(operation, token: token) - } - } - } - } - .buttonStyle(TalerButtonStyle(type: .prominent, disabled: disabled)) - .padding(.horizontal) - } - - fileprivate func toJSON(_ lastError: RequestProgressError?) -> String? { - if let lastError { - do { - let jsonData = try JSONEncoder().encode(lastError) - if let jsonString = String(data: jsonData, encoding: .utf8) { - return jsonString - } - } catch { // JSON encoding of error failed / should never happen - return "Couldn't encode error" - } - } - return nil - } var body: some View { let view = VStack(alignment: .center) { - if showAlert { - let lastError = controller.lastProgressError - let fallback = String(localized: "It seems that there is a problem with the network.") - Text("Couldn't establish a connection") - .talerFont(.title2) - .padding(.vertical) - let hint = lastError?.error.hint - ?? lastError?.error.errorResponse?.hint - Text(hint ?? fallback) - .talerFont(.body) - if let jsonString = toJSON(lastError) { - CopyButton(jsonString, title: "Copy Details") - .padding(.vertical) - } - Spacer() - if let lastPhase = controller.lastProgressPhase { - if lastPhase.phase == .stalled { - if let lastError, let delay = lastError.nextRetryDelay { - if isFinished == false { - TimeView("Next retry in:", seconds: Int(delay.toSeconds()), isFinished: $isFinished) - .talerFont(.title3) - .padding(.vertical) - } else if isFinished == true { - Text("Retrying…") - .talerFont(.title3) - } else { - Text("Waiting for response…") - .talerFont(.title3) - } - } -// Spacer() - retryButton(disabled: isFinished ?? false) - } - } + if controller.stalledConnection { + StalledView() } else { Spacer() RotatingTaler(size: 100, @@ -156,16 +173,6 @@ struct LoadingView: View { .talerFont(.title) .navigationTitle(navTitle) .background(FullBackground()) - .onChange(of: controller.stalledConnection) { isStalled in - showAlert = isStalled - } - .onChange(of: controller.errorConnection) { isError in - if isError { -// print("❗️❗️❗️ error arrived, idle waiting starts") - isFinished = false - controller.errorConnection = false - } - } if #available(iOS 17.0, *) { view.toolbarTitleDisplayMode(.inlineLarge)