taler-ios

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

commit 90c1ac10f9b7236cd98150879def6b00b3064f3c
parent ae7a063131582f96b70d6eb6e6dd4436581c767e
Author: Marc Stibane <marc@taler.net>
Date:   Fri, 19 Jan 2024 08:40:51 +0100

Restrictions

Diffstat:
MTalerWallet.xcodeproj/project.pbxproj | 33+++++++++++++++++++++++++++++++++
MTalerWallet1/Views/Transactions/ManualDetailsV.swift | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
2 files changed, 121 insertions(+), 42 deletions(-)

diff --git a/TalerWallet.xcodeproj/project.pbxproj b/TalerWallet.xcodeproj/project.pbxproj @@ -234,6 +234,9 @@ 4ED2F94B2A278F5100453B40 /* ThreeAmountsV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ED2F94A2A278F5100453B40 /* ThreeAmountsV.swift */; }; 4EDBDCD92AB787CB00925C02 /* CallStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EDBDCD82AB787CB00925C02 /* CallStack.swift */; }; 4EDBDCDA2AB787CB00925C02 /* CallStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EDBDCD82AB787CB00925C02 /* CallStack.swift */; }; + 4EE171882B49635800BF9FF5 /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = 4EE171872B49635800BF9FF5 /* MarkdownUI */; }; + 4EE171902B49FE2B00BF9FF5 /* OrderedCollections in Frameworks */ = {isa = PBXBuildFile; productRef = 4EE1718F2B49FE2B00BF9FF5 /* OrderedCollections */; }; + 4EE171922B49FE4E00BF9FF5 /* OrderedCollections in Frameworks */ = {isa = PBXBuildFile; productRef = 4EE171912B49FE4E00BF9FF5 /* OrderedCollections */; }; 4EEC157329F8242800D46A03 /* QRGeneratorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EEC157229F8242800D46A03 /* QRGeneratorView.swift */; }; 4EEC157629F8ECBF00D46A03 /* CodeScanner in Frameworks */ = {isa = PBXBuildFile; productRef = 4EEC157529F8ECBF00D46A03 /* CodeScanner */; }; 4EEC157829F9032900D46A03 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EEC157729F9032900D46A03 /* Sheet.swift */; }; @@ -427,7 +430,9 @@ 4E3EAE772A990778009F1BE8 /* AnyCodable in Frameworks */, 4E3EAE782A990778009F1BE8 /* SymLog in Frameworks */, 4E3EAE792A990778009F1BE8 /* FTalerWalletcore.framework in Frameworks */, + 4EE171882B49635800BF9FF5 /* MarkdownUI in Frameworks */, 4E3EAE7A2A990778009F1BE8 /* taler-swift in Frameworks */, + 4EE171922B49FE4E00BF9FF5 /* OrderedCollections in Frameworks */, 4E3EAE7B2A990778009F1BE8 /* CodeScanner in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -441,6 +446,7 @@ 4EB094F829897CA20043A8A1 /* FTalerWalletcore.framework in Frameworks */, 4E2D8DD32B3F513800234039 /* MarkdownUI in Frameworks */, ABC13AA32859962800D23185 /* taler-swift in Frameworks */, + 4EE171902B49FE2B00BF9FF5 /* OrderedCollections in Frameworks */, 4EEC157629F8ECBF00D46A03 /* CodeScanner in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -849,6 +855,8 @@ 4E3EAE162A990778009F1BE8 /* AnyCodable */, 4E3EAE182A990778009F1BE8 /* SymLog */, 4E3EAE1A2A990778009F1BE8 /* CodeScanner */, + 4EE171872B49635800BF9FF5 /* MarkdownUI */, + 4EE171912B49FE4E00BF9FF5 /* OrderedCollections */, ); productName = Taler; productReference = 4E3EAE892A990778009F1BE8 /* GNU_Taler.app */; @@ -874,6 +882,7 @@ 4EB094FC29897D280043A8A1 /* SymLog */, 4EEC157529F8ECBF00D46A03 /* CodeScanner */, 4E2D8DD22B3F513800234039 /* MarkdownUI */, + 4EE1718F2B49FE2B00BF9FF5 /* OrderedCollections */, ); productName = Taler; productReference = D14AFD1D24D232B300C51073 /* Taler_Wallet.app */; @@ -955,6 +964,7 @@ 4EB094FB29897D280043A8A1 /* XCRemoteSwiftPackageReference "SymLog" */, 4EEC157429F8ECBF00D46A03 /* XCRemoteSwiftPackageReference "CodeScanner" */, 4E2D8DD12B3F513800234039 /* XCRemoteSwiftPackageReference "swift-markdown-ui-standalone" */, + 4EE1718C2B49EB7200BF9FF5 /* XCRemoteSwiftPackageReference "swift-collections" */, ); productRefGroup = D14AFD1E24D232B300C51073 /* Products */; projectDirPath = ""; @@ -1741,6 +1751,14 @@ minimumVersion = 0.1.0; }; }; + 4EE1718C2B49EB7200BF9FF5 /* XCRemoteSwiftPackageReference "swift-collections" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Fesh-com/swift-collections"; + requirement = { + branch = main; + kind = branch; + }; + }; 4EEC157429F8ECBF00D46A03 /* XCRemoteSwiftPackageReference "CodeScanner" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/twostraws/CodeScanner"; @@ -1789,6 +1807,21 @@ package = 4EB094FB29897D280043A8A1 /* XCRemoteSwiftPackageReference "SymLog" */; productName = SymLog; }; + 4EE171872B49635800BF9FF5 /* MarkdownUI */ = { + isa = XCSwiftPackageProductDependency; + package = 4E2D8DD12B3F513800234039 /* XCRemoteSwiftPackageReference "swift-markdown-ui-standalone" */; + productName = MarkdownUI; + }; + 4EE1718F2B49FE2B00BF9FF5 /* OrderedCollections */ = { + isa = XCSwiftPackageProductDependency; + package = 4EE1718C2B49EB7200BF9FF5 /* XCRemoteSwiftPackageReference "swift-collections" */; + productName = OrderedCollections; + }; + 4EE171912B49FE4E00BF9FF5 /* OrderedCollections */ = { + isa = XCSwiftPackageProductDependency; + package = 4EE1718C2B49EB7200BF9FF5 /* XCRemoteSwiftPackageReference "swift-collections" */; + productName = OrderedCollections; + }; 4EEC157529F8ECBF00D46A03 /* CodeScanner */ = { isa = XCSwiftPackageProductDependency; package = 4EEC157429F8ECBF00D46A03 /* XCRemoteSwiftPackageReference "CodeScanner" */; diff --git a/TalerWallet1/Views/Transactions/ManualDetailsV.swift b/TalerWallet1/Views/Transactions/ManualDetailsV.swift @@ -3,6 +3,7 @@ * See LICENSE.md */ import SwiftUI +import OrderedCollections import taler_swift struct AccountPicker: View { @@ -34,6 +35,39 @@ struct AccountPicker: View { } } +struct TransferRestrictionsV: View { + let amountStr: String + let obtainStr: String + let restrictions: [AccountRestriction]? + + @AppStorage("iconOnly") var iconOnly: Bool = false + + @State private var selectedLanguage = Locale.preferredLanguageCode + + var body: some View { + VStack(alignment: .leading) { + Text(iconOnly ? "Transfer \(amountStr) to the Exchange." + : "You need to transfer \(amountStr) from your regular bank account to the Exchange to receive \(obtainStr) as electronic cash in this wallet.") + .multilineTextAlignment(.leading) + if let restrictions { + ForEach(restrictions) { restriction in + if let hintsI18 = restriction.human_hint_i18n { +// let sortedDict = OrderedDictionary(uniqueKeys: hintsI18.keys, values: hintsI18.values) +// var sorted: OrderedDictionary<String:String> + let sortedDict = OrderedDictionary(uncheckedUniqueKeysWithValues: hintsI18.sorted { $0.key < $1.key }) + Picker("Restriction:", selection: $selectedLanguage) { + ForEach(sortedDict.keys, id: \.self) { + Text(sortedDict[$0] ?? "missing hint") + } + } + } else if let hint = restriction.human_hint { + Text(hint) + } + } + } + } + } +} struct ManualDetailsV: View { var common : TransactionCommon @@ -52,58 +86,68 @@ struct ManualDetailsV: View { var body: some View { if let accountDetails = details.exchangeCreditAccountDetails { + if !iconOnly { + Text("The Exchange is waiting for your wire-transfer.") + .multilineTextAlignment(.leading) + .listRowSeparator(.hidden) + } AccountPicker(title: String(localized: "Bank"), value: accountID, accountDetails: accountDetails, action: redraw) let account = accountDetails[accountID] let payto = account.paytoUri let payURL = URL(string: payto) let iban = payURL?.iban ?? "unknown IBAN" - let amountStr = account.transferAmount.readableDescription // TODO: formatter + let amountStr = account.transferAmount.readableDescription // TODO: formatter? let obtainStr = common.amountRaw.readableDescription + + let cryptocode = HStack { + Text(details.reservePub) + .monospacedDigit() + .accessibilityLabel("Cryptocode") + Spacer() + CopyButton(textToCopy: details.reservePub, vertical: true) + .accessibilityLabel("Copy the cryptocode") + .disabled(false) + } .padding(.leading) + let ibanCode = HStack { + Text(iban) + .monospacedDigit() + .accessibilityLabel("IBAN of the exchange") + Spacer() + CopyButton(textToCopy: iban, vertical: true) + .accessibilityLabel("Copy the IBAN") + .disabled(false) + } .padding(.leading) + .padding(.top, -8) + + let step1 = Text(iconOnly ? "**Step 1:** Copy+Paste this subject:" + : "**Step 1:** Copy this code and paste it into the subject/purpose field in your banking app or bank website:") + .multilineTextAlignment(.leading) + let mandatory = Text("This is mandatory, otherwise your money will not arrive in this wallet.") + .bold() + .multilineTextAlignment(.leading) + .listRowSeparator(.hidden) + let step2 = Text(iconOnly ? "**Step 2:** Copy+Paste this IBAN:" + : "**Step 2:** If you don't already have it in your banking favourites list, then copy and paste this IBAN into the receiver IBAN field in your banking app or website (and save it as favourite for the next time):") + .multilineTextAlignment(.leading) + .padding(.top) + let step3 = Text(iconOnly ? "**Step 3:** Transfer \(amountStr)." + : "**Step 3:** Finish the wire transfer of \(amountStr) in your banking app or website, then this withdrawal will proceed automatically.") + .multilineTextAlignment(.leading) + .padding(.top) Group { - Text(iconOnly ? "Transfer \(amountStr) to the Exchange." - : "You need to transfer \(amountStr) from your regular bank account to the Exchange to receive \(obtainStr) as electronic cash in this wallet.") - Text(iconOnly ? "**Step 1:** Copy+Paste this subject:" - : "**Step 1:** Copy this code and paste it into the subject/purpose field in your banking app or bank website:") - .multilineTextAlignment(.leading) - .listRowSeparator(.hidden) + TransferRestrictionsV(amountStr: amountStr, + obtainStr: obtainStr, + restrictions: account.creditRestrictions) + .listRowSeparator(.visible) + step1.listRowSeparator(.hidden) if !iconOnly { - Text("This is mandatory, otherwise your money will not arrive in this wallet.") - .bold() - .multilineTextAlignment(.leading) - .listRowSeparator(.hidden) + mandatory } - HStack { - Text(details.reservePub) - .monospacedDigit() - .accessibilityLabel("Cryptocode") - Spacer() - CopyButton(textToCopy: details.reservePub, vertical: true) - .accessibilityLabel("Copy the cryptocode") - .disabled(false) - } .padding(.leading) - .listRowSeparator(.hidden) - Text(iconOnly ? "**Step 2:** Copy+Paste this IBAN:" - : "**Step 2:** If you don't already have it in your banking favourites list, then copy and paste this IBAN into the receiver IBAN field in your banking app or website (and save it as favourite for the next time):") - .multilineTextAlignment(.leading) - .padding(.top) - .listRowSeparator(.hidden) - HStack { - Text(iban) - .monospacedDigit() - .accessibilityLabel("IBAN of the exchange") - Spacer() - CopyButton(textToCopy: iban, vertical: true) - .accessibilityLabel("Copy the IBAN") - .disabled(false) - } .padding(.leading) - .padding(.top, -8) - .listRowSeparator(.hidden) - Text(iconOnly ? "**Step 3:** Transfer \(amountStr)." - : "**Step 3:** Finish the wire transfer of \(amountStr) in your banking app or website, then this withdrawal will proceed automatically.") - .multilineTextAlignment(.leading) - .padding(.top) - .listRowSeparator(.visible) + cryptocode.listRowSeparator(.hidden) + step2.listRowSeparator(.hidden) + ibanCode.listRowSeparator(.hidden) + step3.listRowSeparator(.visible) Text(iconOnly ? "**Alternative:** Use this PayTo-Link:" : "**Alternative:** If your bank already supports PayTo, you can use this PayTo-Link instead:") .multilineTextAlignment(.leading) @@ -121,6 +165,8 @@ struct ManualDetailsV: View { } .listRowSeparator(.automatic) }.id(listID) .accessibilityFont(.body) + } else { + // YIKES No exchangeCreditAccountDetails } } }