Refactoring secure backup references.

This commit is contained in:
SBiOSoftWhare
2020-06-26 13:07:53 +02:00
parent 808de8b15c
commit 17c5cdf06e
17 changed files with 205 additions and 142 deletions
@@ -0,0 +1,157 @@
/*
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 UIKit
import Reusable
final class SecureKeyBackupSetupIntroCell: UIView, NibOwnerLoadable, Themable {
// MARK: - Constants
private enum ImageAlpha {
static let highlighted: CGFloat = 0.3
}
// MARK: - Properties
// MARK: Outlets
@IBOutlet private weak var backgroundView: UIView!
@IBOutlet private weak var imageView: UIImageView!
@IBOutlet private weak var titleLabel: UILabel!
@IBOutlet private weak var informationLabel: UILabel!
@IBOutlet private weak var accessoryImageView: UIImageView!
@IBOutlet private weak var separatorView: UIView!
// MARK: Private
private var theme: Theme?
private var isHighlighted: Bool = false {
didSet {
self.updateView()
}
}
// MARK: Public
var action: (() -> Void)?
// MARK: Setup
private func commonInit() {
self.setupGestureRecognizer()
let accessoryTemplateImage = Asset.Images.disclosureIcon.image.withRenderingMode(.alwaysTemplate)
self.accessoryImageView.image = accessoryTemplateImage
self.accessoryImageView.highlightedImage = accessoryTemplateImage.vc_withAlpha(ImageAlpha.highlighted)
}
convenience init() {
self.init(frame: CGRect.zero)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.loadNibContent()
self.commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.loadNibContent()
self.commonInit()
}
// MARK: - Public
func update(theme: Theme) {
self.theme = theme
self.backgroundView.backgroundColor = theme.backgroundColor
self.imageView.tintColor = theme.textPrimaryColor
self.titleLabel.textColor = theme.tintColor
self.informationLabel.textColor = theme.textSecondaryColor
self.accessoryImageView.tintColor = theme.textSecondaryColor
self.separatorView.backgroundColor = theme.lineBreakColor
self.updateView()
}
func fill(title: String, information: String, image: UIImage) {
let templateImage = image.withRenderingMode(.alwaysTemplate)
self.imageView.image = templateImage
self.imageView.highlightedImage = templateImage.vc_withAlpha(ImageAlpha.highlighted)
self.titleLabel.text = title
self.informationLabel.text = information
self.setupAccessibility(title: title, isEnabled: true)
self.updateView()
}
// MARK: - Private
private func setupAccessibility(title: String, isEnabled: Bool) {
self.isAccessibilityElement = true
self.accessibilityLabel = title
self.accessibilityTraits = .button
if !isEnabled {
self.accessibilityTraits.insert(.notEnabled)
}
}
private func setupGestureRecognizer() {
let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(buttonAction(_:)))
gestureRecognizer.minimumPressDuration = 0
self.addGestureRecognizer(gestureRecognizer)
}
private func updateView() {
if let theme = self.theme {
self.backgroundView.backgroundColor = self.isHighlighted ? theme.overlayBackgroundColor : theme.backgroundColor
}
self.imageView.isHighlighted = self.isHighlighted
self.accessoryImageView.isHighlighted = self.isHighlighted
}
// MARK: - Actions
@objc private func buttonAction(_ sender: UILongPressGestureRecognizer) {
let isBackgroundViewTouched = sender.vc_isTouchingInside()
switch sender.state {
case .began, .changed:
self.isHighlighted = isBackgroundViewTouched
case .ended:
self.isHighlighted = false
if isBackgroundViewTouched {
self.action?()
}
case .cancelled:
self.isHighlighted = false
default:
break
}
}
}
@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SecureKeyBackupSetupIntroCell" customModule="Riot" customModuleProvider="target">
<connections>
<outlet property="accessoryImageView" destination="N76-Fa-onz" id="nYX-r6-t7R"/>
<outlet property="backgroundView" destination="WrK-Wq-nzz" id="kgB-Zb-g9N"/>
<outlet property="imageView" destination="PfY-xb-Psn" id="qgq-7B-nSS"/>
<outlet property="informationLabel" destination="q9X-wE-MwV" id="a4J-ZK-teU"/>
<outlet property="separatorView" destination="eKS-Ze-zhB" id="TF5-27-XFD"/>
<outlet property="titleLabel" destination="eGd-jn-myj" id="MyG-x1-33i"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="426" height="122"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WrK-Wq-nzz">
<rect key="frame" x="0.0" y="0.0" width="426" height="122"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="secrets_setup_key" translatesAutoresizingMaskIntoConstraints="NO" id="PfY-xb-Psn">
<rect key="frame" x="19" y="18" width="24" height="24"/>
<constraints>
<constraint firstAttribute="width" secondItem="PfY-xb-Psn" secondAttribute="height" multiplier="1:1" id="71S-sH-VTt"/>
<constraint firstAttribute="width" constant="24" id="Shz-Df-UoM"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="252" text="Use a Security Key" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eGd-jn-myj">
<rect key="frame" x="63" y="20" width="317" height="19.5"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.01176470588" green="0.70196078429999997" blue="0.50588235290000005" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Generate a security key to store somewhere safe like a password manager or a safe." lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="q9X-wE-MwV">
<rect key="frame" x="63" y="49.5" width="317" height="52.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="disclosure_icon" translatesAutoresizingMaskIntoConstraints="NO" id="N76-Fa-onz">
<rect key="frame" x="400" y="55" width="6" height="12"/>
<constraints>
<constraint firstAttribute="width" constant="6" id="23d-HN-WiD"/>
<constraint firstAttribute="height" constant="12" id="4Yt-I6-2YL"/>
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eKS-Ze-zhB" userLabel="separatorView">
<rect key="frame" x="0.0" y="121" width="426" height="1"/>
<color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="5hw-tO-Dw9"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="PfY-xb-Psn" firstAttribute="centerY" secondItem="eGd-jn-myj" secondAttribute="centerY" id="3Ha-I2-24v"/>
<constraint firstAttribute="trailing" secondItem="N76-Fa-onz" secondAttribute="trailing" constant="20" id="9C0-mv-gaL"/>
<constraint firstAttribute="trailing" secondItem="eKS-Ze-zhB" secondAttribute="trailing" id="BlW-zS-HoC"/>
<constraint firstItem="N76-Fa-onz" firstAttribute="leading" secondItem="eGd-jn-myj" secondAttribute="trailing" constant="20" id="CKw-l3-vdY"/>
<constraint firstItem="PfY-xb-Psn" firstAttribute="leading" secondItem="WrK-Wq-nzz" secondAttribute="leading" constant="19" id="NXM-42-myZ"/>
<constraint firstItem="q9X-wE-MwV" firstAttribute="leading" secondItem="eGd-jn-myj" secondAttribute="leading" id="Ovd-Xd-S7O"/>
<constraint firstAttribute="bottom" secondItem="q9X-wE-MwV" secondAttribute="bottom" constant="20" id="S9M-i1-KQ6"/>
<constraint firstItem="q9X-wE-MwV" firstAttribute="trailing" secondItem="eGd-jn-myj" secondAttribute="trailing" id="YU0-XX-vAU"/>
<constraint firstItem="eGd-jn-myj" firstAttribute="top" secondItem="WrK-Wq-nzz" secondAttribute="top" constant="20" id="cAQ-R0-bco"/>
<constraint firstAttribute="bottom" secondItem="eKS-Ze-zhB" secondAttribute="bottom" id="cnI-2n-T2c"/>
<constraint firstItem="q9X-wE-MwV" firstAttribute="top" secondItem="eGd-jn-myj" secondAttribute="bottom" constant="10" id="kYI-mK-UC1"/>
<constraint firstItem="N76-Fa-onz" firstAttribute="centerY" secondItem="WrK-Wq-nzz" secondAttribute="centerY" id="rG1-iI-v3T"/>
<constraint firstItem="eKS-Ze-zhB" firstAttribute="leading" secondItem="WrK-Wq-nzz" secondAttribute="leading" id="raL-7N-TKN"/>
<constraint firstItem="eGd-jn-myj" firstAttribute="leading" secondItem="PfY-xb-Psn" secondAttribute="trailing" constant="20" id="zi9-PT-A2O"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="WrK-Wq-nzz" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="dAF-lS-uGD"/>
<constraint firstItem="WrK-Wq-nzz" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="fAW-fz-tYP"/>
<constraint firstAttribute="bottom" secondItem="WrK-Wq-nzz" secondAttribute="bottom" id="lU3-Jc-aUe"/>
<constraint firstAttribute="trailing" secondItem="WrK-Wq-nzz" secondAttribute="trailing" id="lUt-K8-wV9"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<point key="canvasLocation" x="146.37681159420291" y="-122.54464285714285"/>
</view>
</objects>
<resources>
<image name="disclosure_icon" width="6" height="12"/>
<image name="secrets_setup_key" width="48" height="48"/>
</resources>
</document>
@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="LSX-Vb-DIu">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Secure Key Backup Setup Intro View Controller-->
<scene sceneID="srP-wo-sRp">
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="LSX-Vb-DIu" customClass="SecureKeyBackupSetupIntroViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="pmD-eJ-G3m">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="mvC-lc-ylT">
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Fub-g4-o4o">
<rect key="frame" x="0.0" y="0.0" width="414" height="391"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="79w-lw-B8z">
<rect key="frame" x="0.0" y="0.0" width="414" height="391"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Safe guard against losing access to encrypted messages &amp; data by backing up encryption keys on your server." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DZf-di-JcI">
<rect key="frame" x="20" y="30" width="374" height="54"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tul-b1-7gY">
<rect key="frame" x="0.0" y="114" width="414" height="257"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="Jc9-fc-Vwh">
<rect key="frame" x="0.0" y="0.0" width="414" height="257"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="d77-sQ-Uio">
<rect key="frame" x="0.0" y="0.0" width="414" height="1"/>
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="Gwq-JQ-4Zj"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RQF-pm-g37" customClass="SecureKeyBackupSetupIntroCell" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="1" width="414" height="128"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="128" placeholder="YES" id="dOF-Du-P3S"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Yps-bc-ruH" customClass="SecureKeyBackupSetupIntroCell" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="129" width="414" height="128"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="128" placeholder="YES" id="Gpk-nd-3G2"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="d77-sQ-Uio" firstAttribute="width" secondItem="Jc9-fc-Vwh" secondAttribute="width" id="S3Q-F0-nwW"/>
<constraint firstItem="RQF-pm-g37" firstAttribute="width" secondItem="Jc9-fc-Vwh" secondAttribute="width" id="fZs-9s-jUW"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Jc9-fc-Vwh" firstAttribute="top" secondItem="tul-b1-7gY" secondAttribute="top" id="1Vr-Y3-t2r"/>
<constraint firstItem="Jc9-fc-Vwh" firstAttribute="leading" secondItem="tul-b1-7gY" secondAttribute="leading" id="4op-QY-3vL"/>
<constraint firstAttribute="bottom" secondItem="Jc9-fc-Vwh" secondAttribute="bottom" id="FqW-Rc-K1T"/>
<constraint firstAttribute="trailing" secondItem="Jc9-fc-Vwh" secondAttribute="trailing" id="QcB-wY-lCT"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="tul-b1-7gY" secondAttribute="trailing" id="TFD-iw-7y4"/>
<constraint firstItem="tul-b1-7gY" firstAttribute="top" secondItem="DZf-di-JcI" secondAttribute="bottom" constant="30" id="Ury-rf-0xS"/>
<constraint firstAttribute="trailing" secondItem="DZf-di-JcI" secondAttribute="trailing" constant="20" id="bS3-Gc-DyD"/>
<constraint firstAttribute="width" priority="750" constant="500" id="fuc-5G-HCd"/>
<constraint firstItem="tul-b1-7gY" firstAttribute="leading" secondItem="79w-lw-B8z" secondAttribute="leading" id="gYj-LZ-esB"/>
<constraint firstItem="DZf-di-JcI" firstAttribute="leading" secondItem="79w-lw-B8z" secondAttribute="leading" constant="20" id="nPo-3g-WcD"/>
<constraint firstAttribute="bottom" secondItem="tul-b1-7gY" secondAttribute="bottom" constant="20" id="qYa-0L-wrp"/>
<constraint firstItem="DZf-di-JcI" firstAttribute="top" secondItem="79w-lw-B8z" secondAttribute="top" constant="30" id="t80-aS-JzH"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="79w-lw-B8z" firstAttribute="centerX" secondItem="Fub-g4-o4o" secondAttribute="centerX" id="5Az-52-cbQ"/>
<constraint firstItem="79w-lw-B8z" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Fub-g4-o4o" secondAttribute="leading" id="Aei-Nr-Wzb"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="79w-lw-B8z" secondAttribute="trailing" id="CBG-M0-Uqd"/>
<constraint firstAttribute="bottom" secondItem="79w-lw-B8z" secondAttribute="bottom" id="JbI-yr-iot"/>
<constraint firstItem="79w-lw-B8z" firstAttribute="top" secondItem="Fub-g4-o4o" secondAttribute="top" id="s6B-HO-iVd"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="Fub-g4-o4o" secondAttribute="trailing" id="N9B-1U-3j7"/>
<constraint firstItem="Fub-g4-o4o" firstAttribute="width" secondItem="mvC-lc-ylT" secondAttribute="width" id="NzH-5s-nuz"/>
<constraint firstAttribute="bottom" secondItem="Fub-g4-o4o" secondAttribute="bottom" id="gYj-V0-rlA"/>
<constraint firstItem="Fub-g4-o4o" firstAttribute="leading" secondItem="mvC-lc-ylT" secondAttribute="leading" id="jHU-W6-8Ny"/>
<constraint firstItem="Fub-g4-o4o" firstAttribute="top" secondItem="mvC-lc-ylT" secondAttribute="top" id="nFB-Af-IUw"/>
</constraints>
</scrollView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="JkH-9M-Qql" firstAttribute="top" secondItem="mvC-lc-ylT" secondAttribute="top" id="5Vc-aR-jAF"/>
<constraint firstItem="mvC-lc-ylT" firstAttribute="leading" secondItem="JkH-9M-Qql" secondAttribute="leading" id="HBB-YL-5P5"/>
<constraint firstAttribute="bottom" secondItem="mvC-lc-ylT" secondAttribute="bottom" id="dn5-CG-87P"/>
<constraint firstItem="JkH-9M-Qql" firstAttribute="trailing" secondItem="mvC-lc-ylT" secondAttribute="trailing" id="xj4-xF-VEA"/>
</constraints>
<viewLayoutGuide key="safeArea" id="JkH-9M-Qql"/>
</view>
<connections>
<outlet property="informationLabel" destination="DZf-di-JcI" id="czR-MT-Ipb"/>
<outlet property="secureKeyCell" destination="RQF-pm-g37" id="5dK-h1-N6t"/>
<outlet property="securePassphraseCell" destination="Yps-bc-ruH" id="56B-9H-MOh"/>
<outlet property="topSeparatorView" destination="d77-sQ-Uio" id="TPp-kq-cFq"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="WpU-UP-qtu" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3772.4637681159425" y="-774.10714285714278"/>
</scene>
</scenes>
</document>
@@ -0,0 +1,133 @@
/*
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 UIKit
protocol SecureKeyBackupSetupIntroViewControllerDelegate: class {
func secureKeyBackupSetupIntroViewControllerDidTapUseKey(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController)
func secureKeyBackupSetupIntroViewControllerDidTapUsePassphrase(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController)
func secureKeyBackupSetupIntroViewControllerDidCancel(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController)
}
@objcMembers
final class SecureKeyBackupSetupIntroViewController: UIViewController {
// MARK: - Properties
// MARK: Outlets
@IBOutlet private weak var informationLabel: UILabel!
@IBOutlet private weak var topSeparatorView: UIView!
@IBOutlet private weak var secureKeyCell: SecureKeyBackupSetupIntroCell!
@IBOutlet private weak var securePassphraseCell: SecureKeyBackupSetupIntroCell!
// MARK: Private
private var theme: Theme!
// MARK: Public
weak var delegate: SecureKeyBackupSetupIntroViewControllerDelegate?
// MARK: - Setup
class func instantiate() -> SecureKeyBackupSetupIntroViewController {
let viewController = StoryboardScene.SecureKeyBackupSetupIntroViewController.initialScene.instantiate()
viewController.theme = ThemeService.shared().theme
return viewController
}
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.vc_removeBackTitle()
self.setupViews()
self.registerThemeServiceDidChangeThemeNotification()
self.update(theme: self.theme)
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return self.theme.statusBarStyle
}
// MARK: - Private
private func setupViews() {
let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in
guard let self = self else {
return
}
self.delegate?.secureKeyBackupSetupIntroViewControllerDidCancel(self)
}
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
self.title = VectorL10n.secureKeyBackupSetupIntroTitle
self.informationLabel.text = VectorL10n.secureKeyBackupSetupIntroInfo
self.secureKeyCell.fill(title: VectorL10n.secureKeyBackupSetupIntroUseSecurityKeyTitle,
information: VectorL10n.secureKeyBackupSetupIntroUseSecurityKeyInfo,
image: Asset.Images.secretsSetupKey.image)
self.secureKeyCell.action = { [weak self] in
guard let self = self else {
return
}
self.delegate?.secureKeyBackupSetupIntroViewControllerDidTapUseKey(self)
}
self.securePassphraseCell.fill(title: VectorL10n.secureKeyBackupSetupIntroUseSecurityPassphraseTitle,
information: VectorL10n.secureKeyBackupSetupIntroUseSecurityPassphraseInfo,
image: Asset.Images.secretsSetupPassphrase.image)
self.securePassphraseCell.action = { [weak self] in
guard let self = self else {
return
}
self.delegate?.secureKeyBackupSetupIntroViewControllerDidTapUsePassphrase(self)
}
}
private func update(theme: Theme) {
self.theme = theme
self.view.backgroundColor = theme.headerBackgroundColor
if let navigationBar = self.navigationController?.navigationBar {
theme.applyStyle(onNavigationBar: navigationBar)
}
self.informationLabel.textColor = theme.textPrimaryColor
self.topSeparatorView.backgroundColor = theme.lineBreakColor
self.secureKeyCell.update(theme: theme)
self.securePassphraseCell.update(theme: theme)
}
private func registerThemeServiceDidChangeThemeNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
}
@objc private func themeDidChange() {
self.update(theme: ThemeService.shared().theme)
}
}
@@ -0,0 +1,171 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh KeyBackupSetup/SecureSetup SecureKeyBackupSetup
/*
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 UIKit
@objcMembers
final class SecureKeyBackupSetupCoordinator: SecureKeyBackupSetupCoordinatorType {
// MARK: - Properties
// MARK: Private
private let navigationRouter: NavigationRouterType
private let recoveryService: MXRecoveryService
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
weak var delegate: SecureKeyBackupSetupCoordinatorDelegate?
// MARK: - Setup
init(session: MXSession) {
self.navigationRouter = NavigationRouter(navigationController: RiotNavigationController())
self.recoveryService = session.crypto.recoveryService
}
// MARK: - Public methods
func start() {
let rootViewController = self.createIntro()
self.navigationRouter.setRootModule(rootViewController)
}
func toPresentable() -> UIViewController {
return self.navigationRouter.toPresentable()
}
// MARK: - Private methods
private func createIntro() -> SecureKeyBackupSetupIntroViewController {
let introViewController = SecureKeyBackupSetupIntroViewController.instantiate()
introViewController.delegate = self
return introViewController
}
private func showSetupKey(passphrase: String? = nil) {
let coordinator = SecretsSetupRecoveryKeyCoordinator(recoveryService: self.recoveryService, passphrase: passphrase)
coordinator.delegate = self
coordinator.start()
self.add(childCoordinator: coordinator)
self.navigationRouter.push(coordinator, animated: true) { [weak self] in
self?.remove(childCoordinator: coordinator)
}
}
private func showSetupPassphrase() {
let coordinator = SecretsSetupRecoveryPassphraseCoordinator(passphraseInput: .new)
coordinator.delegate = self
coordinator.start()
self.add(childCoordinator: coordinator)
self.navigationRouter.push(coordinator, animated: true) { [weak self] in
self?.remove(childCoordinator: coordinator)
}
}
private func showSetupPassphraseConfirmation(with passphrase: String) {
let coordinator = SecretsSetupRecoveryPassphraseCoordinator(passphraseInput: .confirm(passphrase))
coordinator.delegate = self
coordinator.start()
self.add(childCoordinator: coordinator)
self.navigationRouter.push(coordinator, animated: true) { [weak self] in
self?.remove(childCoordinator: coordinator)
}
}
private func showCancelAlert() {
let alertController = UIAlertController(title: VectorL10n.secureKeyBackupSetupCancelAlertTitle,
message: VectorL10n.secureKeyBackupSetupCancelAlertMessage,
preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: VectorL10n.continue, style: .cancel, handler: { action in
}))
alertController.addAction(UIAlertAction(title: VectorL10n.keyBackupSetupSkipAlertSkipAction, style: .default, handler: { action in
self.delegate?.secureKeyBackupSetupCoordinatorDidCancel(self)
}))
self.navigationRouter.present(alertController, animated: true)
}
private func didCancel(showSkipAlert: Bool = true) {
if showSkipAlert {
self.showCancelAlert()
} else {
self.delegate?.secureKeyBackupSetupCoordinatorDidCancel(self)
}
}
private func didComplete() {
self.delegate?.secureKeyBackupSetupCoordinatorDidComplete(self)
}
}
// MARK: - SecureKeyBackupSetupIntroViewControllerDelegate
extension SecureKeyBackupSetupCoordinator: SecureKeyBackupSetupIntroViewControllerDelegate {
func secureKeyBackupSetupIntroViewControllerDidTapUseKey(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController) {
self.showSetupKey()
}
func secureKeyBackupSetupIntroViewControllerDidTapUsePassphrase(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController) {
self.showSetupPassphrase()
}
func secureKeyBackupSetupIntroViewControllerDidCancel(_ secureKeyBackupSetupIntroViewController: SecureKeyBackupSetupIntroViewController) {
self.didCancel()
}
}
// MARK: - SecretsSetupRecoveryKeyCoordinatorDelegate
extension SecureKeyBackupSetupCoordinator: SecretsSetupRecoveryKeyCoordinatorDelegate {
func secretsSetupRecoveryKeyCoordinatorDidComplete(_ coordinator: SecretsSetupRecoveryKeyCoordinatorType) {
self.didComplete()
}
func secretsSetupRecoveryKeyCoordinatorDidFailed(_ coordinator: SecretsSetupRecoveryKeyCoordinatorType) {
self.didCancel(showSkipAlert: false)
}
func secretsSetupRecoveryKeyCoordinatorDidCancel(_ coordinator: SecretsSetupRecoveryKeyCoordinatorType) {
self.didCancel()
}
}
// MARK: - SecretsSetupRecoveryPassphraseCoordinatorDelegate
extension SecureKeyBackupSetupCoordinator: SecretsSetupRecoveryPassphraseCoordinatorDelegate {
func secretsSetupRecoveryPassphraseCoordinator(_ coordinator: SecretsSetupRecoveryPassphraseCoordinatorType, didEnterNewPassphrase passphrase: String) {
self.showSetupPassphraseConfirmation(with: passphrase)
}
func secretsSetupRecoveryPassphraseCoordinator(_ coordinator: SecretsSetupRecoveryPassphraseCoordinatorType, didConfirmPassphrase passphrase: String) {
self.showSetupKey(passphrase: passphrase)
}
func secretsSetupRecoveryPassphraseCoordinatorDidCancel(_ coordinator: SecretsSetupRecoveryPassphraseCoordinatorType) {
self.didCancel()
}
}
@@ -0,0 +1,88 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh KeyBackupSetup/SecureSetup SecureKeyBackupSetup
/*
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
@objc protocol SecureKeyBackupSetupCoordinatorBridgePresenterDelegate {
func secureKeyBackupSetupCoordinatorBridgePresenterDelegateDidComplete(_ coordinatorBridgePresenter: SecureKeyBackupSetupCoordinatorBridgePresenter)
func secureKeyBackupSetupCoordinatorBridgePresenterDelegateDidCancel(_ coordinatorBridgePresenter: SecureKeyBackupSetupCoordinatorBridgePresenter)
}
/// SecureKeyBackupSetupCoordinatorBridgePresenter enables to start SecureKeyBackupSetupCoordinator from a view controller.
/// This bridge is used while waiting for global usage of coordinator pattern.
@objcMembers
final class SecureKeyBackupSetupCoordinatorBridgePresenter: NSObject {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private var coordinator: SecureKeyBackupSetupCoordinator?
// MARK: Public
weak var delegate: SecureKeyBackupSetupCoordinatorBridgePresenterDelegate?
// MARK: - Setup
init(session: MXSession) {
self.session = session
super.init()
}
// MARK: - Public
// NOTE: Default value feature is not compatible with Objective-C.
// func present(from viewController: UIViewController, animated: Bool) {
// self.present(from: viewController, animated: animated)
// }
func present(from viewController: UIViewController, animated: Bool) {
let secureKeyBackupSetupCoordinator = SecureKeyBackupSetupCoordinator(session: self.session)
secureKeyBackupSetupCoordinator.delegate = self
viewController.present(secureKeyBackupSetupCoordinator.toPresentable(), animated: animated, completion: nil)
secureKeyBackupSetupCoordinator.start()
self.coordinator = secureKeyBackupSetupCoordinator
}
func dismiss(animated: Bool, completion: (() -> Void)?) {
guard let coordinator = self.coordinator else {
return
}
coordinator.toPresentable().dismiss(animated: animated) {
self.coordinator = nil
if let completion = completion {
completion()
}
}
}
}
// MARK: - SecureKeyBackupSetupCoordinatorDelegate
extension SecureKeyBackupSetupCoordinatorBridgePresenter: SecureKeyBackupSetupCoordinatorDelegate {
func secureKeyBackupSetupCoordinatorDidComplete(_ coordinator: SecureKeyBackupSetupCoordinatorType) {
self.delegate?.secureKeyBackupSetupCoordinatorBridgePresenterDelegateDidComplete(self)
}
func secureKeyBackupSetupCoordinatorDidCancel(_ coordinator: SecureKeyBackupSetupCoordinatorType) {
self.delegate?.secureKeyBackupSetupCoordinatorBridgePresenterDelegateDidCancel(self)
}
}
@@ -0,0 +1,29 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh KeyBackupSetup/SecureSetup SecureKeyBackupSetup
/*
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
protocol SecureKeyBackupSetupCoordinatorDelegate: class {
func secureKeyBackupSetupCoordinatorDidComplete(_ coordinator: SecureKeyBackupSetupCoordinatorType)
func secureKeyBackupSetupCoordinatorDidCancel(_ coordinator: SecureKeyBackupSetupCoordinatorType)
}
/// `SecureKeyBackupSetupCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow.
protocol SecureKeyBackupSetupCoordinatorType: Coordinator, Presentable {
var delegate: SecureKeyBackupSetupCoordinatorDelegate? { get }
}