// // MainControllerRoot.swift // List // // Created by Saveliy Stavitsky on 7/14/20. // Copyright © 2020 Igor Danich. All rights reserved. // import UIKit import Branch import Alamofire import WebKit import WalletKit import WalletFoundation import Combine import RealmSwift extension UserDefaults { @objc dynamic var chatsReadCount: [String: Int] { return (dictionary(forKey: "chatsReadCount") as? [String: Int]) ?? [:] } } extension UIViewController { // swiftlint:disable force_cast var mainController: MainController { UIApplication.shared.windows.first?.rootViewController as! MainController } } final class MainController: UIViewController { @IBOutlet var headerView: UIView! @IBOutlet var accountButton: UIButton! @IBOutlet var accountBarButton: UIBarButtonItem! @IBOutlet var backButton: UIButton! @IBOutlet var barNav: UINavigationBar! @IBOutlet weak var resourcesSwitch: CommonSwitch! @IBOutlet private weak var resourcesBtn: UIBarButtonItem! @IBOutlet weak var settingsGearButton: UIBarButtonItem! @IBOutlet private weak var offset: NSLayoutConstraint! @IBOutlet var inviteView: MainViewInvite! private lazy var interfaceCover: UIView = { let view = UIView() view.backgroundColor = Asset.snow.color view.frame = self.view.bounds return view }() private let service = Main.Service() private var notificationTokens = [NotificationToken]() private var cancellables = Set() private var hasTitle: Bool { guard let barNavItems = self.barNav.items else { return false } let titlesOfItems = barNavItems.compactMap { $0.title } return !titlesOfItems.isEmpty } var content: MainControllerContent { self.child()! } let timerFreeTx = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { timer in timer.tolerance = 0.5 Accounts().fetchQuota() } let timerBalances = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true) { timer in timer.tolerance = 0.2 if Wallet.Service.Tokens.shared.balances.collection.count == 0 { Wallet.Service.Tokens.shared.balances.fetch() } else { timer.invalidate() } } override func viewDidLoad() { super.viewDidLoad() self.accountBarButton.customView = self.accountButton self.headerView.layer.shadowColor = Asset.lightGray.color.cgColor self.configureAccountButton() self.configureQRButton() self.inviteView.changeVisibility(Accounts().hasActiveAccounts) self.updateMsgCount() // if !UserDefaults.standard.bool(forKey: "isFreeTransactionsOn") { // changeFreeSwitchState() // } // Network.shared.onReabilityChange = { } self.view.addSubview(self.interfaceCover) Loader.show() Accounts().messageShelf.activeBook?.fetch() Account.Service.Authorize.shared.updateAuthPublisher .sink { [weak self] in guard let self else { return } self.setupSubscriptions() guard let link = self.deepLink else { return } self.process(deepLink: link) self.deepLink = nil } .store(in: &self.cancellables) NotificationCenter.default.publisher(for: .didUpdateAccountQuota) .sink { [weak self] _ in guard let self else { return } self.configureResourcesSwitch() } .store(in: &self.cancellables) NotificationCenter.default.publisher(for: .didUpdateReachability) .sink { _ in guard !Network.Service().isReachable else { return } Alert.error(text: L10n.Main.NoInternet.text) } .store(in: &self.cancellables) self.inviteView.didLockedFunds = { [weak self] in self?.content.push(P2PLockedFundsController(), animated: true) } // Notification.subscribe(name: .didChangeAccount) { [weak self] _ in // P2PMainLockedFundsService.shared.fetch { // // if P2P.Service.balances.collection. // if P2PMyDealsService.shared.deals.count > 0 || P2PMyOrdersService.shared.orders.count > 0 { // self?.inviteView.lockedFundsView.isHidden = false // let msg = P2PMyOrdersService.shared.orders // .reduce("", { $0 + "Order: \($1.id):\($1.volume_balance)" }) // + P2PMyDealsService.shared.deals // .reduce("", { $0 + "Deal: \($1.id):\($1.volume)" }) // self?.inviteView.lockedFundsLabel.attributedText = msg.attributed // .applying(attribute: .font, value: FontFamily.GolosUI.medium.font(size: 20)) // .applying(attribute: .foregroundColor, value: Asset.textSnow.color) // self?.inviteView.lockedFundsLabel.speed = .rate(20.0) // } else { // self?.inviteView.lockedFundsView.isHidden = true // } // } // } self.resourcesBtn.customView = self.resourcesSwitch self.resourcesSwitch.isSelected = Accounts().quota.isEnabled Accounts().activePublisher .sink { [weak self] _ in guard let self else { return } self.notificationTokens.removeAll() self.notificationTokens.append(contentsOf: [ self.service.p2pBalancesService.balances.observe(on: .main) { [weak self] _ in Wallet.Service.Tokens.shared.balances.fetch() if (self?.service.p2pBalancesService.balances.filter("amount > 0 || blockedAmount > 0").count ?? 0) > 0 { self?.inviteView.lockedFundsView.isHidden = false let msg = L10n.P2p.Main.LockedFunds.headerTitle + (self?.service.p2pBalancesService.balances.filter("amount > 0 || blockedAmount > 0") .reduce("", { $0 + " \(($1.amount.decimalValue + $1.blockedAmount.decimalValue).toString(max: 5)) \($1.symbol) " }) ?? "") + " " self?.inviteView.lockedFundsLabel.attributedText = msg.attributed .applying(attribute: .font, value: FontFamily.GolosUI.medium.font(size: 20)) .applying(attribute: .foregroundColor, value: Asset.textSnow.color) self?.inviteView.lockedFundsLabel.speed = .rate(20.0) } else { self?.inviteView.lockedFundsView.isHidden = true } } ].compactMap { $0 }) } .store(in: &self.cancellables) Accounts().activePublisher .sink { [weak self] _ in Accounts().fetchQuota() self?.onAccountChange() } .store(in: &self.cancellables) Accounts().lockedPublisher .sink { [weak self] _ in self?.onAccountChange() } .store(in: &self.cancellables) Account.Service.Update.shared.updatePublisher .receive(on: DispatchQueue.main) .sink { [weak self] _ in self?.onAccountChange() } .store(in: &self.cancellables) // TODO: - Here we need handle update notifications // Notification.subscribe(name: .socketDidUpdateValue) { [weak self] in // print($0) // print("\(Date()) - socket update") // } NotificationCenter.default.publisher(for: .didUpdateHistory) .sink { [weak self] in guard let username = Accounts().current?.name, username == $0.userInfo?["username"] as? String else { return } Wallet.Service.Tokens.shared.balances.fetch() self?.updateMsgCount() } .store(in: &self.cancellables) UserDefaults.standard .publisher(for: \.chatsReadCount, options: [.initial, .new]) .sink { [weak self] _ in guard let self else { return } guard let username = Accounts().current?.name else { self.setChatsBadge(count: 0) return } self.setChatsBadge(count: self.chatsMsgsCount(username: username) - self.chatsRead(by: username)) } .store(in: &self.cancellables) self.inviteView.didClose = { [weak self] in self?.inviteView.isHidden = true } } func chatsRead(by username: String) -> Int { var chatsRead = 0 AccountViewAuthorize.showGetPrivateKey(in: self) { guard let msgsHistoryService = try? CryptoChat.Service.MsgsHistory( username: username, encryptionKey: $0 ) else { return } msgsHistoryService.fetchFromLocalHistory() chatsRead = msgsHistoryService.readCount } return chatsRead } private func chatsMsgsCount(username: String) -> Int { guard let current = Accounts().messageShelf.activeBook else { return 0 } let contract = ApplicationEnvironment.shared().current.contract(.chat) let action = Network.Model.Blockchain.Action.chatSendDm.rawValue return current.actions .where { $0.username == username && $0.account == contract && $0.name == action && $0.receiver == username } .count } func setChatsBadge(count: Int) { DispatchQueue.main.async { [weak self] in self?.content.viewControllers? .compactMap { $0 as? UINavigationController } .compactMap { $0.viewControllers.first } .first(where: { $0 is CryptoChatControllerChats })? .navigationController?.tabBarItem.badgeValue = count > 0 ? "\(count)" : nil } } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) StoreReviewHelper.checkAndAskForReview() Accounts().messageShelf.activeBook?.fetch() let bank = Accounts().bank if !bank.active.isExist { if !bank.wallets.isEmpty { let ctrl = AccountsListController() self.mainController.content.push(ctrl, animated: true) } else if Account.Service.isAccountMigrated, !(Account.Service.Authorize.shared.password ?? "").isEmpty { self.showWalletBoarding() } } // else if !UserDefaults.standard.bool(forKey: "onboardingOverviewPassed") { // present(StoryboardScene.AccountOnboarding.accountOnboardingControllerInterfaceType.instantiate(), animated: true) // } else if Accounts().isAuthorized { self.interfaceCover.isHidden = true Loader.hide() // Show news /*Task { if let urlString = await service.loadNews().first?.url, let url = URL(string: urlString), !(AccountOnboarding.Service.Common().newsShowed ?? []).contains(urlString) { let webview = WKWebView() webview.load(URLRequest(url: url)) webview.addHeightConstraint(height: UIScreen.main.bounds.height * 0.8 - 100) Popup.show( views: [webview], submit: L10n.Common.Button.close, in: self ) AccountOnboarding.Service.Common().newsShowed = (AccountOnboarding.Service.Common().newsShowed ?? []) + [urlString] } }*/ } } func showWalletBoarding() { guard self.view.window != nil else { return } let ctrl = WalletBoardingViewController { if !Accounts().hasActiveAccounts { let vc = AccountsListController() self.content.push(vc, animated: false) } } ctrl.modalPresentationStyle = .fullScreen self.present(ctrl, animated: true) } func updateMsgCount() { guard let username = Accounts().current?.name else { self.setChatsBadge(count: 0) return } if UserDefaults.standard.object(forKey: "chatsReadCount") == nil { UserDefaults.standard.setValue([username: self.chatsMsgsCount(username: username)], forKey: "chatsReadCount") } else if !(UserDefaults.standard.dictionary(forKey: "chatsReadCount")?.keys.contains(username) ?? false) { var readDict = (UserDefaults.standard.dictionary(forKey: "chatsReadCount") as? [String: Int]) ?? [:] readDict[username] = self.chatsMsgsCount(username: username) UserDefaults.standard.setValue(readDict, forKey: "chatsReadCount") } self.setChatsBadge(count: self.chatsMsgsCount(username: username) - self.chatsRead(by: username)) } @objc func onAccountChange() { self.configureAccountButton() self.configureQRButton() self.configureResourcesSwitch() self.setupSubscriptions() self.inviteView.changeVisibility(Accounts().hasActiveAccounts) self.updateMsgCount() if Accounts().collection.isEmpty { self.showWalletBoarding() } DispatchQueue.main.async { [weak self] in guard let self, self.view.window.isExist else { return } self.interfaceCover.isHidden = true Loader.hide() } } func setupSubscriptions() { guard let username = Accounts().current?.name, !Network.webSockets.contains(id: "\(username)-sockets2.0") else { return } Network.webSockets.remove(idSuffix: "-sockets2.0") let timeText = Date().toISODateString let signature = Network.Service.Blockchain.signWithK1(privateKey: AccountViewAuthorize.getPrivateKey(), data: timeText.data(using: .utf8) ?? Data()) let signaturesString = #""" { \\\"username\\\": \\\"$username\\\", \\\"text\\\": \\\"$timeText\\\", \\\"signature\\\": \\\"$signature\\\" } """# .replacingOccurrences(of: "$username", with: username) .replacingOccurrences(of: "$timeText", with: timeText) .replacingOccurrences(of: "$signature", with: signature) let subscription = #""" {"id":"2","type":"start","payload":{"query":"subscription { notifications(lang: $lang, signature: \"$signature\"){ notificationType state payload previousUid currentUid }}","variables":null}} """# .replacingOccurrences(of: "$signature", with: signaturesString) .replacingOccurrences(of: "$lang", with: Common.Model.Language.current.rawValue) Network.webSockets.open(subscription: subscription, id: "\(username)-sockets2.0") self.service.reloadP2PData(username: Accounts().current?.name ?? "") } private func configureAccountButton() { let wallet = Accounts().current let accountButtonTitle = wallet?.isOnActiveState == true ? (wallet?.name ?? L10n.Account.Button.empty) : L10n.Account.Button.addAccounts self.accountButton.setAttributedTitle(accountButtonTitle.attributed(style: .bold, size: 16, color: Asset.textSnow.color), for: .normal ) self.accountButton.isEnabled = wallet?.isOnActiveState == true self.accountButton.backgroundColor = wallet?.isOnActiveState == true ? Asset.deepWater.color : Asset.disabled.color self.accountButton.isUserInteractionEnabled = wallet?.isOnActiveState == true && !Accounts().isLocked self.accountButton.setImage(Accounts().isLocked ? Asset.accountLock.image : Asset.commonEos.image, for: .normal) } private func configureQRButton() { let wallet = Accounts().current self.settingsGearButton.isEnabled = wallet?.isOnActiveState == true self.settingsGearButton.image = wallet?.isOnActiveState == true ? Asset.commonButtonQr.image : Asset.commonButtonQrDisabled.image } private func configureResourcesSwitch() { let wallet = Accounts().current let quota = Accounts().quota self.resourcesSwitch.isActive = wallet?.isOnActiveState == true self.resourcesSwitch.lzTextFrontSelected = wallet?.isOnActiveState == true ? "\(quota.count)" : "" self.resourcesSwitch.set(isSelected: quota.isEnabled, animated: true) } @IBAction func accountPressed(_ sender: Any) { // let ctrl = AccountsSelectionViewController() let ctrl = AccountsListController() self.mainController.content.push(ctrl, animated: true) } @IBAction func onResources(_: AnyObject?) { let ctrl = StoryboardScene.Resources.setup.instantiate() ctrl.shouldHideBackButton = self.hasTitle self.content.push(ctrl, animated: true) } @IBAction func qrPressed(_ sender: Any) { guard UIImagePickerController.isSourceTypeAvailable(.photoLibrary) else { let ctrl = ScannerViewController() ctrl.navigationItem.leftBarButtonItem = .close { [weak self] in self?.dismiss(animated: true) } ctrl.didCapture = { [weak self] string in guard let self else { return } self.dismiss(animated: true) self.readQrData(string: string) } let navCtrl = UINavigationController(rootViewController: ctrl) navCtrl.modalPresentationStyle = .fullScreen present(navCtrl, animated: true) return } Alert.system( actions: [ .init(title: L10n.Wallet.Send.qrCamera, style: .default) { [weak self] _ in let ctrl = ScannerViewController() ctrl.navigationItem.leftBarButtonItem = .close { [weak ctrl] in ctrl?.dismiss(animated: true) } ctrl.didCapture = { string in self?.dismiss(animated: true) self?.readQrData(string: string) } let navCtrl = UINavigationController(rootViewController: ctrl) navCtrl.modalPresentationStyle = .fullScreen UIViewController.topController().present(navCtrl, animated: true) }, .init(title: L10n.Wallet.Send.qrLibrary, style: .default) { [weak self] _ in guard let self else { return } let ctrl = UIImagePickerController() ctrl.delegate = self ctrl.sourceType = .photoLibrary UIViewController.topController().present(ctrl, animated: true) }, .init(title: L10n.Main.Qr.showMy, style: .default) { [weak self] _ in guard let self else { return } let ctrl = StoryboardScene.Wallet.receive.instantiate() ctrl.isQuickLook = true self.mainController.content.push(ctrl, animated: true) }, .init(title: L10n.Common.Button.cancel, style: .cancel) ], style: .actionSheet, in: self ) } private func openTransfer(with dictionary: [String: Any]) { let viewController = StoryboardScene.Wallet.transfer.instantiate() viewController.dictionary = dictionary let navigationController = self.content.selectedViewController as? UINavigationController navigationController?.popToRootViewController(animated: true) navigationController?.pushViewController(viewController, animated: true) } private func readQrData(string: String) { if let link = URL(string: string) { Branch.getInstance().handleDeepLink(link) } else { self.openTransfer(with: convertStringToDictionary(text: string) ?? [:]) } } private var deepLink: DeepLink? // swiftlint:disable cyclomatic_complexity function_body_length func process(deepLink: DeepLink) { guard Accounts().isAuthorized else { self.deepLink = deepLink return } let navigationController = self.content.selectedViewController as? UINavigationController switch deepLink.action { case .walletAuth: let dictionary = deepLink.dictionary() if let callbackUrl = dictionary["callback_url"] as? String, let verificationCode = dictionary["verification_code"] as? String, let account = Accounts().current?.name { let siteUrl = dictionary["site_url"] as? String ?? "" let siteName = ((dictionary["site_name"] as? String) ?? "").isEmpty ? " " : "\((dictionary["site_name"] as? String) ?? " ")" Popup.show( title: ((dictionary["site_name"] as? String) ?? "").isEmpty ? L10n.Main.ListLogin.title : L10n.Main.ListLogin.titleOn(siteName), views: [ .label( text: L10n.Main.ListLogin.description(siteName) .attributed(style: .regular, size: 16, color: Asset.textCoal.color), numberOfLines: 0 ) ], submit: L10n.Common.Button.confirm, in: navigationController ?? self ) { ctrl in Loader.show(in: ctrl) AccountViewAuthorize.showGetPrivateKey(in: navigationController ?? self) { let data = "{\"account\":\"\(account)\",\"verification_code\":\"\(verificationCode)\"}" let signature = Network.Service.Blockchain.signWithK1(privateKey: $0, data: data.data(using: .utf8) ?? Data()) AF.request( callbackUrl, method: .post, parameters: ["signature": signature, "data": data], encoding: JSONEncoding.default ).responseString { self.interfaceCover.isHidden = true Loader.hide(in: ctrl) Popup.hide() guard let statusCode = $0.response?.statusCode else { return } let errorTitle: String? if statusCode == 200 { // Open URL if it exists deepLink.url >>- { UIApplication.shared.open($0) } return } else if !siteUrl.isEmpty, let url = URL(string: siteUrl) { url >>- { UIApplication.shared.open($0) } return } else if let error = ($0.error as NSError?) { Alert.notify(error.localizedDescription, dismiss: ctrl) return } else if statusCode >= 400, statusCode < 500 { errorTitle = L10n.tr("Localizable", "main.listLogin.expired") } else { errorTitle = L10n.tr("Localizable", "main.listLogin.unexpected") } errorTitle >>- { Alert.notify($0, dismiss: ctrl) } } } } } case .transfer, .competitivePrice: let viewController = StoryboardScene.Wallet.transfer.instantiate() viewController.dictionary = deepLink.dictionary() navigationController?.popToRootViewController(animated: true) navigationController?.pushViewController(viewController, animated: true) case .connect: if let model = deepLink.get(AccountModelConnect.self), let account = Accounts().collection.filter({ $0.name == model.from }).first { Accounts().current = account let ctrl = StoryboardScene.Account.connect.instantiate() ctrl.service.model = model (self.content.selectedViewController as? UINavigationController)?.popToRootViewController(animated: true) (self.content.selectedViewController as? UINavigationController)?.pushViewController(ctrl, animated: true) } case .chat: // guard UIApplication.shared.applicationState == .inactive else { return } if let model = deepLink.get(CryptoChat.Model.DeepLink.self) { AccountViewAuthorize.showGetPrivateKey(in: self) { guard let user = Accounts().current, let msgsHistoryService = try? CryptoChat.Service.MsgsHistory( username: user.name, encryptionKey: $0 ) else { return } let ctrl = CryptoChatControllerChat(username: model.account, unreadCount: 0, service: msgsHistoryService) (self.content.selectedViewController as? UINavigationController)?.popToRootViewController(animated: true) self.content.selectChatViewController() guard let selectedNavigation = (self.content.selectedViewController as? UINavigationController), !(selectedNavigation.viewControllers.last is CryptoChatControllerChat) else { return } selectedNavigation.pushViewController(ctrl, animated: true) selectedNavigation.setNavigationBarHidden(false, animated: true) } } case .chatMessage: // guard UIApplication.shared.applicationState == .inactive else { return } guard let info = deepLink.info, let receiver = info["receiver"] as? String, let sender = info["sender"] as? String, let account = Accounts().collection.filter({ $0.name == receiver }).first else { return } Accounts().current = account AccountViewAuthorize.showGetPrivateKey(in: self) { guard let user = Accounts().current, let msgsHistoryService = try? CryptoChat.Service.MsgsHistory( username: user.name, encryptionKey: $0 ) else { return } let controller = CryptoChatControllerChat(username: sender, unreadCount: 0, service: msgsHistoryService) (self.content.selectedViewController as? UINavigationController)?.popToRootViewController(animated: true) self.content.selectChatViewController() guard let selectedNavigation = (self.content.selectedViewController as? UINavigationController), !(selectedNavigation.viewControllers.last is CryptoChatControllerChat) else { return } selectedNavigation.pushViewController(controller, animated: true) selectedNavigation.setNavigationBarHidden(false, animated: true) } case .tokenization: if let model = deepLink.get(Apartments.Model.Tokenization.self), let account = Accounts().collection.filter({ $0.name == model.permission }).first { Accounts().current = account let ctrl = StoryboardScene.Apartments.request.instantiate() ctrl.title = L10n.Apartments.Tokenization.title ctrl.popupDescription = L10n.Apartments.Tokenization.popup let service = Apartments.Service.Tokenization() service.image = Asset.apartmentsTokenization.image service.warning = L10n.Apartments.Tokenization.warning service.submit = L10n.Apartments.Tokenization.submit service.title = L10n.Apartments.Tokenization.description service.actionTitle = L10n.Apartments.Tokenization.Emission.title service.contract = model.contract service.action = model.action service.symbol = model.symbol service.fetchApartment(id: model.apt_id, contract: model.contract, symbol: model.symbol) { (success) in guard success else { return } service.receiver = nil ctrl.service = service (self.content.selectedViewController as? UINavigationController)?.popToRootViewController(animated: true) (self.content.selectedViewController as? UINavigationController)?.pushViewController(ctrl, animated: true) } } case .approveBuy: if let model = deepLink.get(Apartments.Model.ApproveBuy.self), let account = Accounts().collection.filter({ $0.name == model.permission }).first { Accounts().current = account let ctrl = StoryboardScene.Apartments.request.instantiate() ctrl.title = L10n.Apartments.Approve.title ctrl.popupDescription = L10n.Apartments.Approve.popup let service = Apartments.Service.Approve() service.warning = L10n.Apartments.Approve.warning service.submit = L10n.Apartments.Approve.submit service.title = L10n.Apartments.Approve.description service.actionTitle = L10n.Apartments.Approve.Emission.title service.contract = model.contract service.action = model.action service.symbol = model.token service.fetchApartment(id: model.apt_id, contract: model.contract, symbol: model.token) { (success) in guard success else { return } service.receiver = nil ctrl.service = service (self.content.selectedViewController as? UINavigationController)?.popToRootViewController(animated: true) (self.content.selectedViewController as? UINavigationController)?.pushViewController(ctrl, animated: true) } } case .emission: if let model = deepLink.get(Apartments.Model.Emission.self), let account = Accounts().collection.filter({ $0.name == model.permission }).first { Accounts().current = account let ctrl = StoryboardScene.Apartments.request.instantiate() ctrl.title = L10n.Apartments.Emission.title ctrl.popupDescription = L10n.Apartments.Emission.popup let service = Apartments.Service.Emission() service.image = Asset.apartmentsEmission.image service.warning = L10n.Apartments.Emission.warning service.title = L10n.Apartments.Emission.description service.actionTitle = L10n.Apartments.Tokenization.Emission.title service.submit = L10n.Apartments.Emission.submit service.contract = model.contract service.action = model.action service.to = model.to service.amount = model.amount service.symbol = model.symbol service.memo = model.memo service.fetchApartment(id: model.apt_id, contract: model.contract, symbol: model.symbol) { (success) in guard success else { return } ctrl.service = service (self.content.selectedViewController as? UINavigationController)?.popToRootViewController(animated: true) (self.content.selectedViewController as? UINavigationController)?.pushViewController(ctrl, animated: true) } } case .transactionTransfer, .transactionEmission, .transactionInheritance/*, .cashDealComplete*/: if let info = deepLink.info, let username = info["receiver"] as? String, let symbol = info["currency"] as? String, let account = Accounts().collection.filter({ $0.name == username }).first { Accounts().current = account if let index = self.content.viewControllers?.lastIndex(where: { ($0 as? UINavigationController)?.viewControllers.first is WalletController }) { self.content.selectedIndex = index let walletController = ((self.content.viewControllers?[index] as? UINavigationController)?.viewControllers.first as? WalletController) walletController?.selectedSymbol = symbol ((self.content.viewControllers?[index] as? UINavigationController)?.viewControllers.first as? WalletController)?.selectedSymbol = symbol (self.content.viewControllers?[index] as? UINavigationController)?.popToRootViewController(animated: true) } Wallet.Service.Tokens.shared.balances.fetch() } case .p2pDealNew, .p2pDealComplete, .p2pDealCancel, .p2pDealDispute: guard UIApplication.shared.applicationState == .inactive else { return } if let info = deepLink.info, let username = info["receiver"] as? String, (info["currency"] as? String).isExist, let account = Accounts().collection.filter({ $0.name == username }).first { Accounts().current = account if let index = self.content.viewControllers?.lastIndex(where: { ($0 as? UINavigationController)?.viewControllers.first is P2PControllerDashboard }) { self.content.selectedIndex = index (self.content.viewControllers?[index] as? UINavigationController)?.popToRootViewController(animated: true) // P2P.Service.Dashboard.shared.symbol = symbol Wallet.Service.Tokens.shared.balances.fetch() } } /*case .cashDealNew, .cashDealConfirm, .cashDealCancel: if let info = deepLink.info, let username = info["receiver"] as? String, let account = Accounts().collection.filter({ $0.username == username }).first { Accounts().current = account if let index = content.viewControllers?.lastIndex(where: { ($0 as? UINavigationController)?.viewControllers.first is CCCPMainViewController }) { content.selectedIndex = index (content.viewControllers?[index] as? UINavigationController)?.popToRootViewController(animated: true) if deepLink.action == .cashDealNew || deepLink.action == .cashDealCancel { let ctrl = CCCPControllerExchangeRequests() ctrl.type = .incomingRequests (content.viewControllers?[index] as? UINavigationController)?.pushViewController(ctrl, animated: true) } } }*/ case .news: if let info = deepLink.info, let aps = info["aps"] as? [String: Any], let alert = aps["alert"] as? [String: String] { Popup.show(title: alert["title"], description: alert["body"] ?? "", submit: L10n.Common.Button.ok) } } } } extension MainController: UINavigationControllerDelegate, UIImagePickerControllerDelegate { func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { picker.dismiss(animated: true) guard let selectedImage = info[.originalImage] as? UIImage, let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh]), let ciImage = CIImage(image: selectedImage) else { return } var qrCodeLink = "" for feature in (detector.features(in: ciImage) as? [CIQRCodeFeature]) ?? [] { qrCodeLink += feature.messageString ?? "" } print(qrCodeLink) // Your result from QR Code if !qrCodeLink.isEmpty { readQrData(string: qrCodeLink) } else { Alert.error(L10n.Main.Qr.notValidError) } } }