commit 367047f3dfae1d35fa8c1e56e884de917225eff7
parent 4ca2ef32cf92cbc9005e4ce30ebc726ae65365a9
Author: Marc Stibane <marc@taler.net>
Date: Wed, 26 Jun 2024 15:01:31 +0200
move QR scanner into MainView
Diffstat:
5 files changed, 131 insertions(+), 134 deletions(-)
diff --git a/TalerWallet1/Views/Balances/BalancesListView.swift b/TalerWallet1/Views/Balances/BalancesListView.swift
@@ -11,72 +11,18 @@ import AVFoundation
struct BalancesListView: View {
private let symLog = SymLogV(0)
let stack: CallStack
- let navTitle: String
@Binding var balances: [Balance]
// @Binding var shouldReloadPending: Int
@Binding var shouldReloadBalances: Int
+ let cameraAction: () -> Void
@EnvironmentObject private var model: WalletModel
@EnvironmentObject private var controller: Controller
+ @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
@State private var lastReloadedBalances = 0
@State private var amountToTransfer = Amount.zero(currency: EMPTYSTRING) // Update currency when used
@State private var summary: String = ""
- @State private var showQRScanner: Bool = false
- @State private var showCameraAlert: Bool = false
-
- private var openSettingsButton: some View {
- Button("Open Settings") {
- showCameraAlert = false
- UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
- }
- }
- var ClosingAnnouncement = AttributedString(localized: "Closing Camera")
- private var dismissAlertButton: some View {
- Button("Cancel", role: .cancel) {
- if #available(iOS 17.0, *) {
- AccessibilityNotification.Announcement(ClosingAnnouncement).post()
- }
- showCameraAlert = false
- }
- }
- private func dismissingSheet() {
- if #available(iOS 17.0, *) {
- AccessibilityNotification.Announcement(ClosingAnnouncement).post()
- }
- }
-
- var defaultPriorityAnnouncement = AttributedString(localized: "Opening Camera")
- var lowPriorityAnnouncement: AttributedString {
- var lowPriorityString = AttributedString ("Camera Loading")
- if #available(iOS 17.0, *) {
- lowPriorityString.accessibilitySpeechAnnouncementPriority = .low
- }
- return lowPriorityString
- }
- var highPriorityAnnouncement: AttributedString {
- var highPriorityString = AttributedString("Camera Active")
- if #available(iOS 17.0, *) {
- highPriorityString.accessibilitySpeechAnnouncementPriority = .high
- }
- return highPriorityString
- }
- private func checkCameraAvailable() -> Void {
- // Open Camera when QR-Button was tapped
- if #available(iOS 17.0, *) {
- AccessibilityNotification.Announcement(defaultPriorityAnnouncement).post()
- }
- AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) -> Void in
- if granted {
- showQRScanner = true // present sheet
- if #available(iOS 17.0, *) {
- AccessibilityNotification.Announcement(highPriorityAnnouncement).post()
- }
- } else {
- showCameraAlert = true
- }
- })
- }
/// runs on MainActor if called in some Task {}
@discardableResult
@@ -99,77 +45,41 @@ struct BalancesListView: View {
let _ = Self._printChanges()
let _ = symLog.vlog() // just to get the # to compare it with .onAppear & onDisappear
#endif
- Content(symLog: symLog, stack: stack.push(), balances: $balances,
- amountToTransfer: $amountToTransfer, summary: $summary,
-// shouldReloadPending: $shouldReloadPending,
- shouldReloadBalances: $shouldReloadBalances,
- reloadBalances: reloadBalances)
- .navigationTitle(navTitle)
- .navigationBarItems(trailing: QRButton(action: checkCameraAvailable))
- .alert("Scanning QR-codes requires access to the camera",
- isPresented: $showCameraAlert,
- actions: { openSettingsButton
- dismissAlertButton },
- message: { Text("Please allow camera access in settings.") })
- .sheet(isPresented: $showQRScanner, onDismiss: dismissingSheet) {
- let sheet = AnyView(QRSheet(stack: stack.push(".sheet")))
- Sheet(sheetView: sheet)
- } // sheet
- .task(id: shouldReloadBalances) {
- symLog.log(".task shouldReloadBalances \(shouldReloadBalances)")
- let invalidateCache = (lastReloadedBalances != shouldReloadBalances)
- lastReloadedBalances = shouldReloadBalances
- await reloadBalances(stack.push(".task"), invalidateCache)
- } // task
- }
-}
-// MARK: -
-extension BalancesListView {
- struct Content: View {
- let symLog: SymLogV?
- let stack: CallStack
- @Binding var balances: [Balance]
- @Binding var amountToTransfer: Amount
- @Binding var summary: String
-// @Binding var shouldReloadPending: Int
- @Binding var shouldReloadBalances: Int
- var reloadBalances: (_ stack: CallStack, _ invalidateCache: Bool) async -> Int?
-
- @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
-
- var body: some View {
-#if PRINT_CHANGES
- let _ = Self._printChanges()
- let _ = symLog?.vlog() // just to get the # to compare it with .onAppear & onDisappear
-#endif
- Group { // necessary for .backslide transition (bug in SwiftUI)
- let count = balances.count
- if balances.isEmpty {
- WalletEmptyView(stack: stack.push("isEmpty"))
- } else {
- List(balances, id: \.self) { balance in
- BalancesSectionView(stack: stack.push("\(balance.scopeInfo.currency)"),
- balance: balance, // this is the currency to be used
- sectionCount: count,
- amountToTransfer: $amountToTransfer, // does still have the wrong currency
- summary: $summary,
- shouldReloadBalances: $shouldReloadBalances)
- }
- .onAppear() {
- DebugViewC.shared.setViewID(VIEW_BALANCES, stack: stack.push("onAppear"))
- }
- .listStyle(myListStyle.style).anyView
+ Group { // necessary for .backslide transition (bug in SwiftUI)
+ let count = balances.count
+ if balances.isEmpty {
+ WalletEmptyView(stack: stack.push("isEmpty"))
+ } else {
+ List(balances, id: \.self) { balance in
+ BalancesSectionView(stack: stack.push("\(balance.scopeInfo.currency)"),
+ balance: balance, // this is the currency to be used
+ sectionCount: count,
+ amountToTransfer: $amountToTransfer, // does still have the wrong currency
+ summary: $summary,
+ shouldReloadBalances: $shouldReloadBalances,
+ cameraAction: cameraAction)
}
+ .onAppear() {
+ DebugViewC.shared.setViewID(VIEW_BALANCES, stack: stack.push("onAppear"))
+ }
+ .listStyle(myListStyle.style).anyView
}
+ }
#if REFRESHABLE
- .refreshable { // already async
- symLog?.log("refreshing balances")
- let count = await reloadBalances(stack.push("refreshing balances"), true)
- if let count, count > 0 {
- NotificationCenter.default.post(name: .BalanceReloaded, object: nil)
- }
+ .refreshable { // already async
+ symLog?.log("refreshing balances")
+ let count = await reloadBalances(stack.push("refreshing balances"), true)
+ if let count, count > 0 {
+ NotificationCenter.default.post(name: .BalanceReloaded, object: nil)
}
+ }
#endif
- } // body
- } // Content
+ .navigationBarItems(trailing: QRButton(action: cameraAction))
+ .task(id: shouldReloadBalances) {
+ symLog.log(".task shouldReloadBalances \(shouldReloadBalances)")
+ let invalidateCache = (lastReloadedBalances != shouldReloadBalances)
+ lastReloadedBalances = shouldReloadBalances
+ await reloadBalances(stack.push(".task"), invalidateCache)
+ } // task
+ }
}
diff --git a/TalerWallet1/Views/Balances/BalancesSectionView.swift b/TalerWallet1/Views/Balances/BalancesSectionView.swift
@@ -22,6 +22,7 @@ struct BalancesSectionView {
@Binding var amountToTransfer: Amount // does still have the wrong currency
@Binding var summary: String
@Binding var shouldReloadBalances: Int
+ let cameraAction: () -> Void
@EnvironmentObject private var model: WalletModel
@Environment(\.colorScheme) private var colorScheme
@@ -84,7 +85,8 @@ extension BalancesSectionView: View {
summary: $summary,
completedTransactions: $completedTransactions,
reloadAllAction: reloadCompleted,
- reloadOneAction: reloadOneAction)
+ reloadOneAction: reloadOneAction,
+ cameraAction: cameraAction)
if pendingTransactions.count > 0 {
BalancesPendingRowView(symLog: symLog,
stack: stack.push(),
@@ -233,6 +235,8 @@ fileprivate struct BalancesNavigationLinksView: View {
@Binding var completedTransactions: [Transaction]
let reloadAllAction: (_ stack: CallStack) async -> ()
let reloadOneAction: ((_ transactionId: String, _ viewHandles: Bool) async throws -> Transaction)
+ let cameraAction: () -> Void
+
// @EnvironmentObject private var model: WalletModel
@State private var buttonSelected: Int? = nil
@@ -261,7 +265,8 @@ fileprivate struct BalancesNavigationLinksView: View {
amountAvailable: balance.available,
amountToTransfer: $amountToTransfer, // with correct currency
summary: $summary,
- scopeInfo: balance.scopeInfo)
+ scopeInfo: balance.scopeInfo,
+ cameraAction: cameraAction)
}, tag: 1, selection: $buttonSelected
) { EmptyView() }.frame(width: 0).opacity(0).hidden() // SendAmount
@@ -269,7 +274,8 @@ fileprivate struct BalancesNavigationLinksView: View {
RequestPayment(stack: stack.push(),
amountToTransfer: $amountToTransfer, // with correct currency
summary: $summary,
- scopeInfo: balance.scopeInfo)
+ scopeInfo: balance.scopeInfo,
+ cameraAction: cameraAction)
}, tag: 2, selection: $buttonSelected
) { EmptyView() }.frame(width: 0).opacity(0).hidden() // RequestPayment
diff --git a/TalerWallet1/Views/Main/MainView.swift b/TalerWallet1/Views/Main/MainView.swift
@@ -9,6 +9,7 @@
import SwiftUI
import os.log
import SymLog
+import AVFoundation
// Use this to delay instantiation when using `NavigationLink`, etc...
struct LazyView<Content: View>: View {
@@ -38,11 +39,67 @@ struct MainView: View {
@State private var sheetPresented = false
@State private var urlToOpen: URL? = nil
+ @State private var showQRScanner: Bool = false
+ @State private var showCameraAlert: Bool = false
func sheetDismissed() -> Void {
logger.info("sheet dismiss")
ViewState.shared.popToRootView(nil)
}
+
+ private var openSettingsButton: some View {
+ Button("Open Settings") {
+ showCameraAlert = false
+ UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
+ }
+ }
+ let ClosingAnnouncement = AttributedString(localized: "Closing Camera")
+ private var dismissAlertButton: some View {
+ Button("Cancel", role: .cancel) {
+ if #available(iOS 17.0, *) {
+ AccessibilityNotification.Announcement(ClosingAnnouncement).post()
+ }
+ showCameraAlert = false
+ }
+ }
+ private func dismissingSheet() {
+ if #available(iOS 17.0, *) {
+ AccessibilityNotification.Announcement(ClosingAnnouncement).post()
+ }
+ }
+
+ var defaultPriorityAnnouncement = AttributedString(localized: "Opening Camera")
+ var lowPriorityAnnouncement: AttributedString {
+ var lowPriorityString = AttributedString ("Camera Loading")
+ if #available(iOS 17.0, *) {
+ lowPriorityString.accessibilitySpeechAnnouncementPriority = .low
+ }
+ return lowPriorityString
+ }
+ var highPriorityAnnouncement: AttributedString {
+ var highPriorityString = AttributedString("Camera Active")
+ if #available(iOS 17.0, *) {
+ highPriorityString.accessibilitySpeechAnnouncementPriority = .high
+ }
+ return highPriorityString
+ }
+ private func checkCameraAvailable() -> Void {
+ // Open Camera when QR-Button was tapped
+ if #available(iOS 17.0, *) {
+ AccessibilityNotification.Announcement(defaultPriorityAnnouncement).post()
+ }
+ AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) -> Void in
+ if granted {
+ showQRScanner = true // present sheet
+ if #available(iOS 17.0, *) {
+ AccessibilityNotification.Announcement(highPriorityAnnouncement).post()
+ }
+ } else {
+ showCameraAlert = true
+ }
+ })
+ }
+
var body: some View {
#if PRINT_CHANGES
let _ = Self._printChanges()
@@ -50,7 +107,9 @@ struct MainView: View {
#endif
Group {
if controller.backendState == .ready {
- Content(logger: logger, stack: stack.push("Content"), talerFontIndex: $talerFontIndex)
+ Content(logger: logger, stack: stack.push("Content"),
+ talerFontIndex: $talerFontIndex,
+ cameraAction: checkCameraAvailable)
.onAppear() {
#if DEBUG
if playSoundsI != 0 && playSoundsB && !soundPlayed {
@@ -59,6 +118,15 @@ struct MainView: View {
#endif
soundPlayed = true
}
+ .alert("Scanning QR-codes requires access to the camera",
+ isPresented: $showCameraAlert,
+ actions: { openSettingsButton
+ dismissAlertButton },
+ message: { Text("Please allow camera access in settings.") })
+ .sheet(isPresented: $showQRScanner, onDismiss: dismissingSheet) {
+ let sheet = AnyView(QRSheet(stack: stack.push(".sheet")))
+ Sheet(sheetView: sheet)
+ } // sheet
} else if controller.backendState == .error {
ErrorView(errortext: nil) // TODO: show Error View
} else {
@@ -106,6 +174,7 @@ extension MainView {
let logger: Logger
let stack: CallStack
@Binding var talerFontIndex: Int
+ let cameraAction: () -> Void
#if DEBUG
@AppStorage("developerMode") var developerMode: Bool = true
@@ -190,10 +259,11 @@ extension MainView {
TabView(selection: tabSelection()) {
NavigationView {
BalancesListView(stack: stack.push(balancesTitle),
- navTitle: balancesTitle,
balances: $balances,
// shouldReloadPending: $shouldReloadPending,
- shouldReloadBalances: $shouldReloadBalances)
+ shouldReloadBalances: $shouldReloadBalances,
+ cameraAction: cameraAction)
+ .navigationTitle(balancesTitle)
}.id(viewState.rootViewId) // any change to rootViewId triggers popToRootView behaviour
.navigationViewStyle(.stack)
.tabItem {
@@ -206,10 +276,11 @@ extension MainView {
if balances.count > 1 {
NavigationView {
OverviewListV(stack: stack.push(overviewTitle),
- navTitle: overviewTitle,
- balances: $balances,
+ balances: $balances,
// shouldReloadPending: $shouldReloadPending,
- shouldReloadBalances: $shouldReloadBalances)
+ shouldReloadBalances: $shouldReloadBalances,
+ cameraAction: cameraAction)
+ .navigationTitle(overviewTitle)
}.id(viewState2.rootViewId) // any change to rootViewId triggers popToRootView behaviour
.navigationViewStyle(.stack)
.tabItem {
diff --git a/TalerWallet1/Views/Peer2peer/RequestPayment.swift b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
@@ -14,6 +14,7 @@ struct RequestPayment: View {
@Binding var amountToTransfer: Amount
@Binding var summary: String
let scopeInfo: ScopeInfo
+ let cameraAction: () -> Void
@EnvironmentObject private var controller: Controller
@EnvironmentObject private var model: WalletModel
@@ -102,6 +103,7 @@ struct RequestPayment: View {
.onDisappear {
symLog.log("❗️ \(navTitle) onDisappear")
}
+ .navigationBarItems(trailing: QRButton(action: cameraAction))
.task(id: amountToTransfer.value) {
if exchange == nil {
if let url = scopeInfo.url {
diff --git a/TalerWallet1/Views/Peer2peer/SendAmount.swift b/TalerWallet1/Views/Peer2peer/SendAmount.swift
@@ -18,6 +18,7 @@ struct SendAmount: View {
@Binding var amountToTransfer: Amount
@Binding var summary: String
let scopeInfo: ScopeInfo
+ let cameraAction: () -> Void
@EnvironmentObject private var controller: Controller
@EnvironmentObject private var model: WalletModel
@@ -108,6 +109,7 @@ struct SendAmount: View {
AmountInputV(stack: stack.push(), url: nil,
amountAvailable: amountAvailable,
amountToTransfer: $amountToTransfer,
+ wireFee: nil,
amountLabel: amountLabel,
summaryIsEditable: true,
summary: $summary,
@@ -133,6 +135,7 @@ struct SendAmount: View {
.onDisappear {
symLog.log("❗️ \(navTitle) onDisappear")
}
+ .navigationBarItems(trailing: QRButton(action: cameraAction))
.task(id: amountToTransfer.value) {
if exchange == nil {
if let url = scopeInfo.url {
@@ -176,6 +179,9 @@ fileprivate struct Preview_Content: View {
@State private var amountToPreview = Amount(currency: LONGCURRENCY, cent: 510)
@State private var summary: String = ""
+ private func checkCameraAvailable() -> Void {
+ // Open Camera when QR-Button was tapped
+ }
var body: some View {
let amount = Amount(currency: LONGCURRENCY, cent: 1000)
let scopeInfo = ScopeInfo(type: .exchange, currency: LONGCURRENCY)
@@ -190,7 +196,9 @@ fileprivate struct Preview_Content: View {
SendAmount(stack: CallStack("Preview"),
amountAvailable: amount,
amountToTransfer: $amountToPreview,
- summary: $summary, scopeInfo: scopeInfo)
+ summary: $summary,
+ scopeInfo: scopeInfo,
+ cameraAction: checkCameraAvailable)
}
}