commit b714b11c889e10feded17792e9510324bad2f96f
parent 60fe9037b17f7032816b1bc633206a7e789a75cf
Author: Marc Stibane <marc@taler.net>
Date: Wed, 25 Feb 2026 17:13:29 +0100
QR scanner 2/3 height
Diffstat:
4 files changed, 25 insertions(+), 12 deletions(-)
diff --git a/TalerWallet1/Controllers/PublicConstants.swift b/TalerWallet1/Controllers/PublicConstants.swift
@@ -27,7 +27,8 @@ public let DRAGDELAY = 0.5
public let DRAGDURATION = 0.45
public let DRAGSPEED = 0.1
public let MAXRECENT = 4 // # of rows in Recent Transactions
-public let SCANDETENT = 0.999 // instead .large sheet - in the .001 is a VoiceOver dismiss button
+public let SCANDETENT = 0.666 // 2/3 height - in the rest is a (invisible) dismiss button, also for VoiceOver
+public let ACTIONDETENT = 0.999
public let ICONLEADING = CGFloat(-8)
public let HSPACING = CGFloat(10) // space between items in HStack
diff --git a/TalerWallet1/Views/Actions/ActionsSheet.swift b/TalerWallet1/Views/Actions/ActionsSheet.swift
@@ -164,14 +164,16 @@ struct DualHeightSheet: View {
let logger = Logger(subsystem: "net.taler.gnu", category: "DualSheet")
@Environment(\.colorScheme) private var colorScheme
@Environment(\.colorSchemeContrast) private var colorSchemeContrast
- let scanDetent: PresentationDetent = .fraction(SCANDETENT)
// @State private var selectedDetent: PresentationDetent = scanDetent // Cannot use instance member 'scanDetent' within property initializer
@State private var selectedDetent: PresentationDetent = .fraction(0.1) // workaround - update in .task
@State private var detents: Set<PresentationDetent> = [.fraction(0.1)] // "
@State private var qrButtonTapped2: Bool = false
+ @State private var scannedCode: Bool = false
@State private var innerHeight: CGFloat = .zero
@State private var sheetHeight: CGFloat = .zero
+ let scanDetent: PresentationDetent = .fraction(SCANDETENT)
+
func updateDetentsWithDelay() {
Task {
//(1 second = 1_000_000_000 nanoseconds)
@@ -222,7 +224,7 @@ struct DualHeightSheet: View {
}
.presentationDetents(detents, selection: $selectedDetent)
.onChange(of: selectedDetent) { newValue in
- if newValue == scanDetent { // user swiped the sheet up to full height
+ if newValue == scanDetent { // user swiped the sheet up to activate QR scanner
logger.trace("onChange❗️selectedDetent = \(SCANDETENT)")
updateDetentsWithDelay()
qrButtonTapped = true // tell our caller
@@ -246,10 +248,11 @@ struct DualHeightSheet: View {
onDismiss: dismissScanner
) {
let qrSheet = AnyView(QRSheet(stack: stack.push(".sheet"),
- selectedBalance: selectedBalance))
- let scanDetent: PresentationDetent = .fraction(SCANDETENT)
+ selectedBalance: selectedBalance,
+ scannedSomething: $scannedCode))
+ let detent: PresentationDetent = .fraction(scannedCode ? ACTIONDETENT : SCANDETENT)
Sheet(stack: stack.push(), sheetView: qrSheet)
- .presentationDetents([scanDetent])
+ .presentationDetents([detent])
.transition(.opacity)
}
diff --git a/TalerWallet1/Views/Main/MainView.swift b/TalerWallet1/Views/Main/MainView.swift
@@ -41,6 +41,7 @@ struct MainView: View {
// @State private var showCameraAlert: Bool = false
@State private var qrButtonTapped = false
@State private var qrButton2Tapped = false
+ @State private var scannedCode: Bool = false
@State private var innerHeight: CGFloat = .zero
@State private var userAction = 0 // make Action button jump, hold here
@State private var networkUnavailable = false
@@ -58,6 +59,7 @@ struct MainView: View {
showActionSheet = false
qrButtonTapped = false
qrButton2Tapped = false
+ scannedCode = false
userAction += 1
// TODO: wallet-core could notify us when it creates a dialog tx
NotificationCenter.default.post(name: .TransactionScanned, object: nil, userInfo: nil)
@@ -187,12 +189,13 @@ struct MainView: View {
onDismiss: dismissSheet
) {
let qrSheet = AnyView(QRSheet(stack: stack.push(".sheet"),
- selectedBalance: selectedBalance))
+ selectedBalance: selectedBalance,
+ scannedSomething: $scannedCode))
// let _ = logger.trace("❗️showScanner: \(SCANDETENT)❗️")
if #available(iOS 16.4, *) {
- let scanDetent: PresentationDetent = .fraction(SCANDETENT)
+ let detent: PresentationDetent = .fraction(scannedCode ? ACTIONDETENT : SCANDETENT)
Sheet(stack: stack.push(), sheetView: qrSheet)
- .presentationDetents([scanDetent])
+ .presentationDetents([detent])
.transition(.opacity)
} else {
Sheet(stack: stack.push(), sheetView: qrSheet)
diff --git a/TalerWallet1/Views/Sheets/QRSheet.swift b/TalerWallet1/Views/Sheets/QRSheet.swift
@@ -14,10 +14,11 @@ struct QRSheet: View {
private let symLog = SymLogV(0)
let stack: CallStack
let selectedBalance: Balance?
+ @Binding var scannedSomething: Bool
@EnvironmentObject private var model: WalletModel
@State private var scannedCode: String?
- @State private var urlToOpen: URL?
+ @State private var urlToOpen: URL? = nil
@State private var isTorchOn: Bool = false
func codeToURL(_ code: String) -> URL? {
@@ -40,17 +41,19 @@ struct QRSheet: View {
Group {
let errorAnnouncement = String(localized: "Error while scanning QR code", comment: "a11y")
if scannedCode != nil {
+ // we need to evaluate the scanned code again, because urlToOpen will be set to nil
if let scannedURL = codeToURL(scannedCode!) {
let scheme = scannedURL.scheme
if scheme?.lowercased() == "taler" {
URLSheet(stack: stack.push(),
selectedBalance: selectedBalance,
- urlToOpen: $urlToOpen)
+ urlToOpen: $urlToOpen) // !!! will set @Binding to nil
} else {
// let _ = print(scannedURL) // TODO: error logging
ErrorView(title: String(localized: "Scanned QR is no talerURI"),
message: scannedURL.absoluteString,
copyable: true) {
+ scannedSomething = false
dismissTop(stack.push())
}
}
@@ -58,6 +61,7 @@ struct QRSheet: View {
ErrorView(title: String(localized: "Scanned QR is no URL"),
message: scannedCode,
copyable: true) {
+ scannedSomething = false
dismissTop(stack.push())
}
}
@@ -69,11 +73,13 @@ struct QRSheet: View {
switch response {
case .success(let result):
symLog.log("Found code: \(result.string)")
- scannedCode = result.string
+ scannedSomething = true
urlToOpen = codeToURL(result.string)
+ scannedCode = result.string
closingAnnouncement = String(localized: "QR code recognized", comment: "a11y")
case .failure(let error):
// TODO: errorAlert
+ scannedSomething = false
model.setError(error)
closingAnnouncement = errorAnnouncement
}