// // CCCPControllerDestroyTokens.swift // List // // Created by Saveliy Stavitsky on 7/23/20. // Copyright © 2020 List. All rights reserved. // import UIKit private typealias Contract = Network.Model.Contract private typealias BlockchainAction = Network.Model.Blockchain.Action class CCCPControllerDestroyTokens: UIViewController { var bill: CashBillsService.Bill? @IBOutlet private var mainStackView: UIStackView! @IBOutlet private weak var certificateGiveView: CommonViewCard! @IBOutlet private weak var tokeGiveView: CommonViewCard! @IBOutlet private weak var amountTextField: CommonTextField! @IBOutlet private var labelsStackView: UIStackView! @IBOutlet private weak var youGiveInfoLbl: CommonViewInfoLabel! @IBOutlet private weak var youGetInfoLbl: CommonViewInfoLabel! @IBOutlet var youGiveTokenSelectorView: CCCPViewTokenSelector! @IBOutlet var youGetTokenSelectorView: CCCPViewTokenSelector! @IBOutlet var destroyTokensButton: CommonButtonAction! var selectSymbol = "" var tokensIncome: [Network.Model.TokenSmall] = [] var tokensIncomeCoef: Decimal? { if let certificateGive = youGiveTokenSelectorView.selectedToken, let tokenGet = Wallet.Service.Tokens.shared.certificateToList(certificateGive) { return tokensIncome .first(where: { $0.quantity.symbol == tokenGet.symbol })? .quantity.amount.toDecimal() } else { return nil } } var cashBillsService: CashBillsService? // var cashTokens: [Network.Model.Token] { Wallet.Service.Tokens.shared.cashTokens } var tokens: [Network.Model.Token] = [] { didSet { youGiveTokenSelectorView.tokens = tokens.filter(\.isCertificate) if let index = youGiveTokenSelectorView.tokens.enumerated() .first(where: { $0.element.symbol == self.selectSymbol })?.offset, !selectSymbol.isEmpty { selectSymbol = "" youGiveTokenSelectorView.index = index } certificateGiveView.action = .cards( icon: Asset.commonLock.image.withTintColor(Asset.pebble.color), tokens: youGiveTokenSelectorView.tokens, selected: youGiveTokenSelectorView.tokens .first(where: { $0.symbol == bill?.gtoken_out.quantity.symbol }), empty: .menu( image: Asset.commonToken.image.tinted(with: Asset.deepWater.color), title: L10n.Cccp.IssueBackTokens.youGiveTokenTitle ), title: L10n.Cccp.IssueBackTokens.youGiveTokenTitle, { [weak self] _ in }) certificateGiveView.isUserInteractionEnabled = false tokeGiveView.action = .cards( icon: Asset.commonLock.image.withTintColor(Asset.pebble.color), tokens: youGiveTokenSelectorView.tokens, selected: youGiveTokenSelectorView.selectedToken, empty: .menu( image: Asset.commonToken.image.tinted(with: Asset.deepWater.color), title: L10n.Cccp.IssueBackTokens.youGiveTokenTitle ), title: L10n.Cccp.IssueBackTokens.youGiveTokenTitle, { [weak self] in self?.tokeGiveView.selectedCashBill = nil self?.tokeGiveView.update(animated: true) self?.youGiveTokenSelectorView.index = self?.youGiveTokenSelectorView.tokens.index(of: $0.uuid) ?? -1 }) } } var selectedTokens: (Network.Model.Token, Network.Model.Token, String)? { guard let certificateGive = youGiveTokenSelectorView.tokens .first(where: { $0.symbol == tokeGiveView.selectedCashBill?.gtoken_out.quantity.symbol }) ?? youGiveTokenSelectorView.selectedToken, let cashGive = Wallet.Service.Tokens.shared.certificateToCash(certificateGive), let tokenGet = Wallet.Service.Tokens.shared.certificateToList(certificateGive) else { return nil } return (certificateGive, cashGive, tokenGet.symbol) } override func viewDidLoad() { super.viewDidLoad() navigationItem.title = L10n.Cccp.IssueBackTokens.title navigationItem.leftBarButtonItem = .pop(self) tokeGiveView.isUserInteractionEnabled = false tokeGiveView.root = true tokeGiveView.cashBillsService = cashBillsService self.tokeGiveView.selectCashBillAction = { [weak self] in print($0?.id) self?.tokeGiveView.selectedCashBill = $0 self?.tokeGiveView.update(animated: true) self?.stateChanged() Popup.hide() } youGiveTokenSelectorView.count = 1 if let bill = bill { tokeGiveView.selectedCashBill = bill tokeGiveView.update(animated: true) stateChanged() } tokeGiveView.action = .cards( tokens: [], selected: nil, empty: .menu( image: Asset.commonToken.image.tinted(with: Asset.deepWater.color), title: L10n.Cccp.IssueBackTokens.youGiveTokenTitle ), title: L10n.Cccp.IssueBackTokens.youGiveTokenTitle ) amountTextField.keyboardType = .numberPad amountTextField.delegate = self youGiveTokenSelectorView.titleLabel.text = L10n.Cccp.DestroyTokens.youGiveTitle youGiveTokenSelectorView.secondTitleLabel.isHidden = true youGiveTokenSelectorView.notesTitleLabel.text = L10n.Cccp.DestroyTokens.youGiveYouGiveTitle youGiveTokenSelectorView.balanceStackView.isHidden = false youGiveTokenSelectorView.parentViewController = self youGetTokenSelectorView.secondTitleLabel.isHidden = true youGetTokenSelectorView.countSectionStackView.isHidden = true youGetTokenSelectorView.currencyPickerSectionStackView.isHidden = true youGetTokenSelectorView.currencySectionImageView.isHidden = true youGetTokenSelectorView.notesTitleLabel.text = L10n.Cccp.DestroyTokens.youGetYouGetTitle youGetTokenSelectorView.parentViewController = self observers.append(contentsOf: [ Notification.subscribe(name: .didChangeAccount) { _ in Loader.show() }, Notification.subscribe(name: .didUpdateBalances) { [weak self] _ in self?.setupView() } ]) setupView() // NotificationCenter.default.addObserver(self, selector: #selector(onBalancesChange(_:)), // name: .didUpdateBalances, object: nil) // onBalancesChange(Notification(name: .didUpdateBalances)) } var observers: [AnyObject] = [] deinit { observers.forEach({ Notification.unsubscribe(observer: $0) }) // NotificationCenter.default.removeObserver(self, name: .didUpdateBalances, object: nil) } func setupView() { //(_ notification: Notification) CCCP.Service.Swaps.shared.fetch { [weak self] in self?.tokensIncome = $0 self?.tokens = Wallet.Service.Tokens.shared.balances.collection Loader.hide() } } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) Accounts().isLocked = true } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) Accounts().isLocked = false } @IBAction func destroyTokensPressed(_ sender: Any) { guard let user = Accounts().current, let (certificateTokenGive, cashTokenGive, tokenGet) = selectedTokens, youGiveTokenSelectorView.count > 0 else { return } let actions = prepareBlockchainActions( user: user, certificateTokenGive: certificateTokenGive, tokenGet: tokenGet ) Popup.show(title: navigationItem.title, views: [labelsStackView], submit: L10n.Common.Button.confirm, in: self, { [unowned self] ctrl in AccountViewAuthorize.showGetPrivateKey(in: self) { Loader.show(in: ctrl) Network.Service.Blockchain.execute(actions: actions, privateKeys: [$0]) { result in Loader.hide(in: ctrl) ctrl.dismiss(animated: true) switch result { case .success(let transactionId): delayed(0.5) { //needed because labelsStackView will free inly after previous popup hde Popup.show(title: L10n.Cccp.IssueBackTokens.completeTitle, views: [labelsStackView], submit: L10n.Common.Button.checkOnBloksIO, submitStyle: .outline, cancel: L10n.Common.Button.done, in: self, { _ in guard let checkTransactionUrl = URL(transactionId: transactionId) else { return } UIApplication.shared.open(checkTransactionUrl, options: [:], completionHandler: nil) }, { if let secondViewController = navigationController?.viewControllers.dropFirst().first { navigationController?.popToViewController(secondViewController, animated: true) } }) } case let .failure(error): Alert.notify(error, pop: self) } } } }, { [weak self] in guard let self = self else { return } self.mainStackView.addArrangedSubview(self.labelsStackView) }) } private func prepareBlockchainActions( user: Account.Model, certificateTokenGive: Network.Model.Token, tokenGet: String) -> [(Contract, BlockchainAction, Codable)] { var actions = [(Contract, BlockchainAction, Codable)]() //Create Token balances if not present if !tokens.map({ $0.symbol }).contains(tokenGet) { let openBalanceData = Network.Model.Blockchain.OpenBalance( owner: user.username, symbol: "8,\(tokenGet)", ram_payer: user.username ) actions.append((.list, .open, openBalanceData)) } //Destroy Tokens action if let bill = tokeGiveView.selectedCashBill { let swapBackData = Network.Model.Blockchain.BillSwapback( owner: user.username, receiver: user.username, bill_id: "\(bill.id)" ) actions.append((.cash, .cashBillSwapback, swapBackData)) } else { let swapBackData = Network.Model.Blockchain.Swapback( owner: user.username, receiver: user.username, certificate: "\(youGiveTokenSelectorView.count) \(certificateTokenGive.symbol)" ) actions.append((.cash, .cashSwapback, swapBackData)) } return actions } } extension CCCPControllerDestroyTokens: CCCPViewTokenSelectorDelegate { func stateChanged() { //Reset appearance youGiveTokenSelectorView.notesSectionSubStackView.arrangedSubviews .forEach({ $0.removeFromSuperview() }) youGetTokenSelectorView.notesSectionSubStackView.arrangedSubviews .forEach({ $0.removeFromSuperview() }) // destroyTokensButton.setTitle(L10n.Cccp.DestroyTokens.buttonDestroyTokens(""), for: .normal) destroyTokensButton.isEnabled = false guard let (certGive, cashTokenGive, tokenGet) = selectedTokens else { return } // amountTextField.isHidden = false labelsStackView.isHidden = false labelsStackView.arrangedSubviews.forEach({ $0.removeFromSuperview() }) let cashInfo1 = CommonViewInfoLabel() cashInfo1.lzTitle = L10n.Cash.DestroyTokens.tokenReturn cashInfo1.addText(cashTokenGive.symbol) labelsStackView.addArrangedSubview(cashInfo1) //Cash token select section view appearance let cashTokensCount = Decimal(youGiveTokenSelectorView.count) * cashTokenGive.certCoef let labelCashTokens = CCCPLabelAddMoneyColored(sign: "-", amount: cashTokensCount, symbol: cashTokenGive.symbol) youGiveTokenSelectorView.notesSectionSubStackView.addArrangedSubview(labelCashTokens) let labelListTokens = CCCPLabelAddMoneyColored( amount: Decimal(youGiveTokenSelectorView.count) * (tokensIncomeCoef ?? 0.0), symbol: tokenGet) youGetTokenSelectorView.notesSectionSubStackView.addArrangedSubview(labelListTokens) // youGiveInfoLbl.clearAll() // youGiveInfoLbl.addText("\(youGiveTokenSelectorView.count) \(certGive.symbol)") // youGiveInfoLbl.addText("\(cashTokensCount.toString(precision: 5)) \(cashTokenGive.symbol)") let returnAmount = (tokeGiveView.selectedCashBill?.token_out.quantity ?? "\(cashTokensCount.toString(max: 5, group: false)) \(cashTokenGive.symbol)").amount.toDecimal() let returnCommission = returnAmount * 0.03 let cashInfo2 = CommonViewInfoLabel() cashInfo2.lzTitle = L10n.Cash.DestroyTokens.amountReturn cashInfo2.addText((returnAmount + returnCommission).toString(max: 5)) labelsStackView.addArrangedSubview(cashInfo2) let cashInfo3 = CommonViewInfoLabel() cashInfo3.lzTitle = L10n.Cash.DestroyTokens.commissionReturn cashInfo3.addText(returnCommission.toString(max: 5)) labelsStackView.addArrangedSubview(cashInfo3) let cashInfo4 = CommonViewInfoLabel() cashInfo4.lzTitle = L10n.Cash.DestroyTokens.tokenGet cashInfo4.addText(tokenGet) labelsStackView.addArrangedSubview(cashInfo4) let cashInfo5 = CommonViewInfoLabel() cashInfo5.lzTitle = L10n.Cash.DestroyTokens.amountGet cashInfo5.addText("100") labelsStackView.addArrangedSubview(cashInfo5) // youGetInfoLbl.updateText("\((Double(youGiveTokenSelectorView.count) * (tokensIncomeCoef ?? 0.0)).toString(precision: 8)) \(tokenGet)") // destroyTokensButton.setTitle(L10n.Cccp.DestroyTokens.buttonDestroyTokens(tokenGet), for: .normal) if let amountHave = tokens.first(where: { $0.symbol == cashTokenGive.symbol })?.amount { if amountHave >= (returnAmount + returnCommission) && certGive.amount > 0 { destroyTokensButton.isEnabled = true } else if certGive.amount > 0 { cashInfo2.addError(L10n.Cccp.IssueBackTokens.youGiveAmountError(cashTokenGive.symbol)) } } // amountTextField.error = youGiveTokenSelectorView.count > 0 // && youGiveTokenSelectorView.count > youGiveTokenSelectorView.maxTokens // ? L10n.Cccp.IssueBackTokens.youGiveAmountError(certGive.symbol) : nil // // if youGiveTokenSelectorView.count > 0 && youGiveTokenSelectorView.count <= youGiveTokenSelectorView.maxTokens { // if let amountHave = tokens.first(where: { $0.symbol == cashTokenGive.symbol })?.amount { // if amountHave >= Double(youGiveTokenSelectorView.count) * cashTokenGive.certCoef { // destroyTokensButton.isEnabled = true // } else { // let infoLabel = UILabel() // infoLabel.attributedText = L10n.Cccp.DestroyTokens.noEnoughtBalance.attributed // .applying(attribute: .foregroundColor, value: Asset.liSTRedEnd.color) // .applying(attribute: .font, value: FontFamily.GolosUI.medium.font(size: 14)!) // youGiveTokenSelectorView.notesSectionSubStackView.addArrangedSubview(infoLabel) // youGiveInfoLbl.addError(L10n.Cccp.IssueBackTokens.youGiveAmountError(cashTokenGive.symbol)) // } // } // } } } extension CCCPControllerDestroyTokens: CommonTextFieldDelegate { func textFieldDidChange(_ textField: CommonTextField) { youGiveTokenSelectorView.count = Int(textField.value) ?? 0 } }