element-ios/Riot/Modules/SetPinCode/EnterPinCode/EnterPinCodeViewModel.swift

152 lines
5.5 KiB
Swift
Raw Normal View History

// File created from ScreenTemplate
// $ createScreen.sh SetPinCode/EnterPinCode EnterPinCode
/*
Copyright 2020 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
final class EnterPinCodeViewModel: EnterPinCodeViewModelType {
// MARK: - Properties
// MARK: Private
private let session: MXSession?
2020-07-21 13:16:27 +00:00
private var viewMode: SetPinCoordinatorViewMode
private var firstPin: String = ""
private var currentPin: String = "" {
didSet {
self.viewDelegate?.enterPinCodeViewModel(self, didUpdatePlaceholdersCount: currentPin.count)
}
}
2020-07-21 13:16:27 +00:00
private var numberOfFailuresDuringEnterPIN: Int = 0
// MARK: Public
weak var viewDelegate: EnterPinCodeViewModelViewDelegate?
weak var coordinatorDelegate: EnterPinCodeViewModelCoordinatorDelegate?
2020-07-22 14:47:45 +00:00
var pinCodePreferences: PinCodePreferences
// MARK: - Setup
2020-07-22 14:47:45 +00:00
init(session: MXSession?, viewMode: SetPinCoordinatorViewMode, pinCodePreferences: PinCodePreferences) {
self.session = session
2020-07-21 13:16:27 +00:00
self.viewMode = viewMode
2020-07-22 14:47:45 +00:00
self.pinCodePreferences = pinCodePreferences
}
// MARK: - Public
func process(viewAction: EnterPinCodeViewAction) {
switch viewAction {
2020-07-21 13:16:27 +00:00
case .loadData:
self.loadData()
case .digitPressed(let tag):
self.digitPressed(tag)
2020-07-21 13:16:27 +00:00
case .forgotPinPressed:
self.viewDelegate?.enterPinCodeViewModel(self, didUpdateViewState: .forgotPin)
case .cancel:
self.coordinatorDelegate?.enterPinCodeViewModelDidCancel(self)
2020-07-21 13:16:27 +00:00
case .pinsDontMatchAlertAction:
// reset pins
firstPin.removeAll()
currentPin.removeAll()
// go back to first state
self.update(viewState: .choosePin)
case .forgotPinAlertAction:
self.coordinatorDelegate?.enterPinCodeViewModelDidCompleteWithReset(self)
}
}
// MARK: - Private
private func digitPressed(_ tag: Int) {
if tag == -1 {
// delete tapped
if currentPin.isEmpty {
return
} else {
currentPin.removeLast()
}
} else {
// a digit tapped
2020-07-21 16:32:48 +00:00
currentPin += String(tag)
2020-07-22 14:47:45 +00:00
if currentPin.count == pinCodePreferences.numberOfDigits {
2020-07-21 13:16:27 +00:00
switch viewMode {
case .setPin:
// choosing pin
if firstPin.isEmpty {
// go to next screen
firstPin = currentPin
currentPin.removeAll()
2020-07-21 16:32:48 +00:00
update(viewState: .confirmPin)
} else {
2020-07-21 13:16:27 +00:00
// check first and second pins
if firstPin == currentPin {
// complete with a little delay
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
2020-07-21 13:19:14 +00:00
self.coordinatorDelegate?.enterPinCodeViewModel(self, didCompleteWithPin: self.firstPin)
2020-07-21 13:16:27 +00:00
}
} else {
2020-07-21 16:32:48 +00:00
update(viewState: .pinsDontMatch)
2020-07-21 13:16:27 +00:00
}
}
case .unlockByPin, .confirmPinToDeactivate:
// unlocking
2020-07-22 14:47:45 +00:00
if currentPin != pinCodePreferences.pin {
2020-07-21 13:16:27 +00:00
// no match
numberOfFailuresDuringEnterPIN += 1
2020-07-22 14:47:45 +00:00
if numberOfFailuresDuringEnterPIN < pinCodePreferences.allowedNumberOfTrialsBeforeAlert {
2020-07-21 16:32:48 +00:00
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.viewDelegate?.enterPinCodeViewModel(self, didUpdateViewState: .wrongPin)
self.currentPin.removeAll()
}
2020-07-21 13:16:27 +00:00
} else {
2020-07-21 16:32:48 +00:00
viewDelegate?.enterPinCodeViewModel(self, didUpdateViewState: .wrongPinTooManyTimes)
2020-07-21 13:16:27 +00:00
numberOfFailuresDuringEnterPIN = 0
2020-07-21 16:32:48 +00:00
currentPin.removeAll()
2020-07-21 13:16:27 +00:00
}
} else {
// match
// complete with a little delay
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.coordinatorDelegate?.enterPinCodeViewModelDidComplete(self)
}
}
}
return
}
}
}
private func loadData() {
2020-07-21 13:16:27 +00:00
switch viewMode {
case .setPin:
update(viewState: .choosePin)
case .unlockByPin:
update(viewState: .unlockByPin)
case .confirmPinToDeactivate:
update(viewState: .confirmPinToDisable)
}
}
private func update(viewState: EnterPinCodeViewState) {
self.viewDelegate?.enterPinCodeViewModel(self, didUpdateViewState: viewState)
}
}