Started EnterTanDialog. Had to wrap rootViewController in a UINavigationController for that to be able to push a EnterTanDialog from every point in the application

This commit is contained in:
dankito 2020-07-24 00:44:25 +02:00
parent a7fedc4f05
commit c590c945a5
13 changed files with 364 additions and 41 deletions

View File

@ -7,6 +7,13 @@
objects = {
/* Begin PBXBuildFile section */
366FA4D824C46B160094F009 /* AutoCompleteList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4D724C46B160094F009 /* AutoCompleteList.swift */; };
366FA4DA24C472A90094F009 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4D924C472A90094F009 /* Extensions.swift */; };
366FA4DC24C479120094F009 /* BankInfoListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4DB24C479120094F009 /* BankInfoListItem.swift */; };
366FA4E024C4924A0094F009 /* RemitteeListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4DF24C4924A0094F009 /* RemitteeListItem.swift */; };
366FA4E224C4ED6C0094F009 /* EnterTanDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4E124C4ED6C0094F009 /* EnterTanDialog.swift */; };
366FA4E424C4F2C70094F009 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4E324C4F2C70094F009 /* AppState.swift */; };
366FA4E624C6EBF40094F009 /* EnterTanState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366FA4E524C6EBF40094F009 /* EnterTanState.swift */; };
36BCF85424BA0C54005BEC29 /* BankList.json in Resources */ = {isa = PBXBuildFile; fileRef = 36BCF85324BA0C54005BEC29 /* BankList.json */; };
36BCF85824BA4274005BEC29 /* BankingUiCommon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36BCF85524BA41EE005BEC29 /* BankingUiCommon.framework */; };
36BCF85924BA4274005BEC29 /* BankingUiCommon.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 36BCF85524BA41EE005BEC29 /* BankingUiCommon.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@ -32,6 +39,9 @@
36BCF89124C25971005BEC29 /* CoreDataBankingPersistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36BCF89024C25971005BEC29 /* CoreDataBankingPersistence.swift */; };
36BCF89324C25BC3005BEC29 /* Mapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36BCF89224C25BC3005BEC29 /* Mapper.swift */; };
36BCF89524C31F02005BEC29 /* AppData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36BCF89424C31F02005BEC29 /* AppData.swift */; };
36BE064F24C9A17F00CBBB68 /* ImageTanView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36BE064E24C9A17F00CBBB68 /* ImageTanView.swift */; };
36BE065724C9E04800CBBB68 /* UIKitImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36BE065624C9E04800CBBB68 /* UIKitImageView.swift */; };
36BE065924CA3CAB00CBBB68 /* UIKitSearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36BE065824CA3CAB00CBBB68 /* UIKitSearchBar.swift */; };
36E7BA1424B3D05C00757859 /* ViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36E7BA1324B3D05C00757859 /* ViewExtensions.swift */; };
36FC929C24B39A05002B12E9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FC929B24B39A05002B12E9 /* AppDelegate.swift */; };
36FC929E24B39A05002B12E9 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FC929D24B39A05002B12E9 /* SceneDelegate.swift */; };
@ -87,6 +97,13 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
366FA4D724C46B160094F009 /* AutoCompleteList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteList.swift; sourceTree = "<group>"; };
366FA4D924C472A90094F009 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
366FA4DB24C479120094F009 /* BankInfoListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BankInfoListItem.swift; sourceTree = "<group>"; };
366FA4DF24C4924A0094F009 /* RemitteeListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemitteeListItem.swift; sourceTree = "<group>"; };
366FA4E124C4ED6C0094F009 /* EnterTanDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterTanDialog.swift; sourceTree = "<group>"; };
366FA4E324C4F2C70094F009 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
366FA4E524C6EBF40094F009 /* EnterTanState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterTanState.swift; sourceTree = "<group>"; };
36BCF85324BA0C54005BEC29 /* BankList.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = BankList.json; path = ../../../tools/BankFinder/src/commonMain/resources/BankList.json; sourceTree = "<group>"; };
36BCF85524BA41EE005BEC29 /* BankingUiCommon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BankingUiCommon.framework; path = "../BankingUiCommon/build/xcode-frameworks/BankingUiCommon.framework"; sourceTree = "<group>"; };
36BCF85D24BA4DA8005BEC29 /* MultiplatformUtils.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MultiplatformUtils.framework; path = "../../common/build/xcode-frameworks/MultiplatformUtils.framework"; sourceTree = "<group>"; };
@ -107,6 +124,9 @@
36BCF89024C25971005BEC29 /* CoreDataBankingPersistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataBankingPersistence.swift; sourceTree = "<group>"; };
36BCF89224C25BC3005BEC29 /* Mapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mapper.swift; sourceTree = "<group>"; };
36BCF89424C31F02005BEC29 /* AppData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppData.swift; sourceTree = "<group>"; };
36BE064E24C9A17F00CBBB68 /* ImageTanView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTanView.swift; sourceTree = "<group>"; };
36BE065624C9E04800CBBB68 /* UIKitImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitImageView.swift; sourceTree = "<group>"; };
36BE065824CA3CAB00CBBB68 /* UIKitSearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitSearchBar.swift; sourceTree = "<group>"; };
36E7BA1324B3D05C00757859 /* ViewExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewExtensions.swift; sourceTree = "<group>"; };
36E7BA1824B9E70C00757859 /* xcode-frameworks */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "xcode-frameworks"; path = "../../tools/BankFinder/build/xcode-frameworks"; sourceTree = "<group>"; };
36FC929824B39A05002B12E9 /* BankingiOSApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BankingiOSApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -169,6 +189,9 @@
36BCF89024C25971005BEC29 /* CoreDataBankingPersistence.swift */,
36BCF89224C25BC3005BEC29 /* Mapper.swift */,
36BCF89424C31F02005BEC29 /* AppData.swift */,
366FA4E324C4F2C70094F009 /* AppState.swift */,
366FA4D924C472A90094F009 /* Extensions.swift */,
366FA4E524C6EBF40094F009 /* EnterTanState.swift */,
);
path = persistence;
sourceTree = "<group>";
@ -274,6 +297,7 @@
36BCF86D24BA691B005BEC29 /* DependencyInjector.swift */,
36BCF88824C0A7D7005BEC29 /* Message.swift */,
36BCF88E24C1DFF7005BEC29 /* SheetPresenter.swift */,
366FA4D724C46B160094F009 /* AutoCompleteList.swift */,
);
path = ui;
sourceTree = "<group>";
@ -287,6 +311,12 @@
36BCF88424C098C8005BEC29 /* BankAccountListItem.swift */,
36BCF88A24C0BD2D005BEC29 /* AccountTransactionsDialog.swift */,
36BCF88C24C1C1EA005BEC29 /* TransferMoneyDialog.swift */,
366FA4DB24C479120094F009 /* BankInfoListItem.swift */,
366FA4DF24C4924A0094F009 /* RemitteeListItem.swift */,
366FA4E124C4ED6C0094F009 /* EnterTanDialog.swift */,
36BE064E24C9A17F00CBBB68 /* ImageTanView.swift */,
36BE065624C9E04800CBBB68 /* UIKitImageView.swift */,
36BE065824CA3CAB00CBBB68 /* UIKitSearchBar.swift */,
);
path = views;
sourceTree = "<group>";
@ -425,7 +455,7 @@
/* Begin PBXShellScriptBuildPhase section */
36FC92D324B39E61002B12E9 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
buildActionMask = 12;
files = (
);
inputFileListPaths = (
@ -438,7 +468,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\n#cd \"../../common/build/xcode-frameworks/\"\n#./gradlew :common:packForXCode -PXCODE_CONFIGURATION=${CONFIGURATION}\n\n#cd \"../../fints4k/build/xcode-frameworks/\"\n#./gradlew :fints4k:packForXCode -PXCODE_CONFIGURATION=${CONFIGURATION}#\n\n#cd \"../../tools/BankFinder/build/xcode-frameworks/\"\n#./gradlew :BankFinder:packForXCode -PXCODE_CONFIGURATION=${CONFIGURATION}\n\ncd \"../../ui/BankingUiNativeIntegration/build/xcode-frameworks/\"\n./gradlew :BankingUiNativeIntegration:packForXCode -PXCODE_CONFIGURATION=${CONFIGURATION}\n";
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\n#cd \"../../common/build/xcode-frameworks/\"\n#./gradlew :common:packForXcode -PXCODE_CONFIGURATION=${CONFIGURATION}\n\n#cd \"../../fints4k/build/xcode-frameworks/\"\n#./gradlew :fints4k:packForXcode -PXCODE_CONFIGURATION=${CONFIGURATION}#\n\n#cd \"../../tools/BankFinder/build/xcode-frameworks/\"\n#./gradlew :BankFinder:packForXcode -PXCODE_CONFIGURATION=${CONFIGURATION}\n\ncd \"../../ui/BankingUiNativeIntegration/build/xcode-frameworks/\"\n./gradlew :BankingUiNativeIntegration:packForXcode -PXCODE_CONFIGURATION=${CONFIGURATION}\n";
};
/* End PBXShellScriptBuildPhase section */
@ -447,6 +477,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
36BE065924CA3CAB00CBBB68 /* UIKitSearchBar.swift in Sources */,
36BE064F24C9A17F00CBBB68 /* ImageTanView.swift in Sources */,
366FA4E224C4ED6C0094F009 /* EnterTanDialog.swift in Sources */,
36FC92DC24B3A4A0002B12E9 /* AccountsTab.swift in Sources */,
36BCF86E24BA691B005BEC29 /* DependencyInjector.swift in Sources */,
36BCF89124C25971005BEC29 /* CoreDataBankingPersistence.swift in Sources */,
@ -458,6 +491,7 @@
36BCF88D24C1C1EA005BEC29 /* TransferMoneyDialog.swift in Sources */,
36E7BA1424B3D05C00757859 /* ViewExtensions.swift in Sources */,
36BCF88924C0A7D7005BEC29 /* Message.swift in Sources */,
366FA4E024C4924A0094F009 /* RemitteeListItem.swift in Sources */,
36BCF86C24BA5E72005BEC29 /* DispatchQueueAsyncRunner.swift in Sources */,
36BCF86324BA5097005BEC29 /* SwiftUiRouter.swift in Sources */,
36BCF88F24C1DFF7005BEC29 /* SheetPresenter.swift in Sources */,
@ -465,7 +499,13 @@
36BCF88B24C0BD2D005BEC29 /* AccountTransactionsDialog.swift in Sources */,
36BCF87624BF114F005BEC29 /* UrlSessionWebClient.swift in Sources */,
36FC92A324B39A05002B12E9 /* ContentView.swift in Sources */,
366FA4E624C6EBF40094F009 /* EnterTanState.swift in Sources */,
36BE065724C9E04800CBBB68 /* UIKitImageView.swift in Sources */,
36BCF88724C0A310005BEC29 /* PreviewData.swift in Sources */,
366FA4DA24C472A90094F009 /* Extensions.swift in Sources */,
366FA4D824C46B160094F009 /* AutoCompleteList.swift in Sources */,
366FA4DC24C479120094F009 /* BankInfoListItem.swift in Sources */,
366FA4E424C4F2C70094F009 /* AppState.swift in Sources */,
36FC929E24B39A05002B12E9 /* SceneDelegate.swift in Sources */,
36BCF88524C098C8005BEC29 /* BankAccountListItem.swift in Sources */,
36FC92EF24B3BB81002B12E9 /* AddAccountDialog.swift in Sources */,
@ -646,6 +686,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"BankingiOSApp/Preview Content\"";
DEVELOPMENT_TEAM = 2L8U7W4R52;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = (
"../../common/build/xcode-frameworks/",
@ -661,7 +702,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = net.dankito.banking.ios.BankingiOSApp;
PRODUCT_BUNDLE_IDENTIFIER = net.dankito.banking.ios.BankingiOSApp.freeprovisioning;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@ -674,6 +715,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"BankingiOSApp/Preview Content\"";
DEVELOPMENT_TEAM = 2L8U7W4R52;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = (
"../../common/build/xcode-frameworks/",
@ -689,7 +731,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = net.dankito.banking.ios.BankingiOSApp;
PRODUCT_BUNDLE_IDENTIFIER = net.dankito.banking.ios.BankingiOSApp.freeprovisioning;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";

View File

@ -8,23 +8,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
setupDI()
return true
}
func setupDI() {
let appDataFolder = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, .userDomainMask, true).first
?? Bundle.main.resourceURL?.absoluteString ?? ""
let persistence = CoreDataBankingPersistence(persistentContainer: self.persistentContainer)
let dataFolder = URL(fileURLWithPath: "data", isDirectory: true, relativeTo: URL(fileURLWithPath: appDataFolder))
let presenter = BankingPresenterSwift(dataFolder: dataFolder, router: SwiftUiRouter(), webClient: UrlSessionWebClient(), persistence: persistence, asyncRunner: DispatchQueueAsyncRunner())
DependencyInjector.register(dependency: presenter)
}
// MARK: UISceneSession Lifecycle

