Implement logic and UI

This commit is contained in:
ismailgulek 2020-09-17 14:07:12 +03:00
parent 9094ed128b
commit aa41d75fd4
4 changed files with 126 additions and 33 deletions

View file

@ -63,41 +63,75 @@
<constraint firstItem="UHg-qE-anw" firstAttribute="top" secondItem="ztg-5t-ECh" secondAttribute="top" constant="8" id="uj5-KC-7FD"/>
</constraints>
</view>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="24" translatesAutoresizingMaskIntoConstraints="NO" id="xi9-P9-8WP">
<rect key="frame" x="103.66666666666669" y="171.66666666666666" width="168" height="24"/>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="l5x-qO-sdf">
<rect key="frame" x="2" y="153.33333333333334" width="371" height="78.666666666666657"/>
<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"/>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="24" translatesAutoresizingMaskIntoConstraints="NO" id="xi9-P9-8WP">
<rect key="frame" x="101.66666666666669" y="0.0" 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="47.999999999999986" 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="95.999999999999986" 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>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="CBc-7Z-a5Z">
<rect key="frame" x="0.0" y="23.999999999999996" width="371" height="54.666666666666657"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Q0w-RD-JD3">
<rect key="frame" x="0.0" y="8" width="371" height="2"/>
<color key="backgroundColor" systemColor="systemRedColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="2" id="thx-rI-kOC"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="For security reasons, this PIN isn't available. Please try another PIN" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="H5g-FI-xEj">
<rect key="frame" x="8" y="18" width="355" height="28.666666666666671"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" systemColor="systemRedColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<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 firstItem="H5g-FI-xEj" firstAttribute="top" secondItem="Q0w-RD-JD3" secondAttribute="bottom" constant="8" id="Ass-T4-TrH"/>
<constraint firstAttribute="trailing" secondItem="Q0w-RD-JD3" secondAttribute="trailing" id="KBv-AB-wkc"/>
<constraint firstAttribute="trailing" secondItem="H5g-FI-xEj" secondAttribute="trailing" constant="8" id="SK3-JE-bIK"/>
<constraint firstItem="Q0w-RD-JD3" firstAttribute="leading" secondItem="CBc-7Z-a5Z" secondAttribute="leading" id="ZwL-3A-TND"/>
<constraint firstItem="Q0w-RD-JD3" firstAttribute="top" secondItem="CBc-7Z-a5Z" secondAttribute="top" constant="8" id="fgi-r2-9bD"/>
<constraint firstItem="H5g-FI-xEj" firstAttribute="leading" secondItem="CBc-7Z-a5Z" secondAttribute="leading" constant="8" id="idG-Mm-XPq"/>
<constraint firstAttribute="bottom" secondItem="H5g-FI-xEj" secondAttribute="bottom" constant="8" id="xhM-lP-67t"/>
</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="47.999999999999986" 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="95.999999999999986" 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>
</view>
</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="65.666666666666686" y="281.33333333333331" width="244" height="302.99999999999994"/>
<rect key="frame" x="65.666666666666686" y="299.66666666666669" width="244" height="303.00000000000006"/>
<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"/>
@ -182,7 +216,7 @@
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="32" translatesAutoresizingMaskIntoConstraints="NO" id="YeU-UN-Uo0">
<rect key="frame" x="0.0" y="162" width="244" height="60"/>
<rect key="frame" x="0.0" y="161.99999999999994" width="244" height="60"/>
<subviews>
<button opaque="NO" tag="7" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Lnz-5u-oFb">
<rect key="frame" x="0.0" y="0.0" width="60" height="60"/>
@ -223,7 +257,7 @@
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" spacing="32" translatesAutoresizingMaskIntoConstraints="NO" id="Nrp-tS-u1k">
<rect key="frame" x="0.0" y="243.00000000000006" width="244" height="60"/>
<rect key="frame" x="0.0" y="242.99999999999994" width="244" height="60"/>
<subviews>
<button opaque="NO" userInteractionEnabled="NO" tag="-99" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DEv-rc-fGB">
<rect key="frame" x="0.0" y="0.0" width="60" height="60"/>
@ -303,6 +337,9 @@
<viewLayoutGuide key="safeArea" id="bFg-jh-JZB"/>
</view>
<connections>
<outlet property="blockedPinLabel" destination="H5g-FI-xEj" id="v2X-MF-cPQ"/>
<outlet property="blockedPinLineView" destination="Q0w-RD-JD3" id="7d4-JM-Mvl"/>
<outlet property="blockedPinView" destination="CBc-7Z-a5Z" id="4DN-Tq-CMW"/>
<outlet property="digitsStackView" destination="W0M-eq-abZ" id="xnb-6w-dtC"/>
<outlet property="forgotPinButton" destination="CRt-Fb-0Dq" id="kHp-wn-P0o"/>
<outlet property="inactiveLogoImageView" destination="8qz-Yk-9a4" id="DFZ-fF-0NC"/>

View file

