// // CreateWalletViewController.swift // Malinka // // Created by Nut.Tech on 27.07.2022. // import UIKit final class CreateWalletViewController: UIViewController { // MARK: - Constants private enum Geometry { enum Common { static let left: CGFloat = 12 static let cornerRadius: CGFloat = 2 static let standartFontSize: CGFloat = 12 static let mediumFontSize: CGFloat = 14 static let titleFontSize: CGFloat = 24 static let inputLength = 12 } enum Header { static let commonHeight: CGFloat = 4 static let indicatorsInterval: CGFloat = 4 static let indicatorTop: CGFloat = 10 static let stepTextTop: CGFloat = 16 static let stepTextHeight: CGFloat = 14 static let stepTitleTop: CGFloat = 4 static let stepTitleHeight: CGFloat = 29 } enum InputStack { static let labelTop: CGFloat = 30 static let stackTop: CGFloat = 15 static let stackHeight: CGFloat = 20 } enum AttentionView { static let top: CGFloat = 25 static let cornerRadius: CGFloat = 8 } enum ErrorLabel { static let top: CGFloat = 8 } enum SubmitButton { static let top: CGFloat = 25 static let height: CGFloat = 48 } } // MARK: - Properties private var isPresented: Bool { if let navVc = self.navigationController { return navVc.viewControllers.firstIndex(of: self) == 0 } else { return self.presentingViewController != nil } } private lazy var attentionView: UIView = { let attentionView = CommonViewAlert() attentionView.translatesAutoresizingMaskIntoConstraints = false attentionView.containerView?.backgroundColor = Asset.marble.color attentionView.textLbl.text = L10n.Account.Onboarding.limitationsWarning attentionView.textLbl.font = FontFamily.GolosUI.regular.font(size: Geometry.Common.standartFontSize) attentionView.textLbl.textColor = Asset.dark.color attentionView.imgView.image = Asset.appartmentsWarning.image attentionView.imgView.tintColor = Asset.dark.color attentionView.clipsToBounds = true attentionView.layer.cornerRadius = Geometry.AttentionView.cornerRadius return attentionView }() private lazy var submitButton: UIButton = { let action = CommonMenuAction { [weak self] _ in self?.onSubmit() } let button = CommonButtonAction(action: action, height: Geometry.SubmitButton.height) button.lzTitle = L10n.Common.Button.continue button.isEnabled = false button.translatesAutoresizingMaskIntoConstraints = false return button }() private lazy var inputStack: WalletTextInputView = { let inputView = WalletTextInputView(length: Geometry.Common.inputLength, delegate: self) inputView.translatesAutoresizingMaskIntoConstraints = false return inputView }() private lazy var stepTitle: UILabel = { let stepTitle = UILabel() stepTitle.translatesAutoresizingMaskIntoConstraints = false stepTitle.font = FontFamily.GolosUI.bold.font(size: Geometry.Common.titleFontSize) stepTitle.textColor = Asset.dark.color stepTitle.text = L10n.Account.Onboarding.Step1.title return stepTitle }() private lazy var errorLabel: UILabel = { let errorLabel = UILabel() errorLabel.translatesAutoresizingMaskIntoConstraints = false errorLabel.font = FontFamily.GolosUI.regular.font(size: Geometry.Common.mediumFontSize) errorLabel.textColor = Asset.liSTRedEnd.color return errorLabel }() private var walletIdentifier: String? private var errorLabelHeight: NSLayoutConstraint? private let caseWalletService: CaseWalletService // MARK: - Init init(with service: CaseWalletService) { self.caseWalletService = service super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() self.title = L10n.Account.Onboarding.freeTitle self.view.backgroundColor = .white self.overrideUserInterfaceStyle = .light self.setupNavigationBar() self.setupHeader() self.setupAttetionView() self.setupTextInputStackView() self.setupErrorLabel() self.setupSubmitButton() let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) tap.cancelsTouchesInView = false view.addGestureRecognizer(tap) } private func setupHeader() { let stepIndicatorFull = UIView() stepIndicatorFull.translatesAutoresizingMaskIntoConstraints = false stepIndicatorFull.backgroundColor = Asset.deepWater.color stepIndicatorFull.clipsToBounds = true stepIndicatorFull.layer.cornerRadius = Geometry.Common.cornerRadius let stepIndicatorEmpty = UIView() stepIndicatorEmpty.translatesAutoresizingMaskIntoConstraints = false stepIndicatorEmpty.backgroundColor = Asset.disabled.color stepIndicatorEmpty.clipsToBounds = true stepIndicatorEmpty.layer.cornerRadius = Geometry.Common.cornerRadius let stepText = UILabel() stepText.translatesAutoresizingMaskIntoConstraints = false stepText.font = FontFamily.GolosUI.bold.font(size: Geometry.Common.standartFontSize) stepText.textColor = Asset.lightGray.color stepText.text = L10n.Account.Onboarding.Step1.step self.view.addSubview(stepIndicatorFull) self.view.addSubview(stepIndicatorEmpty) self.view.addSubview(stepText) self.view.addSubview(self.stepTitle) NSLayoutConstraint.activate([ stepIndicatorFull.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: Geometry.Header.indicatorTop), stepIndicatorFull.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: Geometry.Common.left), stepIndicatorFull.heightAnchor.constraint(equalToConstant: Geometry.Header.commonHeight), stepIndicatorFull.rightAnchor.constraint(equalTo: stepIndicatorEmpty.leftAnchor, constant: -Geometry.Header.indicatorsInterval), stepIndicatorEmpty.lastBaselineAnchor.constraint(equalTo: stepIndicatorFull.lastBaselineAnchor), stepIndicatorEmpty.heightAnchor.constraint(equalToConstant: Geometry.Header.commonHeight), stepIndicatorEmpty.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -Geometry.Common.left), stepIndicatorEmpty.widthAnchor.constraint(equalTo: stepIndicatorFull.widthAnchor), stepText.topAnchor.constraint(equalTo: stepIndicatorFull.bottomAnchor, constant: Geometry.Header.stepTextTop), stepText.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: Geometry.Common.left), stepText.heightAnchor.constraint(equalToConstant: Geometry.Header.stepTextHeight), self.stepTitle.topAnchor.constraint(equalTo: stepText.bottomAnchor, constant: Geometry.Header.stepTitleTop), self.stepTitle.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: Geometry.Common.left), self.stepTitle.heightAnchor.constraint(equalToConstant: Geometry.Header.stepTitleHeight) ]) } private func setupTextInputStackView() { let inputInvitationLabel = UILabel() inputInvitationLabel.translatesAutoresizingMaskIntoConstraints = false inputInvitationLabel.textColor = Asset.dark.color inputInvitationLabel.font = FontFamily.GolosUI.medium.font(size: Geometry.Common.mediumFontSize) inputInvitationLabel.text = L10n.Account.Onboarding.Step1.typeAnyInfo inputInvitationLabel.numberOfLines = 0 self.view.addSubview(inputInvitationLabel) self.view.addSubview(self.inputStack) NSLayoutConstraint.activate([ inputInvitationLabel.topAnchor.constraint(equalTo: self.attentionView.bottomAnchor, constant: Geometry.InputStack.labelTop), inputInvitationLabel.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: Geometry.Common.left), inputInvitationLabel.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -Geometry.Common.left), self.inputStack.topAnchor.constraint(equalTo: inputInvitationLabel.bottomAnchor, constant: Geometry.InputStack.stackTop), self.inputStack.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: Geometry.Common.left), self.inputStack.rightAnchor.constraint(lessThanOrEqualTo: self.view.rightAnchor, constant: -Geometry.Common.left), self.inputStack.heightAnchor.constraint(equalToConstant: Geometry.InputStack.stackHeight) ]) } private func setupAttetionView() { self.view.addSubview(self.attentionView) NSLayoutConstraint.activate([ self.attentionView.topAnchor.constraint(equalTo: self.stepTitle.bottomAnchor, constant: Geometry.AttentionView.top), self.attentionView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: Geometry.Common.left), self.attentionView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -Geometry.Common.left) ]) } private func setupErrorLabel() { self.view.addSubview(self.errorLabel) NSLayoutConstraint.activate([ self.errorLabel.topAnchor.constraint(equalTo: self.inputStack.bottomAnchor, constant: Geometry.ErrorLabel.top), self.errorLabel.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: Geometry.Common.left), self.errorLabel.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -Geometry.Common.left) ]) } private func setupSubmitButton() { self.view.addSubview(self.submitButton) NSLayoutConstraint.activate([ self.submitButton.topAnchor.constraint(equalTo: self.errorLabel.bottomAnchor, constant: Geometry.SubmitButton.top), self.submitButton.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: Geometry.Common.left), self.submitButton.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -Geometry.Common.left) ]) } private func setupNavigationBar() { self.navigationItem.leftBarButtonItem = .back { [weak self] in if self?.isPresented ?? false { self?.navigationController?.dismiss(animated: true) } else { self?.navigationController?.popViewController(animated: true) } } if self.isPresented { self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default) self.navigationController?.navigationBar.shadowImage = UIImage() self.navigationController?.navigationBar.isTranslucent = true } } @objc private func dismissKeyboard() { self.inputStack.hideKeyboard() } private func onSubmit() { guard let name = self.walletIdentifier else { self.onErrorAccountAlreadyExists(message: "account.create.name.empty.error".localized) return } self.submitButton.isEnabled = false Task { do { let controller = try await self.caseWalletService.createPrivateKeyController(for: name, manualCreate: !self.isPresented) DispatchQueue.main.async { self.navigationController?.pushViewController(controller, animated: true) } } catch CaseWalletService.ServiceError.exists { self.onErrorAccountAlreadyExists(message: "account.create.name.exists.error".localized) } catch CaseWalletService.ServiceError.system { self.onErrorAlertWindow(message: "account.create.name.reserve.error".localized) } DispatchQueue.main.async { self.submitButton.isEnabled = true } } } private func onErrorAccountAlreadyExists(message: String) { guard !message.isEmpty || !(self.errorLabel.text?.isEmpty ?? true) else { return } self.errorLabel.text = message UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } self.submitButton.isEnabled = false } private func onErrorAlertWindow(message: String) { guard !message.isEmpty || !(self.errorLabel.text?.isEmpty ?? true) else { return } self.errorLabel.text = "" UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } Alert.error(text: message) self.submitButton.isEnabled = false } } extension CreateWalletViewController: WalletTextInputViewDelegate { func walletUpdateTextOutput(wallet: WalletTextInputView, text: String?) { guard text != nil else { self.onErrorAccountAlreadyExists(message: "") self.submitButton.isEnabled = false return } self.walletIdentifier = text self.submitButton.isEnabled = true } }