Files
raspberry/iOS/Wallet/Sources/CCCP/Controller/CCCPControllerDestroyTokens.swift
2022-05-27 20:21:01 +03:00

357 lines
16 KiB
Swift

//
// 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
}
}