diff --git a/Trust.xcodeproj/project.pbxproj b/Trust.xcodeproj/project.pbxproj index 61e565db4..afdac0c06 100644 --- a/Trust.xcodeproj/project.pbxproj +++ b/Trust.xcodeproj/project.pbxproj @@ -331,6 +331,7 @@ 5E7C776BE1B19F824954962D /* BaseTicketTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7F5C10E3895E805EA7E0 /* BaseTicketTableViewCell.swift */; }; 5E7C776CF721EBBD43195926 /* GenerateSellMagicLinkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C79CF6150E4CD4A276FC0 /* GenerateSellMagicLinkViewController.swift */; }; 5E7C7793AB6B577906F2BCA3 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7AFE9AF9FE6B58C925D4 /* SettingsViewController.swift */; }; + 5E7C77A8425E0AFAB11F1FCD /* PromptBackupCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7ADD0FBE8708A6E98AF8 /* PromptBackupCoordinator.swift */; }; 5E7C77AD9FAAC18211B6F355 /* TransferTicketsQuantitySelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7419F47CC8B2996AA8F9 /* TransferTicketsQuantitySelectionViewController.swift */; }; 5E7C77E844D710D7AFBC58D4 /* RequestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C74DCC21272EC231A20E2 /* RequestViewController.swift */; }; 5E7C783B4784DE76971EEBB4 /* StatusViewControllerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C7BD9B4BDAFC2D9EBD741 /* StatusViewControllerViewModel.swift */; }; @@ -859,6 +860,7 @@ 5E7C7A65F6033318F7C8AEB0 /* DateEntryField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateEntryField.swift; sourceTree = ""; }; 5E7C7AB3440C01136DF4F3E9 /* LockCreatePasscodeCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockCreatePasscodeCoordinator.swift; sourceTree = ""; }; 5E7C7ACB94CEE493AC37487F /* TicketRowView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TicketRowView.swift; sourceTree = ""; }; + 5E7C7ADD0FBE8708A6E98AF8 /* PromptBackupCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PromptBackupCoordinator.swift; sourceTree = ""; }; 5E7C7AE6FAE0DF969B4F52E9 /* ContactUsBannerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactUsBannerView.swift; sourceTree = ""; }; 5E7C7AF9A592D7224ED58016 /* OnboardingPageStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingPageStyle.swift; sourceTree = ""; }; 5E7C7AFE9AF9FE6B58C925D4 /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; @@ -1491,6 +1493,7 @@ isa = PBXGroup; children = ( 29DBF2A21F9DBFF400327C60 /* BackupCoordinator.swift */, + 5E7C7ADD0FBE8708A6E98AF8 /* PromptBackupCoordinator.swift */, ); path = Coordinators; sourceTree = ""; @@ -3592,6 +3595,7 @@ 5E7C75E5C64619ABFD246183 /* TransferTicketsViaWalletAddressViewController.swift in Sources */, 5E7C7EAEBB435F3909DA36FB /* TransferTicketsViaWalletAddressViewControllerViewModel.swift in Sources */, 5E7C7CCC8D376C6E5C245715 /* EthCurrencyHelper.swift in Sources */, + 5E7C77A8425E0AFAB11F1FCD /* PromptBackupCoordinator.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Trust/Export/Coordinators/PromptBackupCoordinator.swift b/Trust/Export/Coordinators/PromptBackupCoordinator.swift new file mode 100644 index 000000000..54b6d29ea --- /dev/null +++ b/Trust/Export/Coordinators/PromptBackupCoordinator.swift @@ -0,0 +1,54 @@ +// Copyright © 2018 Stormbird PTE. LTD. + +import UIKit + +protocol PromptBackupCoordinatorDelegate: class { + func viewControllerForPresenting(in coordinator: PromptBackupCoordinator) -> UIViewController? + func didFinish(in coordinator: PromptBackupCoordinator) +} + +class PromptBackupCoordinator: Coordinator { + var coordinators: [Coordinator] = [] + weak var delegate: PromptBackupCoordinatorDelegate? + + func start() { + let keystore = try! EtherKeystore() + guard let vc = delegate?.viewControllerForPresenting(in: self) else { + finish() + return + } + let coordinator = WalletCoordinator(keystore: keystore) + coordinator.delegate = self + let proceed = coordinator.start(.backupWallet) + guard proceed else { + finish() + return + } + vc.present(coordinator.navigationController, animated: true, completion: nil) + addCoordinator(coordinator) + } + + func finish() { + delegate?.didFinish(in: self) + } +} + +extension PromptBackupCoordinator: WalletCoordinatorDelegate { + func didFinish(with account: Wallet, in coordinator: WalletCoordinator) { + coordinator.navigationController.dismiss(animated: true, completion: nil) + removeCoordinator(coordinator) + finish() + } + + func didFail(with error: Error, in coordinator: WalletCoordinator) { + coordinator.navigationController.dismiss(animated: true, completion: nil) + removeCoordinator(coordinator) + finish() + } + + func didCancel(in coordinator: WalletCoordinator) { + coordinator.navigationController.dismiss(animated: true, completion: nil) + removeCoordinator(coordinator) + finish() + } +} diff --git a/Trust/InCoordinator.swift b/Trust/InCoordinator.swift index 52ed53268..c14d4d9f1 100644 --- a/Trust/InCoordinator.swift +++ b/Trust/InCoordinator.swift @@ -205,6 +205,23 @@ class InCoordinator: Coordinator { hideTitlesInTabBarController(tabBarController: tabBarController) showTab(inCoordinatorViewModel.initialTab) + + + let etherToken = TokensDataStore.etherToken(for: config) + tokensStorage.tokensModel.subscribe {[weak self] tokensModel in + guard let tokens = tokensModel, let eth = tokens.first(where: { $0 == etherToken }) else { + return + } + guard let balance = BigInt(eth.value), !(balance.isZero) else { return } + self?.promptBackupWallet() + } + } + + private func promptBackupWallet() { + let coordinator = PromptBackupCoordinator() + addCoordinator(coordinator) + coordinator.delegate = self + coordinator.start() } private func hideTitlesInTabBarController(tabBarController: UITabBarController) { @@ -548,3 +565,12 @@ extension InCoordinator: PaymentCoordinatorDelegate { } } +extension InCoordinator: PromptBackupCoordinatorDelegate { + func viewControllerForPresenting(in coordinator: PromptBackupCoordinator) -> UIViewController? { + return navigationController + } + + func didFinish(in coordinator: PromptBackupCoordinator) { + removeCoordinator(coordinator) + } +} diff --git a/Trust/Market/Coordinators/UniversalLinkCoordinator.swift b/Trust/Market/Coordinators/UniversalLinkCoordinator.swift index d9abb4f8b..07bc1e8fa 100644 --- a/Trust/Market/Coordinators/UniversalLinkCoordinator.swift +++ b/Trust/Market/Coordinators/UniversalLinkCoordinator.swift @@ -261,6 +261,14 @@ class UniversalLinkCoordinator: Coordinator { private func showImportSuccessful() { updateImportTicketController(with: .succeeded) + promptBackupWallet() + } + + private func promptBackupWallet() { + let coordinator = PromptBackupCoordinator() + addCoordinator(coordinator) + coordinator.delegate = self + coordinator.start() } private func showImportError(errorMessage: String) { @@ -317,3 +325,13 @@ extension UniversalLinkCoordinator: ImportTicketViewControllerDelegate { } } } + +extension UniversalLinkCoordinator: PromptBackupCoordinatorDelegate { + func viewControllerForPresenting(in coordinator: PromptBackupCoordinator) -> UIViewController? { + return delegate?.viewControllerForPresenting(in: self) + } + + func didFinish(in coordinator: PromptBackupCoordinator) { + removeCoordinator(coordinator) + } +} diff --git a/Trust/Settings/Types/Config.swift b/Trust/Settings/Types/Config.swift index 822da0f4c..db2a09658 100644 --- a/Trust/Settings/Types/Config.swift +++ b/Trust/Settings/Types/Config.swift @@ -10,6 +10,7 @@ struct Config { static let isDebugEnabled = "isDebugEnabled" static let currencyID = "currencyID" static let dAppBrowser = "dAppBrowser" + static let walletAddressesAlreadyPromptedForBackUp = "walletAddressesAlreadyPromptedForBackUp " } let defaults: UserDefaults @@ -97,4 +98,33 @@ struct Config { }() return URL(string: urlString)! } + + var walletAddressesAlreadyPromptedForBackUp: [String] { + if let addresses = defaults.array(forKey: Keys.walletAddressesAlreadyPromptedForBackUp) { + return addresses as! [String] + } else { + return [] + } + } + + func addToWalletAddressesAlreadyPromptedForBackup(address: String) { + var addresses: [String] + if let value = defaults.array(forKey: Keys.walletAddressesAlreadyPromptedForBackUp) { + addresses = value as! [String] + } else { + addresses = [String]() + } + addresses.append(address) + defaults.setValue(addresses, forKey: Keys.walletAddressesAlreadyPromptedForBackUp) + } + + func isWalletAddresseAlreadyPromptedForBackUp(address: String) -> Bool { + if let value = defaults.array(forKey: Keys.walletAddressesAlreadyPromptedForBackUp) { + let addresses = value as! [String] + return addresses.contains(address) + } else { + return false + } + } + } diff --git a/Trust/Wallet/Coordinators/InitialWalletCreationCoordinator.swift b/Trust/Wallet/Coordinators/InitialWalletCreationCoordinator.swift index 12a2f137e..4e63b908b 100644 --- a/Trust/Wallet/Coordinators/InitialWalletCreationCoordinator.swift +++ b/Trust/Wallet/Coordinators/InitialWalletCreationCoordinator.swift @@ -33,6 +33,8 @@ class InitialWalletCreationCoordinator: Coordinator { showCreateWallet() case .importWallet: presentImportWallet() + case .backupWallet: + break } } diff --git a/Trust/Wallet/Coordinators/WalletCoordinator.swift b/Trust/Wallet/Coordinators/WalletCoordinator.swift index 6026bbf49..c68bb7dd4 100644 --- a/Trust/Wallet/Coordinators/WalletCoordinator.swift +++ b/Trust/Wallet/Coordinators/WalletCoordinator.swift @@ -26,7 +26,8 @@ class WalletCoordinator: Coordinator { self.keystore = keystore } - func start(_ entryPoint: WalletEntryPoint) { + //Return true if proceed + func start(_ entryPoint: WalletEntryPoint) -> Bool { self.entryPoint = entryPoint switch entryPoint { case .welcome: @@ -41,7 +42,16 @@ class WalletCoordinator: Coordinator { navigationController.viewControllers = [controller] case .createInstantWallet: createInstantWallet() + case .backupWallet: + if let type = keystore.recentlyUsedWallet?.type, case let .real(account) = type { + guard !Config().isWalletAddresseAlreadyPromptedForBackUp(address: account.address.eip55String) else { return false } + Config().addToWalletAddressesAlreadyPromptedForBackup(address: account.address.eip55String) + pushBackup(for: account) + } else { + return false + } } + return true } func pushImportWallet() { diff --git a/Trust/Wallet/Types/WalletEntryPoint.swift b/Trust/Wallet/Types/WalletEntryPoint.swift index 7c345fae0..37ec3bdb5 100644 --- a/Trust/Wallet/Types/WalletEntryPoint.swift +++ b/Trust/Wallet/Types/WalletEntryPoint.swift @@ -6,4 +6,5 @@ enum WalletEntryPoint { case welcome case createInstantWallet case importWallet + case backupWallet }