2019-04-05 17:09:29 +00:00
// F i l e c r e a t e d f r o m S c r e e n T e m p l a t e
// $ c r e a t e S c r e e n . s h D e v i c e V e r i f i c a t i o n / V e r i f y D e v i c e V e r i f i c a t i o n V e r i f y
/*
Copyright 2019 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 : // w w w . a p a c h e . o r g / l i c e n s e s / L I C E N S E - 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 UIKit
final class DeviceVerificationVerifyViewController : UIViewController {
2019-04-06 22:01:19 +00:00
2019-04-05 17:09:29 +00:00
// MARK: - C o n s t a n t s
// MARK: - P r o p e r t i e s
// MARK: O u t l e t s
@IBOutlet private weak var scrollView : UIScrollView !
2019-04-05 21:48:06 +00:00
@IBOutlet private weak var titleLabel : UILabel !
@IBOutlet private weak var informationLabel : UILabel !
2019-04-24 06:18:56 +00:00
@IBOutlet private weak var decimalLabel : UILabel !
@IBOutlet private weak var emojisCollectionView : UICollectionView !
@IBOutlet private weak var waitingPartnerLabel : UILabel !
@IBOutlet private weak var continueButtonBackgroundView : UIView !
2019-04-05 21:48:06 +00:00
@IBOutlet private weak var continueButton : UIButton !
2019-04-05 17:09:29 +00:00
// MARK: P r i v a t e
private var viewModel : DeviceVerificationVerifyViewModelType !
private var theme : Theme !
private var errorPresenter : MXKErrorPresentation !
private var activityPresenter : ActivityIndicatorPresenter !
// MARK: - S e t u p
class func instantiate ( with viewModel : DeviceVerificationVerifyViewModelType ) -> DeviceVerificationVerifyViewController {
let viewController = StoryboardScene . DeviceVerificationVerifyViewController . initialScene . instantiate ( )
viewController . viewModel = viewModel
viewController . theme = ThemeService . shared ( ) . theme
return viewController
}
// MARK: - L i f e c y c l e
override func viewDidLoad ( ) {
super . viewDidLoad ( )
// D o a n y a d d i t i o n a l s e t u p a f t e r l o a d i n g t h e v i e w .
2019-04-17 10:47:42 +00:00
self . vc_removeBackTitle ( )
2019-04-05 17:09:29 +00:00
self . setupViews ( )
self . errorPresenter = MXKErrorAlertPresentation ( )
2019-04-18 21:12:01 +00:00
self . activityPresenter = ActivityIndicatorPresenter ( )
2019-04-05 17:09:29 +00:00
self . registerThemeServiceDidChangeThemeNotification ( )
self . update ( theme : self . theme )
self . viewModel . viewDelegate = self
2019-12-10 14:45:36 +00:00
self . viewModel . process ( viewAction : . loadData )
2019-04-05 17:09:29 +00:00
}
override func viewWillAppear ( _ animated : Bool ) {
super . viewWillAppear ( animated )
2019-04-16 09:36:51 +00:00
// H i d e b a c k b u t t o n
self . navigationItem . setHidesBackButton ( true , animated : animated )
2019-04-05 17:09:29 +00:00
}
override var preferredStatusBarStyle : UIStatusBarStyle {
return self . theme . statusBarStyle
}
// MARK: - P r i v a t e
private func update ( theme : Theme ) {
self . theme = theme
self . view . backgroundColor = theme . headerBackgroundColor
if let navigationBar = self . navigationController ? . navigationBar {
theme . applyStyle ( onNavigationBar : navigationBar )
}
2019-04-05 21:48:06 +00:00
self . titleLabel . textColor = theme . textPrimaryColor
self . informationLabel . textColor = theme . textPrimaryColor
2019-04-19 09:31:19 +00:00
self . decimalLabel . textColor = theme . textPrimaryColor
2019-04-05 21:48:06 +00:00
self . waitingPartnerLabel . textColor = theme . textPrimaryColor
2019-04-05 17:09:29 +00:00
2019-05-06 06:21:04 +00:00
self . continueButtonBackgroundView . backgroundColor = theme . backgroundColor
2019-04-05 21:48:06 +00:00
theme . applyStyle ( onButton : self . continueButton )
2019-04-08 15:10:40 +00:00
emojisCollectionView . reloadData ( )
2019-04-05 17:09:29 +00:00
}
private func registerThemeServiceDidChangeThemeNotification ( ) {
NotificationCenter . default . addObserver ( self , selector : #selector ( themeDidChange ) , name : . themeServiceDidChangeTheme , object : nil )
}
@objc private func themeDidChange ( ) {
self . update ( theme : ThemeService . shared ( ) . theme )
}
private func setupViews ( ) {
let cancelBarButtonItem = MXKBarButtonItem ( title : VectorL10n . cancel , style : . plain ) { [ weak self ] in
self ? . cancelButtonAction ( )
}
self . navigationItem . rightBarButtonItem = cancelBarButtonItem
self . scrollView . keyboardDismissMode = . interactive
2019-04-05 21:48:06 +00:00
2020-01-31 14:07:30 +00:00
let isVerificationByEmoji = viewModel . emojis != nil
if isVerificationByEmoji {
2019-04-19 09:31:19 +00:00
self . decimalLabel . isHidden = true
} else {
self . emojisCollectionView . isHidden = true
self . decimalLabel . text = self . viewModel . decimal
}
2020-01-31 14:07:30 +00:00
let title : String
let instructionText : String
let adviceText : String
switch viewModel . verificationKind {
case . device :
title = VectorL10n . deviceVerificationTitle
instructionText = isVerificationByEmoji ? VectorL10n . deviceVerificationVerifyTitleEmoji : VectorL10n . deviceVerificationVerifyTitleNumber
adviceText = VectorL10n . deviceVerificationSecurityAdvice
case . user :
title = " Verify user "
instructionText = isVerificationByEmoji ? " Verify this user by confirming the following unique emoji appears on their screen, in the same order. " : " Verify this user by confirming the following numbers appear on their screen, in the same order. "
adviceText = VectorL10n . deviceVerificationSecurityAdvice
}
2019-04-19 09:31:19 +00:00
2020-01-31 14:07:30 +00:00
self . title = title
self . titleLabel . text = instructionText
self . informationLabel . text = adviceText
2019-04-05 21:48:06 +00:00
self . waitingPartnerLabel . text = VectorL10n . deviceVerificationVerifyWaitPartner
self . waitingPartnerLabel . isHidden = true
2019-04-15 09:06:14 +00:00
self . continueButton . setTitle ( VectorL10n . continue , for : . normal )
2019-04-05 17:09:29 +00:00
}
private func render ( viewState : DeviceVerificationVerifyViewState ) {
switch viewState {
case . loading :
self . renderLoading ( )
case . loaded :
2019-04-11 15:59:12 +00:00
self . renderVerified ( )
case . cancelled ( let reason ) :
self . renderCancelled ( reason : reason )
case . cancelledByMe ( let reason ) :
self . renderCancelledByMe ( reason : reason )
2019-04-05 17:09:29 +00:00
case . error ( let error ) :
self . render ( error : error )
}
}
private func renderLoading ( ) {
self . activityPresenter . presentActivityIndicator ( on : self . view , animated : true )
}
2019-04-11 15:59:12 +00:00
private func renderVerified ( ) {
2019-04-05 17:09:29 +00:00
self . activityPresenter . removeCurrentActivityIndicator ( animated : true )
2019-04-05 21:48:06 +00:00
self . continueButtonBackgroundView . isHidden = true
self . waitingPartnerLabel . isHidden = false
2019-04-05 17:09:29 +00:00
}
2019-04-11 15:59:12 +00:00
private func renderCancelled ( reason : MXTransactionCancelCode ) {
2019-04-11 17:38:46 +00:00
self . activityPresenter . removeCurrentActivityIndicator ( animated : true )
self . errorPresenter . presentError ( from : self , title : " " , message : VectorL10n . deviceVerificationCancelled , animated : true ) {
self . viewModel . process ( viewAction : . cancel )
}
2019-04-11 15:59:12 +00:00
}
private func renderCancelledByMe ( reason : MXTransactionCancelCode ) {
2019-04-17 11:05:18 +00:00
if reason . value != MXTransactionCancelCode . user ( ) . value {
self . activityPresenter . removeCurrentActivityIndicator ( animated : true )
self . errorPresenter . presentError ( from : self , title : " " , message : VectorL10n . deviceVerificationCancelledByMe ( reason . humanReadable ) , animated : true ) {
self . viewModel . process ( viewAction : . cancel )
}
2019-10-23 15:09:58 +00:00
} else {
self . activityPresenter . removeCurrentActivityIndicator ( animated : true )
2019-04-17 11:05:18 +00:00
}
2019-04-11 15:59:12 +00:00
}
2019-04-05 17:09:29 +00:00
private func render ( error : Error ) {
self . activityPresenter . removeCurrentActivityIndicator ( animated : true )
self . errorPresenter . presentError ( from : self , forError : error , animated : true , handler : nil )
}
// MARK: - A c t i o n s
2019-04-05 21:48:06 +00:00
@IBAction private func continueButtonAction ( _ sender : Any ) {
self . viewModel . process ( viewAction : . confirm )
2019-04-05 17:09:29 +00:00
}
private func cancelButtonAction ( ) {
self . viewModel . process ( viewAction : . cancel )
}
}
// MARK: - D e v i c e V e r i f i c a t i o n V e r i f y V i e w M o d e l V i e w D e l e g a t e
extension DeviceVerificationVerifyViewController : DeviceVerificationVerifyViewModelViewDelegate {
func deviceVerificationVerifyViewModel ( _ viewModel : DeviceVerificationVerifyViewModelType , didUpdateViewState viewSate : DeviceVerificationVerifyViewState ) {
self . render ( viewState : viewSate )
}
}
2019-04-06 22:01:19 +00:00
extension DeviceVerificationVerifyViewController : UICollectionViewDataSource {
func collectionView ( _ collectionView : UICollectionView , numberOfItemsInSection section : Int ) -> Int {
guard let emojis = self . viewModel . emojis else {
return 0
}
return emojis . count
}
func collectionView ( _ collectionView : UICollectionView , cellForItemAt indexPath : IndexPath ) -> UICollectionViewCell {
2020-01-31 14:07:30 +00:00
let cell = collectionView . dequeueReusableCell ( for : indexPath , cellType : VerifyEmojiCollectionViewCell . self )
2019-04-06 22:01:19 +00:00
guard let emoji = self . viewModel . emojis ? [ indexPath . row ] else {
return UICollectionViewCell ( )
}
cell . emoji . text = emoji . emoji
2019-04-16 07:33:25 +00:00
cell . name . text = VectorL10n . tr ( " Vector " , " device_verification_emoji_ \( emoji . name ) " )
2019-04-08 15:10:40 +00:00
cell . update ( theme : self . theme )
2019-04-06 22:01:19 +00:00
return cell
}
}