diff options
author | Marc Stibane <marc@taler.net> | 2023-10-15 23:28:12 +0200 |
---|---|---|
committer | Marc Stibane <marc@taler.net> | 2023-10-15 23:28:12 +0200 |
commit | d45d020554bf1681c91b573767e170e0b5ea9ecb (patch) | |
tree | 3f47a9b5380d5f95b37d61a14db5362a433b77d4 | |
parent | f46596353ba8c26a1112030499943c2b13398af5 (diff) | |
download | taler-ios-d45d020554bf1681c91b573767e170e0b5ea9ecb.tar.gz taler-ios-d45d020554bf1681c91b573767e170e0b5ea9ecb.tar.bz2 taler-ios-d45d020554bf1681c91b573767e170e0b5ea9ecb.zip |
Button Layout
-rw-r--r-- | TalerWallet.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | TalerWallet1/Views/Balances/BalanceRowView.swift | 147 | ||||
-rw-r--r-- | TalerWallet1/Views/Balances/TwoRowButtons.swift | 14 | ||||
-rw-r--r-- | TalerWallet1/Views/Exchange/ExchangeSectionView.swift | 33 | ||||
-rw-r--r-- | TalerWallet1/Views/HelperViews/View+needVStack.swift | 32 |
5 files changed, 153 insertions, 79 deletions
diff --git a/TalerWallet.xcodeproj/project.pbxproj b/TalerWallet.xcodeproj/project.pbxproj index a30ede5..91e0346 100644 --- a/TalerWallet.xcodeproj/project.pbxproj +++ b/TalerWallet.xcodeproj/project.pbxproj @@ -169,6 +169,8 @@ 4E9796902A3765ED006F73BC /* AgePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E97968F2A3765ED006F73BC /* AgePicker.swift */; }; 4E983C292ADBDD3500FA9CC5 /* SingleAxisGeometryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E983C282ADBDD3500FA9CC5 /* SingleAxisGeometryReader.swift */; }; 4E983C2A2ADBDD3500FA9CC5 /* SingleAxisGeometryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E983C282ADBDD3500FA9CC5 /* SingleAxisGeometryReader.swift */; }; + 4E983C2C2ADC416800FA9CC5 /* View+needVStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E983C2B2ADC416800FA9CC5 /* View+needVStack.swift */; }; + 4E983C2D2ADC416800FA9CC5 /* View+needVStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E983C2B2ADC416800FA9CC5 /* View+needVStack.swift */; }; 4EA1ABBE29A3833A008821EA /* PublicConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EA1ABBD29A3833A008821EA /* PublicConstants.swift */; }; 4EA551252A2C923600FEC9A8 /* CurrencyInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EA551242A2C923600FEC9A8 /* CurrencyInputView.swift */; }; 4EAD117629F672FA008EDD0B /* KeyboardResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EAD117529F672FA008EDD0B /* KeyboardResponder.swift */; }; @@ -336,6 +338,7 @@ 4E9320462A164BC700A87B0E /* PaymentPurpose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaymentPurpose.swift; sourceTree = "<group>"; }; 4E97968F2A3765ED006F73BC /* AgePicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AgePicker.swift; sourceTree = "<group>"; }; 4E983C282ADBDD3500FA9CC5 /* SingleAxisGeometryReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleAxisGeometryReader.swift; sourceTree = "<group>"; }; + 4E983C2B2ADC416800FA9CC5 /* View+needVStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+needVStack.swift"; sourceTree = "<group>"; }; 4EA1ABBD29A3833A008821EA /* PublicConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicConstants.swift; sourceTree = "<group>"; }; 4EA551242A2C923600FEC9A8 /* CurrencyInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyInputView.swift; sourceTree = "<group>"; }; 4EAD117529F672FA008EDD0B /* KeyboardResponder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardResponder.swift; sourceTree = "<group>"; }; @@ -729,6 +732,7 @@ 4E5A88F42A38A4FD00072618 /* QRCodeDetailView.swift */, 4E6EDD862A363D8D0031D520 /* ListStyle.swift */, 4E983C282ADBDD3500FA9CC5 /* SingleAxisGeometryReader.swift */, + 4E983C2B2ADC416800FA9CC5 /* View+needVStack.swift */, 4EB095482989CBFE0043A8A1 /* TextFieldAlert.swift */, 4EBA82AA2A3EB2CA00E5F39A /* TransactionButton.swift */, 4EB095492989CBFE0043A8A1 /* AmountView.swift */, @@ -1031,6 +1035,7 @@ 4E3EAE252A990778009F1BE8 /* WithdrawAcceptDone.swift in Sources */, 4E3EAE262A990778009F1BE8 /* Transaction.swift in Sources */, 4E605DB72AB05E48002FB9A7 /* View+flippedDirection.swift in Sources */, + 4E983C2C2ADC416800FA9CC5 /* View+needVStack.swift in Sources */, 4E3EAE272A990778009F1BE8 /* WalletColors.swift in Sources */, 4E3EAE282A990778009F1BE8 /* BalancesListView.swift in Sources */, 4E3EAE292A990778009F1BE8 /* WalletBackendError.swift in Sources */, @@ -1135,6 +1140,7 @@ 4E5A88F72A3B9E5B00072618 /* WithdrawAcceptDone.swift in Sources */, 4EB095222989CBCB0043A8A1 /* Transaction.swift in Sources */, 4E605DB82AB05E48002FB9A7 /* View+flippedDirection.swift in Sources */, + 4E983C2D2ADC416800FA9CC5 /* View+needVStack.swift in Sources */, 4E9320432A14F6EA00A87B0E /* WalletColors.swift in Sources */, 4EB0955D2989CBFE0043A8A1 /* BalancesListView.swift in Sources */, 4EB095212989CBCB0043A8A1 /* WalletBackendError.swift in Sources */, diff --git a/TalerWallet1/Views/Balances/BalanceRowView.swift b/TalerWallet1/Views/Balances/BalanceRowView.swift index be6de61..129ea3d 100644 --- a/TalerWallet1/Views/Balances/BalanceRowView.swift +++ b/TalerWallet1/Views/Balances/BalanceRowView.swift @@ -5,93 +5,134 @@ import SwiftUI import taler_swift -/// This view shows the currency row in a currency section -/// [Send Coins] [Receive Coins] Balance +let SPACING = CGFloat(10) // space between the two buttons + +struct BalanceLabel: View { + let balanceTitle: String + let horizontal: Bool + let amountStr: String + let iconOnly: Bool + + var body: some View { + Group { // can either be horizontal (preferred) or vertical (if doesn't fit horizontally) + if !iconOnly { + Text(balanceTitle) + .accessibilityFont(.title2) + .foregroundColor(.secondary) + } + if horizontal { + Spacer(minLength: 0) + Text(amountStr) + .accessibilityFont(.title) + .monospacedDigit() + } else { HStack { + Spacer(minLength: 0) + Text(amountStr) + .accessibilityFont(.title) + .monospacedDigit() + } } + } + } +} struct BalanceButton: View { - let amount: Amount + let amountStr: String let rowAction: () -> Void + @AppStorage("iconOnly") var iconOnly: Bool = false var body: some View { + let balanceTitle = String(localized: "Balance:", comment: "Main view") Button(action: rowAction) { - HStack(alignment: .lastTextBaseline) { - Text("Balance:", comment: "Balance in main view") - .accessibilityFont(.title2) - .foregroundColor(iconOnly ? .clear : .secondary) // hide if iconOnly - Spacer() - Text(verbatim: "\(amount.valueStr)") // TODO: CurrencyFormatter? - .accessibilityFont(.title) - .monospacedDigit() + SingleAxisGeometryReader { width in + Group { + let balancesFont = TalerFont.uiFont(.title2) + let amountFont = TalerFont.uiFont(.title) + let titles = [(balanceTitle, balancesFont), + (amountStr, amountFont)] + let needVStack = !iconOnly && Self.needVStack(titles, width: width, spacing: SPACING, sameSize: false) + if needVStack { + VStack(alignment: .leading, spacing: 0) { + BalanceLabel(balanceTitle: balanceTitle, horizontal: false, amountStr: amountStr, iconOnly: iconOnly) + } + } else { + HStack(alignment: .lastTextBaseline, spacing: 0) { + BalanceLabel(balanceTitle: balanceTitle, horizontal: true, amountStr: amountStr, iconOnly: iconOnly) + } + } + } } - .accessibilityFont(.subheadline) } .disabled(false) - .accessibilityElement(children: /*@START_MENU_TOKEN@*/.ignore/*@END_MENU_TOKEN@*/) - .accessibilityLabel("Balance \(amount.readableDescription)") // TODO: CurrencyFormatter! .buttonStyle(TalerButtonStyle(type: iconOnly ? .plain : .balance, aligned: .trailing)) -// .background(Color.yellow) + .accessibilityElement(children: /*@START_MENU_TOKEN@*/.ignore/*@END_MENU_TOKEN@*/) + .accessibilityLabel("\(balanceTitle) \(amountStr)") // TODO: CurrencyFormatter! } } + +/// This view shows the currency row in a currency section +/// [Send Coins] [Receive Coins] Balance struct BalanceRowView: View { let amount: Amount let sendAction: () -> Void let recvAction: () -> Void let rowAction: () -> Void @Environment(\.sizeCategory) var sizeCategory + @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic + let sendTitle1 = String(localized: "Send", comment: "Top of button <Send Money>") let sendTitle2 = String(localized: "Money", comment: "Bottom of button <Send Money>") let requestTitle1 = String(localized: "Request", comment: "Top of button <Request Payment>") let requestTitle2 = String(localized: "Payment", comment: "Bottom of button <Request Payment>") - func needVStack(_ amount: Amount) -> Bool { - // Sizes: 320 (SE), 375 (X, Xs, 12, 13 mini), 390 (12,13,14), 414 (Plus, Max), 428 (Pro Max) - guard 350 < UIScreen.screenWidth else {return true} // always for iPhone SE 1st Gen - var count = amount.currencyStr.count -// print(sizeCategory) - switch sizeCategory { - case ContentSizeCategory.extraSmall: - count += 0 - case ContentSizeCategory.small: - count += 1 - case ContentSizeCategory.medium: - count += 2 - case ContentSizeCategory.large: - count += 3 - case ContentSizeCategory.extraLarge: - count += 4 - default: - count += 5 - } - return count > 9 - } - var body: some View { - VStack (alignment: .trailing) { - BalanceButton(amount: amount, rowAction: rowAction) - let sendTitle = sendTitle1 + "\n" + sendTitle2 - let requestTitle = requestTitle1 + "\n" + requestTitle2 - let twoRowButtons = TwoRowButtons(sendTitle: sendTitle, recvTitle: requestTitle, - lineLimit: 5, sendDisabled: amount.isZero, - sendAction: sendAction, recvAction: recvAction) - if needVStack(amount) { - VStack { twoRowButtons } - } else { - HStack { twoRowButtons } + SingleAxisGeometryReader { width in + VStack (alignment: .trailing) { + BalanceButton(amountStr: amount.valueStr, // TODO: CurrencyFormatter? + rowAction: rowAction) + let uiFont = TalerFont.uiFont(.title3) + let titles = [(requestTitle1, uiFont), (requestTitle2, uiFont), (sendTitle1, uiFont), (sendTitle2, uiFont)] + let sendTitle = sendTitle1 + "\n" + sendTitle2 + let requestTitle = requestTitle1 + "\n" + requestTitle2 + let twoRowButtons = TwoRowButtons(sendTitle: sendTitle, recvTitle: requestTitle, + lineLimit: 5, sendDisabled: amount.isZero, + sendAction: sendAction, recvAction: recvAction) + let _ = print("Screenwidth: \(UIScreen.screenWidth) Geometry: \(width) \(sizeCategory): \(sizeCategory)") + if Self.needVStack(titles, width: width, spacing: SPACING) { + VStack { twoRowButtons } + } else { + HStack(spacing: SPACING) { twoRowButtons } + } } + .accessibilityElement(children: .combine) } - .accessibilityElement(children: .combine) } } // MARK: - #if DEBUG struct BalanceRowView_Previews: PreviewProvider { static var previews: some View { + let test = try! Amount(fromString: TESTCURRENCY + ":1.23") + let demo = try! Amount(fromString: DEMOCURRENCY + ":1234.56") List { - BalanceRowView(amount: try! Amount(fromString: TESTCURRENCY + ":1234.56"), - sendAction: {}, recvAction: {}, rowAction: {}) - BalanceRowView(amount: try! Amount(fromString: DEMOCURRENCY + ":1234.56"), - sendAction: {}, recvAction: {}, rowAction: {}) + Section { + HStack(alignment: .lastTextBaseline) { + BalanceLabel(balanceTitle: "BalanceA:", horizontal: true, amountStr: test.valueStr, iconOnly: false) + .listRowSeparator(.hidden) + } + } + Section { + BalanceLabel(balanceTitle: "Balance:", horizontal: false, amountStr: demo.valueStr, iconOnly: false) + .listRowSeparator(.hidden) + } + Section { + BalanceButton(amountStr: demo.valueStr, rowAction: {}) + .listRowSeparator(.hidden) + } + Section { + BalanceRowView(amount: demo, sendAction: {}, recvAction: {}, rowAction: {}) + } + BalanceRowView(amount: test, sendAction: {}, recvAction: {}, rowAction: {}) } } } diff --git a/TalerWallet1/Views/Balances/TwoRowButtons.swift b/TalerWallet1/Views/Balances/TwoRowButtons.swift index 3d5014e..163b703 100644 --- a/TalerWallet1/Views/Balances/TwoRowButtons.swift +++ b/TalerWallet1/Views/Balances/TwoRowButtons.swift @@ -35,22 +35,16 @@ struct TwoRowButtons: View { struct TwoRowButtons_Previews: PreviewProvider { static var previews: some View { List { - VStack { - let amount = try! Amount(fromString: LONGCURRENCY + ":1234.56") - TwoRowButtons(sendTitle: "Send\n" + LONGCURRENCY, + TwoRowButtons(sendTitle: "Send\n" + TESTCURRENCY, recvTitle: "Receive\n" + LONGCURRENCY, - lineLimit: 0, sendDisabled: true, + lineLimit: 2, sendDisabled: true, sendAction: {}, recvAction: {}) - BalanceButton(amount: amount, rowAction: {}) - } - HStack { - let amount = try! Amount(fromString: DEMOCURRENCY + ":1234.56") + .listRowSeparator(.hidden) TwoRowButtons(sendTitle: "Send\n" + DEMOCURRENCY, recvTitle: "Receive\n" + DEMOCURRENCY, lineLimit: 2, sendDisabled: true, sendAction: {}, recvAction: {}) - BalanceButton(amount: amount, rowAction: {}) - } + .listRowSeparator(.hidden) } } } diff --git a/TalerWallet1/Views/Exchange/ExchangeSectionView.swift b/TalerWallet1/Views/Exchange/ExchangeSectionView.swift index 692e750..1a6c622 100644 --- a/TalerWallet1/Views/Exchange/ExchangeSectionView.swift +++ b/TalerWallet1/Views/Exchange/ExchangeSectionView.swift @@ -29,11 +29,6 @@ struct ExchangeRowView: View { let depositTitle = String(localized: "Deposit", comment: "Top of button <Deposit (currency)>") let withdrawTitle = String(localized: "Withdraw", comment: "Top of button <Withdraw (currency)>") - func needVStack(_ currency: String) -> Bool { - // Sizes: 320 (SE), 375 (X, Xs, 12, 13 mini), 390 (12,13,14), 414 (Plus, Max), 428 (Pro Max) - - return false - } var body: some View { let baseURL = exchange.exchangeBaseUrl @@ -54,16 +49,23 @@ struct ExchangeRowView: View { ) { EmptyView() }.frame(width: 0).opacity(0) }.listRowSeparator(.hidden) - let sendTitle = depositTitle + "\n" + currency // TODO: amount.currencyStr - let recvTitle = withdrawTitle + "\n" + currency // TODO: amount.currencyStr - let twoRowButtons = TwoRowButtons(sendTitle: sendTitle, recvTitle: recvTitle, - lineLimit: 5, sendDisabled: true, // TODO: amount.isZero - sendAction: { selectAndUpdate(1) }, - recvAction: { selectAndUpdate(2) }) - if needVStack(currency) { - VStack { twoRowButtons } - } else { - HStack { twoRowButtons } + SingleAxisGeometryReader { width in + Group { + let uiFont = TalerFont.uiFont(.title3) + let titles = [(depositTitle, uiFont), (withdrawTitle, uiFont), (currency, uiFont)] + let sendTitle = depositTitle + "\n" + currency // TODO: amount.currencyStr + let recvTitle = withdrawTitle + "\n" + currency // TODO: amount.currencyStr + let twoRowButtons = TwoRowButtons(sendTitle: sendTitle, recvTitle: recvTitle, + lineLimit: 5, sendDisabled: true, // TODO: amount.isZero + sendAction: { selectAndUpdate(1) }, + recvAction: { selectAndUpdate(2) }) + let spacing = CGFloat(10) // space between the two buttons + if Self.needVStack(titles, width: width, spacing: spacing) { + VStack { twoRowButtons } + } else { + HStack(spacing: spacing) { twoRowButtons } + } + } } } } @@ -76,7 +78,6 @@ struct ExchangeSectionView: View { // let amount: Amount let currency: String // TODO: amount.currencyStr let exchanges: [Exchange] - @Binding var centsToTransfer: UInt64 var body: some View { diff --git a/TalerWallet1/Views/HelperViews/View+needVStack.swift b/TalerWallet1/Views/HelperViews/View+needVStack.swift new file mode 100644 index 0000000..e71cf72 --- /dev/null +++ b/TalerWallet1/Views/HelperViews/View+needVStack.swift @@ -0,0 +1,32 @@ +/* + * This file is part of GNU Taler, ©2022-23 Taler Systems S.A. + * See LICENSE.md + */ +import SwiftUI +import UIKit + +extension View { + /// returns true if any of the strings in 'titles' wouldn't fit in a view 1/'numViews' the size of 'width', with 'spacing' + static func needVStack(_ titles: [(String, UIFont)], width: CGFloat, spacing: CGFloat, + sameSize: Bool = true, numViews: Int = 2) -> Bool { + let padding: CGFloat = 20 // TODO: depend on myListStyle + var maxTitleWidth: CGFloat = 0 + var totalWidth = padding + + for (title, uiFont) in titles { + let titleWidth = title.widthOfString(usingUIFont: uiFont) + if titleWidth > maxTitleWidth { + maxTitleWidth = titleWidth + } + totalWidth += titleWidth + } + + let neededWidth = padding + maxTitleWidth + let totalSpacing = spacing * CGFloat(numViews - 1) + let availableWidth = (width / CGFloat(numViews)) - totalSpacing + totalWidth += totalSpacing + + return sameSize ? neededWidth > availableWidth + : totalWidth > width + } +} |