View File

@ -1,5 +1,6 @@
"OK" = "OK";
"Cancel" = "Cancel";
"Add" = "Add";
@ -21,6 +22,7 @@
"Show transfer money dialog" = "Transfer money";
/* TransferMoneyDialog */
"Transfer Money Dialog Title" = "Überweisung";
"Remittee Name" = "Name";
"Remittee IBAN" = "IBAN";
@ -31,3 +33,12 @@
"Successfully transferred %@ %@ to %@." = "Successfully transferred %@ %@ to %@.";
"Could not transfer %@ %@ to %@. Error: %@." = "Could not transfer %@ %@ to %@.\n\nError message from your bank:\n\n%@";
/* EnterTanDialog */
"Enter TAN Dialog Title" = "Enter TAN";
"TAN procedure" = "TAN procedure";
"TAN medium" = "TAN medium";
"TAN hint from your bank:" = "Hint from your bank:";
"Enter TAN:" = "TAN";

View File

@ -1,5 +1,7 @@
import UIKit
import SwiftUI
import BankingUiSwift
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
@ -12,16 +14,32 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Get the managed object context from the shared persistent container.
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let appDataFolder = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, .userDomainMask, true).first
?? Bundle.main.resourceURL?.absoluteString ?? ""
let persistence = CoreDataBankingPersistence(context: context)
let dataFolder = URL(fileURLWithPath: "data", isDirectory: true, relativeTo: URL(fileURLWithPath: appDataFolder))
let presenter = BankingPresenterSwift(dataFolder: dataFolder, router: SwiftUiRouter(), webClient: UrlSessionWebClient(), persistence: persistence, remitteeSearcher: persistence, asyncRunner: DispatchQueueAsyncRunner())
DependencyInjector.register(dependency: persistence)
DependencyInjector.register(dependency: presenter)
// Create the SwiftUI view and set the context as the value for the managedObjectContext environment keyPath.
// Add `@Environment(\.managedObjectContext)` in the views that will need the context.
let contentView = ContentView().environment(\.managedObjectContext, context)
let contentView = ContentView()
.environment(\.managedObjectContext, context)
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
window.rootViewController = UINavigationController(rootViewController: UIHostingController(rootView: contentView))
self.window = window
window.makeKeyAndVisible()
}

