gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taler-ios] 16/30: ShortcutButton


From: gnunet
Subject: [taler-taler-ios] 16/30: ShortcutButton
Date: Sun, 19 Nov 2023 23:53:40 +0100

This is an automated email from the git hooks/post-receive script.

marc-stibane pushed a commit to branch master
in repository taler-ios.

commit fbf878e49ff96b939322323b1fd6b3200c714f69
Author: Marc Stibane <marc@taler.net>
AuthorDate: Sat Nov 18 19:24:55 2023 +0100

    ShortcutButton
---
 TalerWallet1/Views/Exchange/ManualWithdraw.swift   |   3 +-
 TalerWallet1/Views/HelperViews/CurrencyField.swift |  70 ++++++++-----
 .../Views/HelperViews/CurrencyInputView.swift      | 109 +++++++++++++++++----
 TalerWallet1/Views/Peer2peer/RequestPayment.swift  |  30 +++---
 TalerWallet1/Views/Peer2peer/SendAmount.swift      |   4 +-
 TalerWallet1/Views/Peer2peer/SendPurpose.swift     |  16 ++-
 6 files changed, 166 insertions(+), 66 deletions(-)

diff --git a/TalerWallet1/Views/Exchange/ManualWithdraw.swift 
b/TalerWallet1/Views/Exchange/ManualWithdraw.swift
index e371df4..6b17785 100644
--- a/TalerWallet1/Views/Exchange/ManualWithdraw.swift
+++ b/TalerWallet1/Views/Exchange/ManualWithdraw.swift
@@ -34,8 +34,7 @@ struct ManualWithdraw: View {
             VStack {
                 CurrencyInputView(amount: $amountToTransfer,
                                    title: iconOnly ? String(localized: "How 
much:")
-                                                   : String(localized: "Amount 
to withdraw:"),
-                           shortcutLabel: String(localized: "Withdraw", 
comment: "VoiceOver: Withdraw $50,$25,$10,$5 shortcut buttons"))
+                                                   : String(localized: "Amount 
to withdraw:"))
                 let someCoins = SomeCoins(details: withdrawalAmountDetails)
                 QuiteSomeCoins(someCoins: someCoins,
                            shouldShowFee: true,           // TODO: set to 
false if we never charge withdrawal fees
diff --git a/TalerWallet1/Views/HelperViews/CurrencyField.swift 
b/TalerWallet1/Views/HelperViews/CurrencyField.swift
index 784c9dd..7b74114 100644
--- a/TalerWallet1/Views/HelperViews/CurrencyField.swift
+++ b/TalerWallet1/Views/HelperViews/CurrencyField.swift
@@ -30,25 +30,25 @@ struct CurrencyField: View {
     @Binding var amount: Amount         // the `value´
     let currencyInfo: CurrencyInfo
 
-    private var currencyInputField: CurrencyInputField! = nil
+    private var currencyFieldRepresentable: CurrencyTextfieldRepresentable! = 
nil
 
-    public func becomeFirstResponder() -> Void {
-        currencyInputField.becomeFirstResponder()
+    public func becomeFirstResponder() -> Bool {
+        currencyFieldRepresentable.becomeFirstResponder()
     }
 
     public func resignFirstResponder() -> Void {
-        currencyInputField.resignFirstResponder()
+        currencyFieldRepresentable.resignFirstResponder()
     }
 
     func updateText(amount: Amount) {
-        currencyInputField.updateText(amount: amount)
+        currencyFieldRepresentable.updateText(amount: amount)
     }
 
     public init(amount: Binding<Amount>, currencyInfo: CurrencyInfo) {
         self._amount = amount
         self.currencyInfo = currencyInfo
-        self.currencyInputField = CurrencyInputField(amount: self.$amount,
-                                               currencyInfo: currencyInfo)
+        self.currencyFieldRepresentable = 
CurrencyTextfieldRepresentable(amount: self.$amount,
+                                                                   
currencyInfo: currencyInfo)
     }
 
     var body: some View {
@@ -61,11 +61,13 @@ struct CurrencyField: View {
             // Set as priority so CurrencyInputField size doesn't affect parent
             Text(amount.string(currencyInfo))
                 .layoutPriority(1)
+                // make the textfield use the whole width for tapping inside 
to become active
+                .frame(maxWidth: .infinity, alignment: .trailing)
+//                .background(.clear) this is not the problem of the white 
corners
 
             // Input text field to handle UI
-            currencyInputField
-                .accessibilityHidden(true)
-//                .textFieldStyle(.roundedBorder)
+            currencyFieldRepresentable
+//                .accessibilityHidden(true)
         }
     }
 }
@@ -86,7 +88,7 @@ class NoCaretTextField: UITextField {
 }
 
 @MainActor
-struct CurrencyInputField: UIViewRepresentable {
+struct CurrencyTextfieldRepresentable: UIViewRepresentable {
     @Binding var amount: Amount
     let currencyInfo: CurrencyInfo
 
@@ -96,12 +98,13 @@ struct CurrencyInputField: UIViewRepresentable {
         Coordinator(self)
     }
 
-    @MainActor public func becomeFirstResponder() -> Void {
+    @MainActor public func becomeFirstResponder() -> Bool {
         textField.becomeFirstResponder()
     }
 
     @MainActor public func resignFirstResponder() -> Void {
         textField.resignFirstResponder()
+        Self.endEditing()
     }
 
     func updateText(amount: Amount) {
@@ -113,17 +116,29 @@ struct CurrencyInputField: UIViewRepresentable {
     }
 
     func makeUIView(context: Context) -> NoCaretTextField {
+        textField.setContentCompressionResistancePriority(.defaultLow, for: 
.horizontal)
+
         // Assign delegate
         textField.delegate = context.coordinator
 
         // Set keyboard type
         textField.keyboardType = .numberPad
 
-        // Make visual components invisible
+        // Make visual components invisible...
         textField.tintColor = .clear
         textField.textColor = .clear
         textField.backgroundColor = .clear
+        // ... except for the bezel around the textfield
+        textField.borderStyle = .roundedRect
+//        textField.textFieldStyle(.roundedBorder)
 
+#if DEBUG
+        // Debugging: add a red border around the textfield
+        let myColor = UIColor(red: 0.9, green: 0.1, blue:0, alpha: 1.0)
+        textField.layer.masksToBounds = true
+        textField.layer.borderColor = myColor.cgColor
+    //    textField.layer.borderWidth = 2.0      //    <-   uncomment to show 
the border
+#endif
         // Add editingChanged event handler
         textField.addTarget(
             context.coordinator,
@@ -141,13 +156,13 @@ struct CurrencyInputField: UIViewRepresentable {
 
     class Coordinator: NSObject, UITextFieldDelegate {
         // Reference to currency input field
-        private var input: CurrencyInputField
+        private var textfieldRepresentable: CurrencyTextfieldRepresentable
 
         // Last valid text input string to be displayed
         private var lastValidInput: String? = ""
 
-        init(_ currencyTextField: CurrencyInputField) {
-            self.input = currencyTextField
+        init(_ representable: CurrencyTextfieldRepresentable) {
+            self.textfieldRepresentable = representable
         }
 
         func setValue(_ amount: Amount, textField: UITextField) {
@@ -155,12 +170,12 @@ struct CurrencyInputField: UIViewRepresentable {
             updateText(amount, textField: textField)
             // Update input value
 //    print(input.amount.description, " := ", amount.description)
-            input.amount = amount
+            textfieldRepresentable.amount = amount
         }
 
         func updateText(_ amount: Amount, textField: UITextField) {
             // Update field text and last valid input text
-            lastValidInput = amount.plainString(input.currencyInfo)
+            lastValidInput = 
amount.plainString(textfieldRepresentable.currencyInfo)
 //    print("lastValidInput: `\(lastValidInput)´")
             textField.text = lastValidInput
             let endPosition = textField.endOfDocument
@@ -171,18 +186,27 @@ struct CurrencyInputField: UIViewRepresentable {
             // If replacement string is empty, we can assume the backspace key 
was hit
             if string.isEmpty {
                 // Resign first responder when delete is hit when value is 0
-                if input.amount.isZero {
+                if textfieldRepresentable.amount.isZero {
                     textField.resignFirstResponder()
+//                    Self.endEditing()
                 } else {
                     // Remove trailing digit: divide value by 10
-                    let amount = input.amount.copy()
-                    amount.removeDigit(input.currencyInfo)
+                    let amount = textfieldRepresentable.amount.copy()
+                    amount.removeDigit(textfieldRepresentable.currencyInfo)
                     setValue(amount, textField: textField)
                 }
             }
             return true
         }
 
+        func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
+            return true
+        }
+
+        func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
+            return true
+        }
+
         @objc func editingChanged(textField: NoCaretTextField) {
             // Get a mutable copy of last text
             guard var oldText = lastValidInput else {
@@ -209,8 +233,8 @@ struct CurrencyInputField: UIViewRepresentable {
 
             // Multiply by 10 to shift numbers one position to the left, 
revert if an overflow occurs
             // Add the new trailing digit, revert if an overflow occurs
-            let amount = input.amount.copy()
-            amount.addDigit(digit, currencyInfo: input.currencyInfo)
+            let amount = textfieldRepresentable.amount.copy()
+            amount.addDigit(digit, currencyInfo: 
textfieldRepresentable.currencyInfo)
 
             // If new value has more digits than allowed by formatter, revert
 //            if input.formatter.maximumFractionDigits + 
input.formatter.maximumIntegerDigits < String(addValue).count {
diff --git a/TalerWallet1/Views/HelperViews/CurrencyInputView.swift 
b/TalerWallet1/Views/HelperViews/CurrencyInputView.swift
index 7d6c045..6155802 100644
--- a/TalerWallet1/Views/HelperViews/CurrencyInputView.swift
+++ b/TalerWallet1/Views/HelperViews/CurrencyInputView.swift
@@ -5,24 +5,60 @@
 import SwiftUI
 import taler_swift
 
+fileprivate let shortcuts = [5000,2500,1000,500]        // TODO: adapt for ¥
+
+struct ShortcutButton: View {
+    let shortcut: Int
+    let currency: String
+    let currencyInfo: CurrencyInfo
+    let currencyField: CurrencyField
+    let action: (Int, CurrencyField) -> Void
+
+    func makeButton(with newShortcut: Int) -> ShortcutButton {
+        ShortcutButton(shortcut: newShortcut,
+                       currency: currency,
+                   currencyInfo: currencyInfo,
+                  currencyField: currencyField,
+                         action: action)
+    }
+
+    var body: some View {
+        let shortie = Amount(currency: currency, cent: UInt64(shortcut))       
 // TODO: adapt for ¥
+        let title = shortie.string(currencyInfo)
+        let shortcutLabel = String(localized: "Shortcut", comment: "VoiceOver: 
$50,$25,$10,$5 shortcut buttons")
+        Button(action: { action(shortcut, currencyField)} ) {
+            Text(title)
+                .accessibilityFont(.callout)
+        }.buttonStyle(.bordered)
+            .accessibilityLabel("\(shortcutLabel) \(title)")
+    }
+}
+// MARK: -
 struct CurrencyInputView: View {
     @Binding var amount: Amount         // the `value´
     let title: String
-    let shortcutLabel: String
 
     @EnvironmentObject private var controller: Controller
     
-    @State var hasBeenShown = false
+    @State private var hasBeenShown = false
+    @State private var showKeyboard = 0
+    @State private var useShortcut = 0
+
+    func action(shortcut: Int, currencyField: CurrencyField) {
+        useShortcut = shortcut
+        let shortie = Amount(currency: amount.currencyStr, cent: 
UInt64(shortcut))      // TODO: adapt for ¥
+        currencyField.updateText(amount: shortie)
+        amount = shortie
+        currencyField.resignFirstResponder()
+    }
 
     var body: some View {
-        let shortcuts = [50,25,10,5]
         let currency = amount.currencyStr
         let currencyInfo = controller.info(for: currency, 
controller.currencyTicker)
         let currencyField = CurrencyField(amount: $amount, currencyInfo: 
currencyInfo)
         VStack (alignment: .center) {
             HStack {
                 Text(title)
-//                  .padding(.top)
                     .accessibilityFont(.title3)
                     .accessibilityAddTraits(.isHeader)
                     .accessibilityRemoveTraits(.isStaticText)
@@ -34,29 +70,67 @@ struct CurrencyInputView: View {
                 .background(WalletColors().fieldBackground)
                 .accessibilityFont(.title2)
                 .textFieldStyle(.roundedBorder)
-            HStack {
-                ForEach(shortcuts, id: \.self) { shortcut in
-                    let shortie = Amount(currency: currency, integer: 
UInt64(shortcut), fraction: 0)
-                    let title = shortie.string(currencyInfo)
-                    Button(title) {
-                        currencyField.updateText(amount: shortie)
-                        amount = shortie
-                    }.buttonStyle(.bordered)
-                        .accessibilityLabel("\(shortcutLabel) \(title)")
+                .onTapGesture {
+                    if useShortcut != 0 {
+                        amount = Amount.zero(currency: currency)
+                        useShortcut = 0
+                    }
+                    showKeyboard += 1
                 }
-            }
+            if #available(iOS 16.0, *) {
+                let shortcutButton = ShortcutButton(shortcut: 0,
+                                                    currency: currency,
+                                                currencyInfo: currencyInfo,
+                                               currencyField: currencyField,
+                                                      action: action)
+                ViewThatFits(in: .horizontal) {
+                    HStack {
+                        ForEach(shortcuts, id: \.self) {
+                            shortcutButton.makeButton(with: $0)
+                                .accessibilityAddTraits($0 == useShortcut ? 
.isSelected : [])
+                        }
+                    }
+                    VStack {
+                        let count = shortcuts.count
+                        let half = count / 2
+                        HStack {
+                            ForEach(0..<half, id: \.self) { index in
+                                let thisShortcut = shortcuts[index]
+                                shortcutButton.makeButton(with: thisShortcut)
+                                    .accessibilityAddTraits(thisShortcut == 
useShortcut ? .isSelected : [])
+                            }
+                        }
+                        HStack {
+                            ForEach(half..<count, id: \.self) { index in
+                                let thisShortcut = shortcuts[index]
+                                shortcutButton.makeButton(with: thisShortcut)
+                                    .accessibilityAddTraits(thisShortcut == 
useShortcut ? .isSelected : [])
+                            }
+                        }
+                    }
+                    VStack {
+                        ForEach(shortcuts, id: \.self) {
+                            shortcutButton.makeButton(with: $0)
+                                .accessibilityAddTraits($0 == useShortcut ? 
.isSelected : [])
+                        }
+                    }
+                }
+            } // iOS 16+ only
         }.onAppear {   // make CurrencyField show the keyboard after 0.4 
seconds
             if hasBeenShown {
 //                print("❗️Yikes: CurrencyInputView hasBeenShown")
             } else {
-//                print("❗️Yikes: First CurrencyInputView❗️")
+                print("❗️CurrencyInputView❗️")
                 DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
                     hasBeenShown = true
-                    currencyField.becomeFirstResponder()
+                    if !currencyField.becomeFirstResponder() {
+                        print("❗️Yikes❗️")
+                    }
                 }
             }
         }.onDisappear {
             currencyField.resignFirstResponder()
+            hasBeenShown = false
         }
     }
 }
@@ -70,8 +144,7 @@ fileprivate struct Previews: PreviewProvider {
         var body: some View {
 //            Preview_Content()
             CurrencyInputView(amount: $amountToTransfer,
-                               title: "Amount to withdraw:",
-                       shortcutLabel: "Withdraw")
+                               title: "Amount to withdraw:")
                 .environmentObject(controller)
         }
     }
diff --git a/TalerWallet1/Views/Peer2peer/RequestPayment.swift 
b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
index 618ddee..5192731 100644
--- a/TalerWallet1/Views/Peer2peer/RequestPayment.swift
+++ b/TalerWallet1/Views/Peer2peer/RequestPayment.swift
@@ -31,8 +31,7 @@ struct RequestPayment: View {
         ScrollView { VStack {
             CurrencyInputView(amount: $amountToTransfer,
                                title: iconOnly ? String(localized: "How much:")
-                                               : String(localized: "Amount to 
request:"),
-                       shortcutLabel: String(localized: "Request", comment: 
"VoiceOver: Request $50,$25,$10,$5 shortcut buttons"))
+                                               : String(localized: "Amount to 
request:"))
 
             let someCoins = SomeCoins(details: peerPullCheck)
             QuiteSomeCoins(someCoins: someCoins,
@@ -40,29 +39,24 @@ struct RequestPayment: View {
                             currency: currency,
                      amountEffective: peerPullCheck?.amountEffective)
 
-            HStack {
-                let disabled = amountToTransfer.isZero || someCoins.invalid || 
someCoins.tooMany
+            let disabled = amountToTransfer.isZero || someCoins.invalid || 
someCoins.tooMany
 
-                NavigationLink(destination: LazyView {
-                    RequestPurpose(stack: stack.push(),
-                        amountToTransfer: amountToTransfer,
-                                     fee: someCoins.fee,
-                                 summary: $summary,
-                              expireDays: $expireDays)
-//                        { deactivateAction() }
-                }) {
-                    Text("Request \(amountToTransfer.readableDescription)")    
 // TODO: formatter
-                }
+            NavigationLink(destination: LazyView {
+                RequestPurpose(stack: stack.push(),
+                    amountToTransfer: amountToTransfer,
+                                 fee: someCoins.fee,
+                             summary: $summary,
+                          expireDays: $expireDays)
+            }) { Text("Next") }
                 .buttonStyle(TalerButtonStyle(type: .prominent))
                 .disabled(disabled)
-            }
             Spacer()
         } } // ScrollVStack
         .frame(maxWidth: .infinity, alignment: .leading)
         .padding(.horizontal)
         .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all))
         .navigationTitle(navTitle)
-        .onAppear {   // make CurrencyField show the keyboard
+        .onAppear {
             DebugViewC.shared.setViewID(VIEW_REQUEST_P2P, stack: stack.push())
             symLog.log("❗️Yikes \(navTitle) onAppear")
         }
@@ -70,7 +64,9 @@ struct RequestPayment: View {
             symLog.log("❗️Yikes \(navTitle) onDisappear")
         }
         .task(id: amountToTransfer.value) {
-            if !amountToTransfer.isZero {
+            if amountToTransfer.isZero {
+//                fee = EMPTYSTRING
+            } else {
                 do {
                     let ppCheck = try await 
model.checkPeerPullCreditM(amountToTransfer, exchangeBaseUrl: nil)
                     peerPullCheck = ppCheck     // redraw
diff --git a/TalerWallet1/Views/Peer2peer/SendAmount.swift 
b/TalerWallet1/Views/Peer2peer/SendAmount.swift
index 7eef7c7..3088ff3 100644
--- a/TalerWallet1/Views/Peer2peer/SendAmount.swift
+++ b/TalerWallet1/Views/Peer2peer/SendAmount.swift
@@ -59,8 +59,7 @@ struct SendAmount: View {
                 .padding(.bottom, 2)
             CurrencyInputView(amount: $amountToTransfer,
                                title: iconOnly ? String(localized: "How much:")
-                                               : String(localized: "Amount to 
send:"),
-                       shortcutLabel: String(localized: "Send", comment: 
"VoiceOver: Send $50,$25,$10,$5 shortcut buttons"))
+                                               : String(localized: "Amount to 
send:"))
             let disabled = insufficient || amountToTransfer.isZero
             Text(insufficient ? insufficientLabel
                               : feeLabel)
@@ -73,6 +72,7 @@ struct SendAmount: View {
                   amountAvailable: amountAvailable,
                  amountToTransfer: amountToTransfer,
                               fee: fee,
+                     currencyInfo: currencyInfo,
                           summary: $summary,
                        expireDays: $expireDays)
             }) { Text("Next") }
diff --git a/TalerWallet1/Views/Peer2peer/SendPurpose.swift 
b/TalerWallet1/Views/Peer2peer/SendPurpose.swift
index 6d7c619..ba17c92 100644
--- a/TalerWallet1/Views/Peer2peer/SendPurpose.swift
+++ b/TalerWallet1/Views/Peer2peer/SendPurpose.swift
@@ -13,6 +13,7 @@ struct SendPurpose: View {
     let amountAvailable: Amount
     let amountToTransfer: Amount
     let fee: String
+    let currencyInfo: CurrencyInfo
     @Binding var summary: String
     @Binding var expireDays: UInt
     @AppStorage("iconOnly") var iconOnly: Bool = false
@@ -22,15 +23,23 @@ struct SendPurpose: View {
     @FocusState private var isFocused: Bool
 
     var body: some View {
+#if DEBUG
+        let _ = Self._printChanges()
+        let _ = symLog.vlog()       // just to get the # to compare it with 
.onAppear & onDisappear
+#endif
+        let currency = amountAvailable.currencyStr
+        let current = amountToTransfer.string(currencyInfo)
         ScrollView { VStack (spacing: 6) {
-            Text(amountToTransfer.readableDescription)              // TODO: 
curreny formatter
+            Text(current)
             Text("+ \(fee) payment fee")
                 .accessibilityFont(.body)
                 .foregroundColor(.red)
             VStack(alignment: .leading, spacing: 6) {
                 if !iconOnly {
-                    Text("Subject:")    // Purpose
+                    Text("Enter subject:")    // Purpose
                         .accessibilityFont(.title2)
+                        .accessibilityAddTraits(.isHeader)
+                        .accessibilityRemoveTraits(.isStaticText)
                         .padding(.top)
                 }
                 Group { if #available(iOS 16.0, *) {
@@ -74,7 +83,7 @@ struct SendPurpose: View {
                          expireDays: expireDays,
                  transactionStarted: $transactionStarted)
                 }) {
-                    Text("Send \(amountToTransfer.readableDescription) now", 
comment: "amountToTransfer")  // TODO: currency formatter
+                    Text("Send \(current) now", comment: "amountToTransfer")  
// TODO: currency formatter
                 }
                 .buttonStyle(TalerButtonStyle(type: .prominent))
                 .disabled(disabled)
@@ -82,7 +91,6 @@ struct SendPurpose: View {
 
                 Spacer()
             }
-            .textFieldStyle(.roundedBorder)
             .frame(maxWidth: .infinity, alignment: .leading)
             .padding(.horizontal)
         } } // ScrollVStack

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]