@ -35,6 +35,9 @@ final class EnterPinCodeViewController: UIViewController {
@IBOutlet private weak var inactiveLogoImageView: UIImageView!
@IBOutlet private weak var logoImageView: UIImageView!
@IBOutlet private weak var placeholderStackView: UIStackView!
@IBOutlet private weak var blockedPinView: UIView!
@IBOutlet private weak var blockedPinLineView: UIView!
@IBOutlet private weak var blockedPinLabel: UILabel!
@IBOutlet private weak var digitsStackView: UIStackView!
@IBOutlet private weak var informationLabel: UILabel!
@IBOutlet private weak var forgotPinButton: UIButton!
@ -116,6 +119,8 @@ final class EnterPinCodeViewController: UIViewController {
}
self.informationLabel.textColor = theme.textPrimaryColor
self.blockedPinLineView.backgroundColor = theme.noticeColor
self.blockedPinLabel.textColor = theme.noticeColor
updateThemesOfAllImages(in: placeholderStackView, with: theme)
updateThemesOfAllButtons(in: digitsStackView, with: theme)
@ -157,6 +162,8 @@ final class EnterPinCodeViewController: UIViewController {
self.title = ""
blockedPinLabel.text = VectorL10n.pinProtectionBlockedPin
placeholderStackView.vc_removeAllArrangedSubviews()
for i in 0..<PinCodePreferences.shared.numberOfDigits {
let imageView = UIImageView(image: Asset.Images.selectionUntick.image)
@ -183,6 +190,8 @@ final class EnterPinCodeViewController: UIViewController {
switch viewState {
case .choosePin:
self.renderChoosePin()
case .blockedPin:
self.renderBlockedPin()
case .confirmPin:
self.renderConfirmPin()
case .pinsDontMatch:
@ -208,12 +217,25 @@ final class EnterPinCodeViewController: UIViewController {
self.logoImageView.isHidden = true
self.informationLabel.text = VectorL10n.pinProtectionChoosePin
self.forgotPinButton.isHidden = true
self.blockedPinView.isHidden = true
}
private func renderBlockedPin() {
self.inactiveView.isHidden = true
self.mainStackView.isHidden = false
self.logoImageView.isHidden = true
self.informationLabel.text = VectorL10n.pinProtectionChoosePin
self.forgotPinButton.isHidden = true
self.blockedPinView.isHidden = false
renderPlaceholdersCount(.max, error: true)
}
private func renderConfirmPin() {
self.inactiveView.isHidden = true
self.mainStackView.isHidden = false
self.informationLabel.text = VectorL10n.pinProtectionConfirmPin
self.blockedPinView.isHidden = true
// reset placeholders
renderPlaceholdersCount(0)
@ -236,11 +258,13 @@ final class EnterPinCodeViewController: UIViewController {
self.logoImageView.isHidden = false
self.informationLabel.text = VectorL10n.pinProtectionEnterPin
self.forgotPinButton.isHidden = false
self.blockedPinView.isHidden = true
}
private func renderWrongPin() {
self.inactiveView.isHidden = true
self.mainStackView.isHidden = false
self.blockedPinView.isHidden = true
self.placeholderStackView.vc_shake()
}
@ -276,19 +300,25 @@ final class EnterPinCodeViewController: UIViewController {
self.logoImageView.isHidden = true
self.informationLabel.text = VectorL10n.pinProtectionConfirmPinToDisable
self.forgotPinButton.isHidden = true
self.blockedPinView.isHidden = true
}
private func renderInactive() {
self.hideCancelButton()
self.inactiveView.isHidden = false
self.mainStackView.isHidden = true
self.blockedPinView.isHidden = true
}
private func renderPlaceholdersCount(_ count: Int) {
private func renderPlaceholdersCount(_ count: Int, error: Bool = false) {
UIView.animate(withDuration: 0.3) {
for case let imageView as UIImageView in self.placeholderStackView.arrangedSubviews {
if imageView.tag < count {
imageView.image = Asset.Images.placeholder.image
if error {
imageView.image = Asset.Images.placeholder.image.vc_tintedImage(usingColor: self.theme.noticeColor)
} else {
imageView.image = Asset.Images.placeholder.image
}
} else {
imageView.image = Asset.Images.selectionUntick.image
}

View file

@ -84,9 +84,28 @@ final class EnterPinCodeViewModel: EnterPinCodeViewModelType {
return
} else {
currentPin.removeLast()
// switch to setPin if blocked
if viewMode == .blockedPin {
// clear error UI
update(viewState: .choosePin)
// switch to normal flow
viewMode = .setPin
}
}
} else {
// a digit tapped
// switch to setPin if blocked
if viewMode == .blockedPin {
// clear old pin first
currentPin.removeAll()
// clear error UI
update(viewState: .choosePin)
// switch to normal flow
viewMode = .setPin
}
// add new digit
currentPin += String(tag)
if currentPin.count == pinCodePreferences.numberOfDigits {
@ -94,6 +113,12 @@ final class EnterPinCodeViewModel: EnterPinCodeViewModelType {
case .setPin:
// choosing pin
if firstPin.isEmpty {
// check if this PIN is allowed
if pinCodePreferences.blockedPINs.contains(currentPin) {
viewMode = .blockedPin
update(viewState: .blockedPin)
return
}
// go to next screen
firstPin = currentPin
currentPin.removeAll()

View file

@ -21,6 +21,7 @@ import Foundation
/// EnterPinCodeViewController view state
enum EnterPinCodeViewState {
case choosePin // creating pin for the first time, enter for first
case blockedPin // creating pin for the first time, provided pin is blocked
case confirmPin // creating pin for the first time, confirm
case pinsDontMatch // pins don't match
case unlock // after pin has been set, enter pin to unlock