View File

@ -1,5 +1,6 @@
"OK" = "OK";
"Cancel" = "Abbrechen";
"Add" = "Hinzufügen";
@ -21,6 +22,7 @@
"Show transfer money dialog" = "Überweisung";
/* TransferMoneyDialog */
"Transfer Money Dialog Title" = "Überweisung";
"Remittee Name" = "Name";
"Remittee IBAN" = "IBAN";
@ -31,3 +33,12 @@
"Successfully transferred %@ %@ to %@." = "%@ %@ wurden erfolgreich an %@ überwiesen.";
"Could not transfer %@ %@ to %@. Error: %@." = "Konnte nicht %@ %@ an %@ überweisen.\n\nFehlermeldung Ihrer Bank:\n\n%@";
/* EnterTanDialog */
"Enter TAN Dialog Title" = "TAN-Abfrage";
"TAN procedure" = "TAN Verfahren";
"TAN medium" = "TAN Medium";
"TAN hint from your bank:" = "Hinweis Ihrer Bank:";
"Enter TAN:" = "TAN";

View File

@ -0,0 +1,22 @@
import Foundation
import BankingUiSwift
class EnterTanState : Identifiable {
let id: Foundation.UUID = UUID()
let customer: Customer
let tanChallenge: TanChallenge
let callback: (EnterTanResult) -> Void
init(_ customer: Customer, _ tanChallenge: TanChallenge, _ callback: @escaping (EnterTanResult) -> Void) {
self.customer = customer
self.tanChallenge = tanChallenge
self.callback = callback
}
}

