Files
raspberry/iOS/Wallet/Sources/Account/Controller/AccountControllerPin.swift
T

324 lines
13 KiB
Swift

//
// AccountControllerPin.swift
// Wallet
//
// Created by Saveliy Stavitsky on 12/4/20.
// Copyright © 2020 List. All rights reserved.
//
import UIKit
protocol AccountControllerPinDelegate: AnyObject {
func pinControllerDismiss(_ controller: AccountControllerPin)
func pinController(_ controller: AccountControllerPin, update password: String)
func pinControllerValidatePinSuccess(_ controller: AccountControllerPin)
func pinControllerClearAccountData(_ controller: AccountControllerPin)
}
final class AccountControllerPin: UIViewController {
enum AccountControllerPinType {
case old
case new
case protectionNew
}
@IBOutlet weak var logoTopConstraint: NSLayoutConstraint!
@IBOutlet var headerTitleLabel: UILabel!
@IBOutlet var headerDescriptionLabel: UILabel!
@IBOutlet var pinStackView: UIStackView!
@IBOutlet private weak var submitBtn: UIButton!
@IBOutlet private weak var haveWalletButton: UIButton!
@IBOutlet var leftButton: UIButton!
@IBOutlet var errorTopConstraint: NSLayoutConstraint!
@IBOutlet var errorTitleLabel: UILabel!
@IBOutlet var errorTryLabel: UILabel!
@IBOutlet var timeoutTitleLabel: UILabel!
@IBOutlet var timeoutLabel: UILabel!
@IBOutlet var timeoutView: UIView!
@IBOutlet private var warningView: CommonViewWarning!
weak var delegate: AccountControllerPinDelegate?
var type: AccountControllerPinType = .new
var pinValidate: ((String) -> Bool)?
var faceSubmit: (() -> Void)?
var showBackButton = true
var repeatPin: [Int] = []
var pin: [Int] = [Int]() {
didSet {
self.pinStackView.arrangedSubviews
.compactMap { $0 as? UIStackView }
.compactMap { $0.arrangedSubviews.first as? UIImageView }
.forEach { $0.image = Asset.accountPinStarEmpty.image }
self.errorTitleLabel.isHidden = true
for index in self.pin.indices where index < self.pinStackView.arrangedSubviews.count {
if let stack = pinStackView.arrangedSubviews[index] as? UIStackView {
(stack.arrangedSubviews.first as? UIImageView)?.image = Asset.accountPinStarFill.image
}
}
if self.repeatPin.count == 4,
self.pin.count == 4,
self.repeatPin != self.pin {
self.pinStackView.arrangedSubviews
.compactMap { $0 as? UIStackView }
.compactMap { $0.arrangedSubviews.first as? UIImageView }
.forEach { $0.image = Asset.accountPinStarError.image }
self.errorTitleLabel.isHidden = false
}
}
}
@IBOutlet var numbersStackView: UIStackView!
@IBOutlet var numberButtons: [UIButton]!
private var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
// print(UIApplication.shared.windows.first?.safeAreaInsets.top)
// if (UIApplication.shared.windows.first?.safeAreaInsets.top ?? 0) < 50 {
// logoTopConstraint.constant = 0
// }
self.timeoutTitleLabel.textAlignment = .center
self.warningView.makeCritical()
self.numbersStackView.spacing = UIScreen.main.bounds.height < 570 ? 8 : 24
self.timer = delayed(1, repeats: true) { [weak self] in
guard let self = self, self.pinValidate != nil else { return }
// let timeout = 3 * 60 - (Account.Service.Authorize.shared.lastPinTryTimeout() ?? 0)
// let seconds = timeout % 60 < 10 ? "0\(timeout % 60)" : "\(timeout % 60)"
// self.timeoutLabel.text = "\(timeout / 60):\(seconds)"
self.errorTryLabel.text = L10n.Account.Pin.tryCount(5 - Account.Service.Authorize.shared.getPinTries().count)
if Account.Service.Authorize.shared.getPinTries().count >= 5 {
// if Account.Service.Authorize.shared.lastPinTryTimeout()! < 3 * 60 {
self.timeoutView.isHidden = false
self.delegate?.pinControllerClearAccountData(self)
// } else {
// Account.Service.Authorize.shared.clearPinTries()
// self.timeoutView.isHidden = true
// }
} else {
self.timeoutView.isHidden = true
}
}
self.timer?.fire()
if self.pinValidate != nil {
if self.faceSubmit != nil {
self.title = "" // L10n.Account.Authorize.title
self.headerTitleLabel.text = L10n.Account.Pin.Enter.title
self.logoTopConstraint.constant = -40
} else {
self.title = "" // L10n.Account.Password.title
self.headerTitleLabel.text = type == .new ? L10n.Account.Pin.Enter.titleNew : L10n.Account.Pin.Enter.titleOld
self.logoTopConstraint.constant = -40
}
if self.showBackButton {
self.navigationItem.leftBarButtonItem = .back { [unowned self] in
self.timer?.invalidate()
self.timer = nil
self.navigationController?.dismiss(animated: true)
}
}
// Clear the background image.
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
// Clear the shadow image.
self.navigationController?.navigationBar.shadowImage = UIImage()
// Ensure the navigation bar is translucent.
self.navigationController?.navigationBar.isTranslucent = true
// navigationController?.navigationBar.layer.shadowColor = Asset.lightGray.color.cgColor
// navigationController?.navigationBar.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
// navigationController?.navigationBar.layer.shadowRadius = 4.0
// navigationController?.navigationBar.layer.shadowOpacity = 1.0
// navigationController?.navigationBar.layer.masksToBounds = false
self.leftButton.isHidden = !(Account.Service.isBiometricksEnabled) || faceSubmit == nil
self.leftButton.lzTitle = ""
self.leftButton.setImage(Asset.accountPinFaceId.image, for: .normal)
self.headerTitleLabel.font = .font(style: .regular, size: 14)
self.headerTitleLabel.textColor = Asset.textGranite.color.withAlphaComponent(0.7)
self.headerDescriptionLabel.isHidden = true
} else {
self.headerTitleLabel.font = .font(style: .bold, size: 24)
self.headerTitleLabel.textColor = Asset.textGranite.color
self.headerDescriptionLabel.isHidden = false
self.leftButton.lzTitle = L10n.Common.Button.back
if self.repeatPin.count == 0 {
self.leftButton.isHidden = true
} else {
self.leftButton.isHidden = false
self.headerTitleLabel.text = L10n.Account.Pin.Repeat.title
}
}
self.headerDescriptionLabel.font = .font(style: .regular, size: 14)
for button in self.numberButtons {
button.titleLabel?.font = .font(style: .regular, size: 28)
button.setTitleColor(Asset.textGranite.color, for: .normal)
// button.setBackgroundImage(Asset.accountPinNumberBackground.image, for: .highlighted)
}
self.leftButton.titleLabel?.font = .font(style: .medium, size: 18)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.callBiometricsSignInIfEnabled()
}
private func callBiometricsSignInIfEnabled() {
if Account.Service.isBiometricksEnabled {
self.faceSubmit?()
}
}
@IBAction
private func onSubmit(_ : AnyObject?) {
}
@IBAction private func onUnderstand(_ : AnyObject?) {
Account.Service.Authorize.shared.clearPinTries()
self.delegate?.pinControllerDismiss(self)
}
@IBAction func haveWalletPrssed(_: AnyObject?) {
Alert.hint(text: L10n.Account.Onboarding.Password.hint)
}
@IBAction func numberPressed(_ sender: Any) {
if let value = (sender as? UIButton)?.tag {
switch value {
case -4:
self.leftButton.isHidden = self.faceSubmit == nil
if self.faceSubmit == nil {
self.headerTitleLabel.text = L10n.Account.Pin.Enter.title
}
self.repeatPin = []
self.pin = []
self.faceSubmit?()
case -1:
self.pin = self.pin.dropLast()
default:
if self.pin.count < 4 {
self.pin += [value]
} else {
return
}
}
//print(self.pin)
if let pinValidate,
self.pin.count == 4 {
let password = "\(self.pin[0])\(self.pin[1])\(self.pin[2])\(self.pin[3])"
if pinValidate(password) {
self.delegate?.pinControllerValidatePinSuccess(self)
} else {
for stack in (pinStackView.arrangedSubviews as? [UIStackView]) ?? [] {
(stack.arrangedSubviews.first as? UIImageView)?.image = Asset.accountPinStarError.image
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
self?.pin = []
self?.timer?.fire()
self?.errorTryLabel.text = L10n.Account.Pin.tryCount(5 - Account.Service.Authorize.shared.getPinTries().count)
self?.errorTryLabel.isHidden = false
self?.errorTitleLabel.isHidden = false
self?.warningView.isHidden = false
}
}
} else {
if repeatPin.count == 0,
pin.count == 4 {
leftButton.isHidden = false
headerTitleLabel.text = L10n.Account.Pin.Repeat.title
self.repeatPin = pin
pin = []
} else if repeatPin.count == 4 && pin.count == 4 && repeatPin == pin {
Account.Service.Authorize.shared.password = "\(pin[0])\(pin[1])\(pin[2])\(pin[3])"
successShow()
}
}
}
}
func successShow() {
UserDefaults.standard.setValue(true, forKey: "isPinPwdMode")
let password = "\(pin[0])\(pin[1])\(pin[2])\(pin[3])"
self.delegate?.pinController(self, update: password)
Popup.show(
title: L10n.Account.Onboarding.Success.title,
description: L10n.Account.Onboarding.Success.description,
submit: Account.Service.isBiometricksAvailable ? L10n.Account.Onboarding.Success.submit : L10n.Common.Button.ok,
in: self, { ctrl in
ctrl.dismiss(animated: true)
guard Account.Service.isBiometricksAvailable else {
self.delegate?.pinControllerDismiss(self)
return
}
let submit: (UIViewController) -> Void = { ctrl in
ctrl.dismiss(animated: true)
Account.Service.checkBiometricks { (success) in
if success {
Account.Service.isBiometricksEnabled = true
Alert.success()
self.delegate?.pinControllerDismiss(self)
} else {
Alert.error(text: L10n.Account.Onboarding.Bimetricks.error)
self.delegate?.pinControllerDismiss(self)
}
}
}
if Account.Service.isFaceIdAvailable {
Popup.show(
title: L10n.Account.Onboarding.FaceId.title,
image: Asset.commonFaceId.image,
description: L10n.Account.Onboarding.FaceId.description,
submit: L10n.Account.Onboarding.FaceId.submit,
in: self,
submit
)
} else {
Popup.show(
title: L10n.Account.Onboarding.TouchId.title,
image: Asset.commonTouchId.image,
description: L10n.Account.Onboarding.TouchId.description,
submit: L10n.Account.Onboarding.TouchId.submit,
in: self,
submit
)
}
}
)
}
}