// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit import PromiseKit import SignalCoreKit import SignalUtilitiesKit import SessionUIKit import SessionUtilitiesKit final class SAEScreenLockViewController: ScreenLockViewController, ScreenLockViewDelegate { private var hasShownAuthUIOnce: Bool = false private var isShowingAuthUI: Bool = false private weak var shareViewDelegate: ShareViewDelegate? // MARK: - Initialization init(shareViewDelegate: ShareViewDelegate) { super.init(nibName: nil, bundle: nil) self.shareViewDelegate = shareViewDelegate self.delegate = self } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { OWSLogger.verbose("Dealloc: \(type(of: self))") } // MARK: - UI private lazy var gradientBackground: CAGradientLayer = { let layer: CAGradientLayer = CAGradientLayer() let gradientStartColor: UIColor = (LKAppModeUtilities.isLightMode ? UIColor(rgbHex: 0xFCFCFC) : UIColor(rgbHex: 0x171717) ) let gradientEndColor: UIColor = (LKAppModeUtilities.isLightMode ? UIColor(rgbHex: 0xFFFFFF) : UIColor(rgbHex: 0x121212) ) layer.colors = [gradientStartColor.cgColor, gradientEndColor.cgColor] return layer }() private lazy var titleLabel: UILabel = { let titleLabel: UILabel = UILabel() titleLabel.font = UIFont.boldSystemFont(ofSize: Values.veryLargeFontSize) titleLabel.text = "vc_share_title".localized() titleLabel.textColor = Colors.text return titleLabel }() private lazy var closeButton: UIBarButtonItem = { let closeButton: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "X"), style: .plain, target: self, action: #selector(dismissPressed)) closeButton.tintColor = Colors.text return closeButton }() // MARK: - Lifecycle override func loadView() { super.loadView() UIView.appearance().tintColor = Colors.text self.view.backgroundColor = UIColor.clear self.view.layer.insertSublayer(gradientBackground, at: 0) self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default) self.navigationController?.navigationBar.shadowImage = UIImage() self.navigationController?.navigationBar.isTranslucent = false self.navigationController?.navigationBar.tintColor = Colors.navigationBarBackground self.navigationItem.titleView = titleLabel self.navigationItem.leftBarButtonItem = closeButton setupLayout() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.ensureUI() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) self.ensureUI() // Auto-show the auth UI f if !hasShownAuthUIOnce { hasShownAuthUIOnce = true self.tryToPresentAuthUIToUnlockScreenLock() } } // MARK: - Layout private func setupLayout() { gradientBackground.frame = UIScreen.main.bounds } // MARK: - Functions private func tryToPresentAuthUIToUnlockScreenLock() { AssertIsOnMainThread() // If we're already showing the auth UI; abort. if self.isShowingAuthUI { return } OWSLogger.info("try to unlock screen lock") isShowingAuthUI = true OWSScreenLock.shared.tryToUnlockScreenLock( success: { [weak self] in AssertIsOnMainThread() OWSLogger.info("unlock screen lock succeeded.") self?.isShowingAuthUI = false self?.shareViewDelegate?.shareViewWasUnlocked() }, failure: { [weak self] error in AssertIsOnMainThread() OWSLogger.info("unlock screen lock failed.") self?.isShowingAuthUI = false self?.ensureUI() self?.showScreenLockFailureAlert(message: error.localizedDescription) }, unexpectedFailure: { [weak self] error in AssertIsOnMainThread() OWSLogger.info("unlock screen lock unexpectedly failed.") self?.isShowingAuthUI = false // Local Authentication isn't working properly. // This isn't covered by the docs or the forums but in practice // it appears to be effective to retry again after waiting a bit. DispatchQueue.main.async { self?.ensureUI() } }, cancel: { [weak self] in AssertIsOnMainThread() OWSLogger.info("unlock screen lock cancelled.") self?.isShowingAuthUI = false self?.ensureUI() } ) self.ensureUI() } private func ensureUI() { self.updateUI(with: .screenLock, isLogoAtTop: false, animated: false) } private func showScreenLockFailureAlert(message: String) { AssertIsOnMainThread() OWSAlerts.showAlert( // Title for alert indicating that screen lock could not be unlocked. title: "SCREEN_LOCK_UNLOCK_FAILED".localized(), message: message, buttonTitle: nil, buttonAction: { [weak self] action in // After the alert, update the UI self?.ensureUI() }, fromViewController: self ) } // MARK: - Transitions @objc private func dismissPressed() { OWSLogger.debug("unlock screen lock cancelled.") self.cancelShareExperience() } private func cancelShareExperience() { self.shareViewDelegate?.shareViewWasCancelled() } // MARK: - ScreenLockViewDelegate func unlockButtonWasTapped() { AssertIsOnMainThread() OWSLogger.info("unlockButtonWasTapped") self.tryToPresentAuthUIToUnlockScreenLock() } }