View File

@ -20,3 +20,10 @@ extension AccountTransaction : Identifiable {
public var id: UUID { UUID() }
}
extension TanProcedure : Identifiable {
public var id: String { self.bankInternalProcedureCode }
}

View File

@ -1,3 +1,4 @@
import SwiftUI
import BankingUiSwift
@ -9,9 +10,15 @@ class SwiftUiRouter : IRouter {
}
func getTanFromUserFromNonUiThread(customer: Customer, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: @escaping (EnterTanResult) -> Void) {
callback(EnterTanResult.Companion().userDidNotEnterTan())
if let rootViewController = UIApplication.shared.windows.first(where: { (window) -> Bool in window.isKeyWindow})?.rootViewController as? UINavigationController {
let enterTanState = EnterTanState(customer, tanChallenge, callback)
let enterTanDialogController = UIHostingController(rootView: EnterTanDialog(enterTanState))
rootViewController.pushViewController(enterTanDialogController, animated: true)
}
}
func getAtcFromUserFromNonUiThread(tanMedium: TanGeneratorTanMedium, callback: @escaping (EnterTanGeneratorAtcResult) -> Void) {
callback(EnterTanGeneratorAtcResult.Companion().userDidNotEnterAtc())
}

View File

@ -15,6 +15,23 @@ extension View {
.navigationBarTitle(title, displayMode: displayMode)
}
func customNavigationBarBackButton(onBackButtonPressed: @escaping () -> Void) -> some View {
return self
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: Button(action: onBackButtonPressed) {
HStack {
Image(systemName: "chevron.left")
.font(.headline)
.padding(.horizontal, 0)
Text("Cancel")
.padding(.leading, 0)
}
.edgesIgnoringSafeArea(.leading)
.padding(.leading, 0)
})
}
}

