mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-18 23:48:29 +02:00
Complete functions
This commit is contained in:
@@ -38,10 +38,10 @@ final class EnterPinCodeCoordinator: EnterPinCodeCoordinatorType {
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(session: MXSession?) {
|
||||
init(session: MXSession?, viewMode: SetPinCoordinatorViewMode) {
|
||||
self.session = session
|
||||
|
||||
let enterPinCodeViewModel = EnterPinCodeViewModel(session: self.session)
|
||||
let enterPinCodeViewModel = EnterPinCodeViewModel(session: self.session, viewMode: viewMode)
|
||||
let enterPinCodeViewController = EnterPinCodeViewController.instantiate(with: enterPinCodeViewModel)
|
||||
self.enterPinCodeViewModel = enterPinCodeViewModel
|
||||
self.enterPinCodeViewController = enterPinCodeViewController
|
||||
@@ -61,6 +61,14 @@ final class EnterPinCodeCoordinator: EnterPinCodeCoordinatorType {
|
||||
// MARK: - EnterPinCodeViewModelCoordinatorDelegate
|
||||
extension EnterPinCodeCoordinator: EnterPinCodeViewModelCoordinatorDelegate {
|
||||
|
||||
func enterPinCodeViewModelDidComplete(_ viewModel: EnterPinCodeViewModelType) {
|
||||
self.delegate?.enterPinCodeCoordinatorDidComplete(self)
|
||||
}
|
||||
|
||||
func enterPinCodeViewModelDidCompleteWithReset(_ viewModel: EnterPinCodeViewModelType) {
|
||||
self.delegate?.enterPinCodeCoordinatorDidCompleteWithReset(self)
|
||||
}
|
||||
|
||||
func enterPinCodeViewModel(_ viewModel: EnterPinCodeViewModelType, didCompleteWithPin pin: String) {
|
||||
self.delegate?.enterPinCodeCoordinator(self, didCompleteWithPin: pin)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
import Foundation
|
||||
|
||||
protocol EnterPinCodeCoordinatorDelegate: class {
|
||||
func enterPinCodeCoordinatorDidComplete(_ coordinator: EnterPinCodeCoordinatorType)
|
||||
func enterPinCodeCoordinatorDidCompleteWithReset(_ coordinator: EnterPinCodeCoordinatorType)
|
||||
func enterPinCodeCoordinator(_ coordinator: EnterPinCodeCoordinatorType, didCompleteWithPin pin: String)
|
||||
func enterPinCodeCoordinatorDidCancel(_ coordinator: EnterPinCodeCoordinatorType)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ import Foundation
|
||||
|
||||
/// EnterPinCodeViewController view actions exposed to view model
|
||||
enum EnterPinCodeViewAction {
|
||||
case loadData
|
||||
case digitPressed(_ tag: Int)
|
||||
case forgotPinPressed
|
||||
case cancel
|
||||
case pinsDontMatchAlertAction
|
||||
case forgotPinAlertAction
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="V8j-Lb-PgC">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<device id="retina3_5" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
|
||||
@@ -13,56 +13,74 @@
|
||||
<objects>
|
||||
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="V8j-Lb-PgC" customClass="EnterPinCodeViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="EL9-GA-lwo">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Choose a PIN for security" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bxI-mu-qng">
|
||||
<rect key="frame" x="80.5" y="83" width="253" height="26.5"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="22"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="24" translatesAutoresizingMaskIntoConstraints="NO" id="xi9-P9-8WP">
|
||||
<rect key="frame" x="123" y="205.5" width="168" height="24"/>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="DMT-DS-IA8">
|
||||
<rect key="frame" x="0.0" y="8" width="320" height="464"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="selection_untick" translatesAutoresizingMaskIntoConstraints="NO" id="Gwx-8X-ZWk">
|
||||
<rect key="frame" x="0.0" y="0.0" width="24" height="24"/>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ztg-5t-ECh" userLabel="Container">
|
||||
<rect key="frame" x="20" y="0.0" width="280" height="86"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="callkit_icon" translatesAutoresizingMaskIntoConstraints="NO" id="UHg-qE-anw">
|
||||
<rect key="frame" x="120" y="8" width="40" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="40" id="ERR-Np-6I1"/>
|
||||
<constraint firstAttribute="height" constant="40" id="zYD-Rk-nOH"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Choose a PIN for security" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bxI-mu-qng">
|
||||
<rect key="frame" x="13.5" y="57" width="253" height="29"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="22"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="aek-t8-dK4"/>
|
||||
<constraint firstAttribute="width" constant="24" id="cJN-ZQ-6aQ"/>
|
||||
<constraint firstAttribute="height" constant="86" id="30N-bq-9g8"/>
|
||||
<constraint firstAttribute="bottom" secondItem="bxI-mu-qng" secondAttribute="bottom" id="8Qc-aK-wkM"/>
|
||||
<constraint firstItem="UHg-qE-anw" firstAttribute="centerX" secondItem="ztg-5t-ECh" secondAttribute="centerX" id="Vhm-GS-xYs"/>
|
||||
<constraint firstItem="bxI-mu-qng" firstAttribute="top" secondItem="UHg-qE-anw" secondAttribute="bottom" constant="9" id="laj-kY-eW1"/>
|
||||
<constraint firstItem="bxI-mu-qng" firstAttribute="centerX" secondItem="ztg-5t-ECh" secondAttribute="centerX" id="p4o-hz-jZJ"/>
|
||||
<constraint firstItem="UHg-qE-anw" firstAttribute="top" secondItem="ztg-5t-ECh" secondAttribute="top" constant="8" id="uj5-KC-7FD"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" tag="1" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="selection_untick" translatesAutoresizingMaskIntoConstraints="NO" id="qDY-R1-l5l">
|
||||
<rect key="frame" x="48" y="0.0" width="24" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="24" id="QDg-LP-R4J"/>
|
||||
<constraint firstAttribute="height" constant="24" id="f4G-d8-hoA"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" tag="2" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="selection_untick" translatesAutoresizingMaskIntoConstraints="NO" id="X0l-q3-fXm">
|
||||
<rect key="frame" x="96" y="0.0" width="24" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="24" id="HQA-9R-8bC"/>
|
||||
<constraint firstAttribute="height" constant="24" id="Zjd-RW-DiW"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" tag="3" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="selection_untick" translatesAutoresizingMaskIntoConstraints="NO" id="o1F-px-ZT5">
|
||||
<rect key="frame" x="144" y="0.0" width="24" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="FA6-QR-ld2"/>
|
||||
<constraint firstAttribute="width" constant="24" id="TcR-MF-wE3"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="3on-xo-2n5"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tUL-bI-Cpy">
|
||||
<rect key="frame" x="0.0" y="229.5" width="414" height="632.5"/>
|
||||
<subviews>
|
||||
</view>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="24" translatesAutoresizingMaskIntoConstraints="NO" id="xi9-P9-8WP">
|
||||
<rect key="frame" x="76" y="87" width="168" height="24"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="selection_untick" translatesAutoresizingMaskIntoConstraints="NO" id="Gwx-8X-ZWk">
|
||||
<rect key="frame" x="0.0" y="0.0" width="24" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="aek-t8-dK4"/>
|
||||
<constraint firstAttribute="width" constant="24" id="cJN-ZQ-6aQ"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" tag="1" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="selection_untick" translatesAutoresizingMaskIntoConstraints="NO" id="qDY-R1-l5l">
|
||||
<rect key="frame" x="48" y="0.0" width="24" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="24" id="QDg-LP-R4J"/>
|
||||
<constraint firstAttribute="height" constant="24" id="f4G-d8-hoA"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" tag="2" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="selection_untick" translatesAutoresizingMaskIntoConstraints="NO" id="X0l-q3-fXm">
|
||||
<rect key="frame" x="96" y="0.0" width="24" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="24" id="HQA-9R-8bC"/>
|
||||
<constraint firstAttribute="height" constant="24" id="Zjd-RW-DiW"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" tag="3" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="selection_untick" translatesAutoresizingMaskIntoConstraints="NO" id="o1F-px-ZT5">
|
||||
<rect key="frame" x="144" y="0.0" width="24" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="FA6-QR-ld2"/>
|
||||
<constraint firstAttribute="width" constant="24" id="TcR-MF-wE3"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" alignment="center" spacing="21" translatesAutoresizingMaskIntoConstraints="NO" id="W0M-eq-abZ">
|
||||
<rect key="frame" x="85" y="165" width="244" height="303"/>
|
||||
<rect key="frame" x="38" y="112" width="244" height="303"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="32" translatesAutoresizingMaskIntoConstraints="NO" id="Uqh-o2-7HP">
|
||||
<rect key="frame" x="0.0" y="0.0" width="244" height="60"/>
|
||||
@@ -225,40 +243,59 @@
|
||||
</stackView>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nCW-ER-9SF" userLabel="Container">
|
||||
<rect key="frame" x="40" y="416" width="240" height="48"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CRt-Fb-0Dq">
|
||||
<rect key="frame" x="0.0" y="0.0" width="240" height="48"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<state key="normal" title="Forgot PIN"/>
|
||||
<connections>
|
||||
<action selector="forgotPinButtonAction:" destination="V8j-Lb-PgC" eventType="touchUpInside" id="hE4-CJ-Bdh"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="CRt-Fb-0Dq" firstAttribute="top" secondItem="nCW-ER-9SF" secondAttribute="top" id="QVD-G0-uHm"/>
|
||||
<constraint firstAttribute="bottom" secondItem="CRt-Fb-0Dq" secondAttribute="bottom" id="gJw-QQ-7PO"/>
|
||||
<constraint firstAttribute="trailing" secondItem="CRt-Fb-0Dq" secondAttribute="trailing" id="gnV-kg-BCW"/>
|
||||
<constraint firstAttribute="height" constant="48" id="whx-HV-FXN"/>
|
||||
<constraint firstItem="CRt-Fb-0Dq" firstAttribute="leading" secondItem="nCW-ER-9SF" secondAttribute="leading" id="wxI-iX-ugm"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="W0M-eq-abZ" firstAttribute="centerY" secondItem="tUL-bI-Cpy" secondAttribute="centerY" id="aqm-0i-Sq4"/>
|
||||
<constraint firstItem="W0M-eq-abZ" firstAttribute="centerX" secondItem="tUL-bI-Cpy" secondAttribute="centerX" id="tdZ-I0-AMy"/>
|
||||
<constraint firstAttribute="trailing" secondItem="ztg-5t-ECh" secondAttribute="trailing" constant="20" id="ADS-wF-wRi"/>
|
||||
<constraint firstItem="ztg-5t-ECh" firstAttribute="leading" secondItem="DMT-DS-IA8" secondAttribute="leading" constant="20" id="YU9-Am-aht"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.94509803921568625" green="0.96078431372549022" blue="0.97254901960784312" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="bxI-mu-qng" firstAttribute="centerX" secondItem="EL9-GA-lwo" secondAttribute="centerX" id="2Bf-EF-ikh"/>
|
||||
<constraint firstItem="xi9-P9-8WP" firstAttribute="centerX" secondItem="EL9-GA-lwo" secondAttribute="centerX" id="4iN-py-NUV"/>
|
||||
<constraint firstItem="xi9-P9-8WP" firstAttribute="top" secondItem="bxI-mu-qng" secondAttribute="bottom" constant="96" id="7mW-Ct-gas"/>
|
||||
<constraint firstItem="tUL-bI-Cpy" firstAttribute="top" secondItem="xi9-P9-8WP" secondAttribute="bottom" id="Bh0-nk-4NF"/>
|
||||
<constraint firstItem="bxI-mu-qng" firstAttribute="top" secondItem="bFg-jh-JZB" secondAttribute="top" constant="39" id="U9h-07-CLy"/>
|
||||
<constraint firstItem="tUL-bI-Cpy" firstAttribute="leading" secondItem="bFg-jh-JZB" secondAttribute="leading" id="USU-5t-l6v"/>
|
||||
<constraint firstItem="bFg-jh-JZB" firstAttribute="trailing" secondItem="tUL-bI-Cpy" secondAttribute="trailing" id="Xb3-zu-Zbb"/>
|
||||
<constraint firstItem="bFg-jh-JZB" firstAttribute="bottom" secondItem="tUL-bI-Cpy" secondAttribute="bottom" id="fZf-Se-umS"/>
|
||||
<constraint firstItem="DMT-DS-IA8" firstAttribute="top" secondItem="bFg-jh-JZB" secondAttribute="top" constant="8" id="Mlg-kp-E06"/>
|
||||
<constraint firstItem="bFg-jh-JZB" firstAttribute="trailing" secondItem="DMT-DS-IA8" secondAttribute="trailing" id="Vwu-g7-vNh"/>
|
||||
<constraint firstItem="bFg-jh-JZB" firstAttribute="bottom" secondItem="DMT-DS-IA8" secondAttribute="bottom" constant="8" id="gPa-B5-LIs"/>
|
||||
<constraint firstItem="DMT-DS-IA8" firstAttribute="leading" secondItem="bFg-jh-JZB" secondAttribute="leading" id="kA7-cw-VK1"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="bFg-jh-JZB"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="digitsStackView" destination="W0M-eq-abZ" id="xnb-6w-dtC"/>
|
||||
<outlet property="forgotPinButton" destination="CRt-Fb-0Dq" id="kHp-wn-P0o"/>
|
||||
<outlet property="informationLabel" destination="bxI-mu-qng" id="pbX-aZ-inC"/>
|
||||
<outlet property="logoImageView" destination="UHg-qE-anw" id="8C0-pd-i3b"/>
|
||||
<outlet property="placeholderStackView" destination="xi9-P9-8WP" id="ynl-7M-Rpb"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="zK0-v6-7Wt" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-3198" y="-647"/>
|
||||
<point key="canvasLocation" x="-3199.1999999999998" y="-648.02955665024638"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="back_icon" width="14" height="23"/>
|
||||
<image name="callkit_icon" width="40" height="40"/>
|
||||
<image name="selection_untick" width="22" height="22"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -30,9 +30,11 @@ final class EnterPinCodeViewController: UIViewController {
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@IBOutlet private weak var logoImageView: UIImageView!
|
||||
@IBOutlet private weak var placeholderStackView: UIStackView!
|
||||
@IBOutlet private weak var digitsStackView: UIStackView!
|
||||
@IBOutlet private weak var informationLabel: UILabel!
|
||||
@IBOutlet private weak var forgotPinButton: UIButton!
|
||||
|
||||
// MARK: Private
|
||||
|
||||
@@ -67,8 +69,13 @@ final class EnterPinCodeViewController: UIViewController {
|
||||
self.update(theme: self.theme)
|
||||
|
||||
self.viewModel.viewDelegate = self
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
modalPresentationStyle = .fullScreen
|
||||
isModalInPresentation = true
|
||||
}
|
||||
|
||||
// self.viewModel.process(viewAction: .loadData)
|
||||
self.viewModel.process(viewAction: .loadData)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
@@ -134,29 +141,87 @@ final class EnterPinCodeViewController: UIViewController {
|
||||
|
||||
private func render(viewState: EnterPinCodeViewState) {
|
||||
switch viewState {
|
||||
case .enterFirstPin:
|
||||
self.renderEnterFirstPin()
|
||||
case .choosePin:
|
||||
self.renderChoosePin()
|
||||
case .confirmPin:
|
||||
self.renderConfirmPin()
|
||||
case .pinsDontMatch(let error):
|
||||
self.render(error: error)
|
||||
case .pinsDontMatch:
|
||||
self.renderPinsDontMatch()
|
||||
case .unlockByPin:
|
||||
self.renderUnlockByPin()
|
||||
case .wrongPin:
|
||||
self.renderWrongPin()
|
||||
case .wrongPinTooManyTimes:
|
||||
self.renderWrongPinTooManyTimes()
|
||||
case .forgotPin:
|
||||
self.renderForgotPin()
|
||||
case .confirmPinToDisable:
|
||||
self.renderConfirmPinToDisable()
|
||||
}
|
||||
}
|
||||
|
||||
private func renderEnterFirstPin() {
|
||||
self.informationLabel.text = "Choose a PIN for security"
|
||||
private func renderChoosePin() {
|
||||
self.logoImageView.isHidden = true
|
||||
self.informationLabel.text = VectorL10n.pinProtectionChoosePin
|
||||
self.forgotPinButton.isHidden = true
|
||||
}
|
||||
|
||||
private func renderConfirmPin() {
|
||||
self.informationLabel.text = "Confirm your PIN"
|
||||
self.informationLabel.text = VectorL10n.pinProtectionConfirmPin
|
||||
|
||||
// reset placeholders
|
||||
renderPlaceholdersCount(0)
|
||||
}
|
||||
|
||||
private func render(error: Error) {
|
||||
private func renderPinsDontMatch() {
|
||||
let error = NSError(domain: "", code: 0, userInfo: [
|
||||
NSLocalizedFailureReasonErrorKey: VectorL10n.pinProtectionMismatchErrorTitle,
|
||||
NSLocalizedDescriptionKey: VectorL10n.pinProtectionMismatchErrorMessage
|
||||
])
|
||||
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
|
||||
self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil)
|
||||
self.errorPresenter.presentError(from: self, forError: error, animated: true) {
|
||||
self.viewModel.process(viewAction: .pinsDontMatchAlertAction)
|
||||
}
|
||||
}
|
||||
|
||||
private func renderUnlockByPin() {
|
||||
self.logoImageView.isHidden = false
|
||||
self.informationLabel.text = VectorL10n.pinProtectionEnterPin
|
||||
self.forgotPinButton.isHidden = false
|
||||
}
|
||||
|
||||
private func renderWrongPin() {
|
||||
self.placeholderStackView.vc_shake()
|
||||
}
|
||||
|
||||
private func renderWrongPinTooManyTimes() {
|
||||
let error = NSError(domain: "", code: 0, userInfo: [
|
||||
NSLocalizedFailureReasonErrorKey: VectorL10n.pinProtectionMismatchErrorTitle,
|
||||
NSLocalizedDescriptionKey: VectorL10n.pinProtectionMismatchErrorMessage
|
||||
])
|
||||
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
|
||||
self.errorPresenter.presentError(from: self, forError: error, animated: true) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private func renderForgotPin() {
|
||||
let controller = UIAlertController(title: VectorL10n.pinProtectionResetAlertTitle,
|
||||
message: VectorL10n.pinProtectionResetAlertMessage,
|
||||
preferredStyle: .alert)
|
||||
|
||||
let resetAction = UIAlertAction(title: VectorL10n.pinProtectionResetAlertActionReset, style: .default) { (_) in
|
||||
self.viewModel.process(viewAction: .forgotPinAlertAction)
|
||||
}
|
||||
|
||||
controller.addAction(resetAction)
|
||||
self.present(controller, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
private func renderConfirmPinToDisable() {
|
||||
self.logoImageView.isHidden = true
|
||||
self.informationLabel.text = VectorL10n.pinProtectionConfirmPinToDisable
|
||||
self.forgotPinButton.isHidden = true
|
||||
}
|
||||
|
||||
private func renderPlaceholdersCount(_ count: Int) {
|
||||
@@ -172,12 +237,15 @@ final class EnterPinCodeViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction private func digitButtonAction(_ sender: UIButton) {
|
||||
self.viewModel.process(viewAction: .digitPressed(sender.tag))
|
||||
}
|
||||
|
||||
@IBAction private func forgotPinButtonAction(_ sender: UIButton) {
|
||||
self.viewModel.process(viewAction: .forgotPinPressed)
|
||||
}
|
||||
|
||||
private func cancelButtonAction() {
|
||||
self.viewModel.process(viewAction: .cancel)
|
||||
|
||||
@@ -25,6 +25,7 @@ final class EnterPinCodeViewModel: EnterPinCodeViewModelType {
|
||||
// MARK: Private
|
||||
|
||||
private let session: MXSession?
|
||||
private var viewMode: SetPinCoordinatorViewMode
|
||||
|
||||
private var currentOperation: MXHTTPOperation?
|
||||
private var firstPin: String = ""
|
||||
@@ -33,6 +34,7 @@ final class EnterPinCodeViewModel: EnterPinCodeViewModelType {
|
||||
self.viewDelegate?.enterPinCodeViewModel(self, didUpdatePlaceholdersCount: currentPin.count)
|
||||
}
|
||||
}
|
||||
private var numberOfFailuresDuringEnterPIN: Int = 0
|
||||
|
||||
// MARK: Public
|
||||
|
||||
@@ -41,8 +43,9 @@ final class EnterPinCodeViewModel: EnterPinCodeViewModelType {
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(session: MXSession?) {
|
||||
init(session: MXSession?, viewMode: SetPinCoordinatorViewMode) {
|
||||
self.session = session
|
||||
self.viewMode = viewMode
|
||||
}
|
||||
|
||||
deinit {
|
||||
@@ -53,11 +56,23 @@ final class EnterPinCodeViewModel: EnterPinCodeViewModelType {
|
||||
|
||||
func process(viewAction: EnterPinCodeViewAction) {
|
||||
switch viewAction {
|
||||
case .loadData:
|
||||
self.loadData()
|
||||
case .digitPressed(let tag):
|
||||
self.digitPressed(tag)
|
||||
case .forgotPinPressed:
|
||||
self.viewDelegate?.enterPinCodeViewModel(self, didUpdateViewState: .forgotPin)
|
||||
case .cancel:
|
||||
self.cancelOperations()
|
||||
self.coordinatorDelegate?.enterPinCodeViewModelDidCancel(self)
|
||||
case .pinsDontMatchAlertAction:
|
||||
// reset pins
|
||||
firstPin.removeAll()
|
||||
currentPin.removeAll()
|
||||
// go back to first state
|
||||
self.update(viewState: .choosePin)
|
||||
case .forgotPinAlertAction:
|
||||
self.coordinatorDelegate?.enterPinCodeViewModelDidCompleteWithReset(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,30 +91,60 @@ final class EnterPinCodeViewModel: EnterPinCodeViewModelType {
|
||||
currentPin += "\(tag)"
|
||||
|
||||
if currentPin.count == 4 {
|
||||
if firstPin.isEmpty {
|
||||
// go to next screen
|
||||
firstPin = currentPin
|
||||
currentPin = ""
|
||||
self.update(viewState: .confirmPin)
|
||||
} else {
|
||||
// check first and second pins
|
||||
if firstPin == currentPin {
|
||||
self.coordinatorDelegate?.enterPinCodeViewModel(self, didCompleteWithPin: firstPin)
|
||||
switch viewMode {
|
||||
case .setPin:
|
||||
// choosing pin
|
||||
if firstPin.isEmpty {
|
||||
// go to next screen
|
||||
firstPin = currentPin
|
||||
currentPin.removeAll()
|
||||
self.update(viewState: .confirmPin)
|
||||
} else {
|
||||
self.update(viewState: .pinsDontMatch(NSError(domain: "", code: -1002, userInfo: nil)))
|
||||
firstPin = ""
|
||||
currentPin = ""
|
||||
self.update(viewState: .enterFirstPin)
|
||||
// check first and second pins
|
||||
if firstPin == currentPin {
|
||||
// complete with a little delay
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
self.coordinatorDelegate?.enterPinCodeViewModel(self, didCompleteWithPin: firstPin)
|
||||
}
|
||||
} else {
|
||||
self.update(viewState: .pinsDontMatch)
|
||||
}
|
||||
}
|
||||
case .unlockByPin, .confirmPinToDeactivate:
|
||||
// unlocking
|
||||
if currentPin != PinCodePreferences.shared.pin {
|
||||
// no match
|
||||
numberOfFailuresDuringEnterPIN += 1
|
||||
if numberOfFailuresDuringEnterPIN < PinCodePreferences.shared.allowedNumberOfTrialsBeforeAlert {
|
||||
self.viewDelegate?.enterPinCodeViewModel(self, didUpdateViewState: .wrongPin)
|
||||
} else {
|
||||
self.viewDelegate?.enterPinCodeViewModel(self, didUpdateViewState: .wrongPinTooManyTimes)
|
||||
numberOfFailuresDuringEnterPIN = 0
|
||||
}
|
||||
|
||||
currentPin.removeAll()
|
||||
} else {
|
||||
// match
|
||||
// complete with a little delay
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
self.coordinatorDelegate?.enterPinCodeViewModelDidComplete(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func loadData() {
|
||||
self.update(viewState: .enterFirstPin)
|
||||
switch viewMode {
|
||||
case .setPin:
|
||||
update(viewState: .choosePin)
|
||||
case .unlockByPin:
|
||||
update(viewState: .unlockByPin)
|
||||
case .confirmPinToDeactivate:
|
||||
update(viewState: .confirmPinToDisable)
|
||||
}
|
||||
}
|
||||
|
||||
private func update(viewState: EnterPinCodeViewState) {
|
||||
|
||||
@@ -24,6 +24,8 @@ protocol EnterPinCodeViewModelViewDelegate: class {
|
||||
}
|
||||
|
||||
protocol EnterPinCodeViewModelCoordinatorDelegate: class {
|
||||
func enterPinCodeViewModelDidComplete(_ viewModel: EnterPinCodeViewModelType)
|
||||
func enterPinCodeViewModelDidCompleteWithReset(_ viewModel: EnterPinCodeViewModelType)
|
||||
func enterPinCodeViewModel(_ viewModel: EnterPinCodeViewModelType, didCompleteWithPin pin: String)
|
||||
func enterPinCodeViewModelDidCancel(_ viewModel: EnterPinCodeViewModelType)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,12 @@ import Foundation
|
||||
|
||||
/// EnterPinCodeViewController view state
|
||||
enum EnterPinCodeViewState {
|
||||
case enterFirstPin
|
||||
case confirmPin
|
||||
case pinsDontMatch(Error)
|
||||
case choosePin // creating pin for the first time, enter for first
|
||||
case confirmPin // creating pin for the first time, confirm
|
||||
case pinsDontMatch // pins don't match
|
||||
case unlockByPin // after pin has been set, enter pin to unlock
|
||||
case wrongPin // after pin has been set, pin entered wrongly
|
||||
case wrongPinTooManyTimes // after pin has been set, pin entered wrongly too many times
|
||||
case forgotPin // after pin has been set, user tapped forgot pin
|
||||
case confirmPinToDisable // after pin has been set, confirm pin to disable pin
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user