View File

@ -10,27 +10,24 @@ struct AccountsTab: View {
var body: some View {
NavigationView {
VStack {
if data.banks.isEmpty == false {
Form {
ForEach(data.banks) { bank in
BankListItem(bank: bank)
}
VStack {
if data.banks.isEmpty == false {
Form {
ForEach(data.banks) { bank in
BankListItem(bank: bank)
}
}
Spacer()
NavigationLink(destination: AddAccountDialog()) {
Text("Add account")
}
Spacer()
}
.navigationBarHidden(true)
.navigationBarTitle(Text("Accounts"), displayMode: .inline)
Spacer()
NavigationLink(destination: AddAccountDialog()) {
Text("Add account")
}
Spacer()
}
.hideNavigationBar()
}
}

View File

@ -0,0 +1,149 @@
import SwiftUI
import BankingUiSwift
struct EnterTanDialog: View {
@Environment(\.presentationMode) var presentation
private var state: EnterTanState
private var tanChallenge: TanChallenge
private var customer: Customer
@State private var selectedTanProcedureIndex: Int
private var customersTanProcdures: [TanProcedure] = []
@State private var selectedTanMediumIndex = 0
private var customersTanMedia: [TanMedium] = []
private var showSelectTanMediumView = false
private var showFlickerCodeTanView = false
private var showImageTanView = false
@State private var enteredTan = ""
@Inject private var presenter: BankingPresenterSwift
init(_ state: EnterTanState) {
self.state = state
self.tanChallenge = state.tanChallenge
self.customer = state.customer
self.customersTanProcdures = customer.supportedTanProcedures
_selectedTanProcedureIndex = State(initialValue: customer.supportedTanProcedures.firstIndex(of: tanChallenge.tanProcedure) ?? 0)
self.customersTanMedia = customer.tanMediaSorted
self.showSelectTanMediumView = true // TODO: use isOpticalTanProcedure && tanMedia.count > 1
self.showFlickerCodeTanView = tanChallenge is FlickerCodeTanChallenge
self.showImageTanView = tanChallenge is ImageTanChallenge
}
var body: some View {
Form {
Section {
Picker("TAN procedure", selection: $selectedTanProcedureIndex) {
ForEach(0 ..< self.customersTanProcdures.count) { index in
Text(self.customersTanProcdures[index].displayName)
}
}
if showSelectTanMediumView {
Picker("TAN medium", selection: $selectedTanMediumIndex) {
ForEach(0 ..< self.customersTanMedia.count) { index in
Text(self.customersTanMedia[index].displayName)
}
}
}
}
if showFlickerCodeTanView {
Text("Entschuldigen Sie, aber die Darstellung von Flicker Codes wird gegenwärtig noch nicht unterstützt (fauler Programmierer). Bitte wählen Sie ein anderes TAN Verfahren, im Notfall chipTAN manuell.")
}
if showImageTanView {
ImageTanView(self.tanChallenge as! ImageTanChallenge)
}
VStack {
HStack {
Text("TAN hint from your bank:")
Spacer()
}
HStack {
Text(tanChallenge.messageToShowToUser)
Spacer()
}
.padding(.top, 6)
}
.padding(.vertical)
Section {
TextField("Enter TAN:", text: $enteredTan)
}
Section {
HStack {
Spacer()
Button(action: { self.enteringTanDone() },
label: { Text("OK") })
.disabled(self.enteredTan.isEmpty)
Spacer()
}
}
}
.showNavigationBarTitle("Enter TAN Dialog Title")
.customNavigationBarBackButton {
self.sendEnterTanResult(EnterTanResult.Companion().userDidNotEnterTan())
}
}
func enteringTanDone() {
let companion = EnterTanResult.Companion()
let result = enteredTan.isEmpty ? companion.userDidNotEnterTan() : companion.userEnteredTan(enteredTan: enteredTan)
sendEnterTanResult(result)
}
func sendEnterTanResult(_ result: EnterTanResult) {
self.state.callback(result)
// TODO: if a TAN has been entered, check result if user has made a mistake and has to re-enter TAN
self.presentation.wrappedValue.dismiss()
}
}
struct EnterTanDialog_Previews: PreviewProvider {
static var previews: some View {
let customer = Customer(bankCode: "", customerId: "", password: "", finTsServerAddress: "")
customer.supportedTanProcedures = [
TanProcedure(displayName: "chipTAN optisch", type: .chiptanflickercode, bankInternalProcedureCode: ""),
TanProcedure(displayName: "chipTAN QR", type: .chiptanqrcode, bankInternalProcedureCode: ""),
TanProcedure(displayName: "Secure Super Duper Plus", type: .apptan, bankInternalProcedureCode: "")
]
customer.tanMedia = [
TanMedium(displayName: "EC-Karte mit Nummer 12345678", status: .available),
TanMedium(displayName: "Handy mit Nummer 0170 / 12345678", status: .available)
]
let tanChallenge = TanChallenge(messageToShowToUser: "Hier ist eine Nachricht deiner Bank, die dir die Welt erklaert", tanProcedure: customer.supportedTanProcedures[0])
let enterTanState = EnterTanState(customer, tanChallenge, { result in })
return EnterTanDialog(enterTanState)
}
}

View File

@ -0,0 +1,33 @@
import SwiftUI
import BankingUiSwift
struct ImageTanView: View {
private var tanChallenge: ImageTanChallenge
private var imageData: Data
init(_ tanChallenge: ImageTanChallenge) {
self.tanChallenge = tanChallenge
self.imageData = tanChallenge.image.imageBytesAsNSData()
}
var body: some View {
UIKitImageView(data: self.imageData)
}
}
struct ImageTanView_Previews: PreviewProvider {
static var previews: some View {
let tanChallenge = ImageTanChallenge(image: TanImage(mimeType: "image/png", imageBytes: KotlinByteArray(size: 0), decodingError: nil), messageToShowToUser: "", tanProcedure: TanProcedure(displayName: "", type: .phototan, bankInternalProcedureCode: ""))
return ImageTanView(tanChallenge)
}
}

View File

@ -0,0 +1,24 @@
import UIKit
import SwiftUI
struct UIKitImageView : UIViewRepresentable {
typealias UIViewType = UIImageView
let data: Data
func makeUIView(context: Context) -> UIImageView {
let imageView = UIImageView(image: UIImage(data: data))
imageView.contentMode = .scaleAspectFit
return imageView
}
func updateUIView(_ uiView: UIImageView, context: Context) {
}
}