Create secrets reset screen.

This commit is contained in:
SBiOSoftWhare
2020-09-30 17:42:51 +02:00
parent bc72e60596
commit c6d61b8cea
9 changed files with 658 additions and 0 deletions
@@ -0,0 +1,71 @@
// File created from ScreenTemplate
// $ createScreen.sh Secrets/Reset SecretsReset
/*
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
import UIKit
final class SecretsResetCoordinator: SecretsResetCoordinatorType {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private var secretsResetViewModel: SecretsResetViewModelType
private let secretsResetViewController: SecretsResetViewController
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
weak var delegate: SecretsResetCoordinatorDelegate?
// MARK: - Setup
init(session: MXSession) {
self.session = session
let secretsResetViewModel = SecretsResetViewModel(session: self.session)
let secretsResetViewController = SecretsResetViewController.instantiate(with: secretsResetViewModel)
self.secretsResetViewModel = secretsResetViewModel
self.secretsResetViewController = secretsResetViewController
}
// MARK: - Public methods
func start() {
self.secretsResetViewModel.coordinatorDelegate = self
}
func toPresentable() -> UIViewController {
return self.secretsResetViewController
}
}
// MARK: - SecretsResetViewModelCoordinatorDelegate
extension SecretsResetCoordinator: SecretsResetViewModelCoordinatorDelegate {
func secretsResetViewModelDidResetSecrets(_ viewModel: SecretsResetViewModelType) {
self.delegate?.secretsResetCoordinatorDidResetSecrets(self)
}
func secretsResetViewModelDidCancel(_ viewModel: SecretsResetViewModelType) {
self.delegate?.secretsResetCoordinatorDidCancel(self)
}
}
@@ -0,0 +1,29 @@
// File created from ScreenTemplate
// $ createScreen.sh Secrets/Reset SecretsReset
/*
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 SecretsResetCoordinatorDelegate: class {
func secretsResetCoordinatorDidResetSecrets(_ coordinator: SecretsResetCoordinatorType)
func secretsResetCoordinatorDidCancel(_ coordinator: SecretsResetCoordinatorType)
}
/// `SecretsResetCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow.
protocol SecretsResetCoordinatorType: Coordinator, Presentable {
var delegate: SecretsResetCoordinatorDelegate? { get }
}
@@ -0,0 +1,27 @@
// File created from ScreenTemplate
// $ createScreen.sh Secrets/Reset SecretsReset
/*
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
/// SecretsResetViewController view actions exposed to view model
enum SecretsResetViewAction {
case loadData
case reset
case authenticationInfoEntered(_ authInfo: [String: Any])
case cancel
}
@@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.3" 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"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Secrets Reset View Controller-->
<scene sceneID="mt5-wz-YKA">
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="V8j-Lb-PgC" customClass="SecretsResetViewController" 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"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9U2-KL-ZVA">
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="e7g-um-WO4">
<rect key="frame" x="0.0" y="0.0" width="414" height="339"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="voD-3Q-ryt">
<rect key="frame" x="5" y="0.0" width="404.5" height="339"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="secrets_reset_warning" translatesAutoresizingMaskIntoConstraints="NO" id="WeW-92-lD0">
<rect key="frame" x="180" y="30" width="44" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="80n-Vr-84Z"/>
<constraint firstAttribute="width" constant="44" id="fJv-pC-wyu"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Only do this if you have no other device you can verify this device with. " textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ljr-lR-H2p">
<rect key="frame" x="20" y="94" width="364.5" height="36"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="If you reset everything" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Gry-K5-URB">
<rect key="frame" x="20" y="160" width="364.5" height="18"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
<color key="textColor" systemColor="systemRedColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="You will restart with no history, no messages, trusted devices or trusted users" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kvV-8I-XXw">
<rect key="frame" x="20" y="193" width="364.5" height="36"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yPo-s1-j4H">
<rect key="frame" x="0.0" y="269" width="404.5" height="50"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Fps-LF-Ix9" customClass="RoundedButton" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="15" y="0.0" width="374" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="PfY-kj-KDw"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<inset key="contentEdgeInsets" minX="20" minY="0.0" maxX="20" maxY="0.0"/>
<state key="normal" title="Reset">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="1" colorSpace="calibratedRGB"/>
</state>
<state key="disabled">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="0.5" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="resetAction:" destination="V8j-Lb-PgC" eventType="touchUpInside" id="SQd-u3-VKU"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Fps-LF-Ix9" firstAttribute="width" secondItem="yPo-s1-j4H" secondAttribute="width" priority="750" id="0df-cU-uIb"/>
<constraint firstAttribute="bottom" secondItem="Fps-LF-Ix9" secondAttribute="bottom" id="4k4-Hp-pPG"/>
<constraint firstItem="Fps-LF-Ix9" firstAttribute="centerX" secondItem="yPo-s1-j4H" secondAttribute="centerX" id="7FD-rd-PHK"/>
<constraint firstItem="Fps-LF-Ix9" firstAttribute="top" secondItem="yPo-s1-j4H" secondAttribute="top" id="Tpp-3I-FYg"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="kvV-8I-XXw" firstAttribute="leading" secondItem="Gry-K5-URB" secondAttribute="leading" id="0d6-bR-ILD"/>
<constraint firstItem="yPo-s1-j4H" firstAttribute="top" secondItem="kvV-8I-XXw" secondAttribute="bottom" constant="40" id="ARy-kZ-2tj"/>
<constraint firstItem="Ljr-lR-H2p" firstAttribute="top" secondItem="WeW-92-lD0" secondAttribute="bottom" constant="20" id="BaZ-1G-gUe"/>
<constraint firstItem="Gry-K5-URB" firstAttribute="leading" secondItem="Ljr-lR-H2p" secondAttribute="leading" id="E4X-cE-vkr"/>
<constraint firstItem="Ljr-lR-H2p" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" constant="20" id="FOD-4K-svD"/>
<constraint firstItem="WeW-92-lD0" firstAttribute="top" secondItem="voD-3Q-ryt" secondAttribute="top" constant="30" id="LQY-SY-Sxh"/>
<constraint firstItem="yPo-s1-j4H" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" id="LZe-H5-yWT"/>
<constraint firstItem="kvV-8I-XXw" firstAttribute="trailing" secondItem="Gry-K5-URB" secondAttribute="trailing" id="Ww6-Mg-0ta"/>
<constraint firstAttribute="bottom" secondItem="yPo-s1-j4H" secondAttribute="bottom" constant="20" id="Xay-Bq-UIr"/>
<constraint firstItem="WeW-92-lD0" firstAttribute="centerX" secondItem="voD-3Q-ryt" secondAttribute="centerX" id="YXi-rg-G64"/>
<constraint firstItem="Gry-K5-URB" firstAttribute="trailing" secondItem="Ljr-lR-H2p" secondAttribute="trailing" id="aXA-k0-0EH"/>
<constraint firstAttribute="width" priority="750" constant="500" id="glD-Sz-73O"/>
<constraint firstAttribute="trailing" secondItem="Ljr-lR-H2p" secondAttribute="trailing" constant="20" id="mfj-xv-fbN"/>
<constraint firstItem="Gry-K5-URB" firstAttribute="top" secondItem="Ljr-lR-H2p" secondAttribute="bottom" constant="30" id="pXs-AR-9Ah"/>
<constraint firstItem="kvV-8I-XXw" firstAttribute="top" secondItem="Gry-K5-URB" secondAttribute="bottom" constant="15" id="rND-bN-Jxq"/>
<constraint firstAttribute="trailing" secondItem="yPo-s1-j4H" secondAttribute="trailing" id="tYl-qC-a3t"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="voD-3Q-ryt" secondAttribute="bottom" id="63a-5e-ptU"/>
<constraint firstItem="voD-3Q-ryt" firstAttribute="centerX" secondItem="e7g-um-WO4" secondAttribute="centerX" id="P2G-mq-gQW"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="voD-3Q-ryt" secondAttribute="trailing" id="QgV-SO-5yf"/>
<constraint firstItem="Fps-LF-Ix9" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="e7g-um-WO4" secondAttribute="leading" constant="20" id="Qp7-H5-3ih"/>
<constraint firstItem="voD-3Q-ryt" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="e7g-um-WO4" secondAttribute="leading" id="YPo-u1-PtT"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Fps-LF-Ix9" secondAttribute="trailing" constant="20" id="mBV-o5-oUU"/>
<constraint firstItem="voD-3Q-ryt" firstAttribute="top" secondItem="e7g-um-WO4" secondAttribute="top" id="rhQ-96-szL"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="e7g-um-WO4" secondAttribute="trailing" id="GyG-Fh-PME"/>
<constraint firstItem="e7g-um-WO4" firstAttribute="width" secondItem="9U2-KL-ZVA" secondAttribute="width" id="Ok2-WQ-Zgc"/>
<constraint firstAttribute="bottom" secondItem="e7g-um-WO4" secondAttribute="bottom" id="Y46-NP-zAc"/>
<constraint firstItem="e7g-um-WO4" firstAttribute="leading" secondItem="9U2-KL-ZVA" secondAttribute="leading" id="aoV-Yh-AcD"/>
<constraint firstItem="e7g-um-WO4" firstAttribute="top" secondItem="9U2-KL-ZVA" secondAttribute="top" id="pFN-bA-SHw"/>
</constraints>
</scrollView>
</subviews>
<color key="backgroundColor" red="0.94509803921568625" green="0.96078431372549022" blue="0.97254901960784312" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="9U2-KL-ZVA" secondAttribute="bottom" id="7Cb-nY-CsO"/>
<constraint firstItem="9U2-KL-ZVA" firstAttribute="leading" secondItem="bFg-jh-JZB" secondAttribute="leading" id="GdQ-hK-muG"/>
<constraint firstItem="bFg-jh-JZB" firstAttribute="trailing" secondItem="9U2-KL-ZVA" secondAttribute="trailing" id="sbD-ek-vGJ"/>
<constraint firstItem="bFg-jh-JZB" firstAttribute="top" secondItem="9U2-KL-ZVA" secondAttribute="top" id="wTB-V6-IHV"/>
</constraints>
<viewLayoutGuide key="safeArea" id="bFg-jh-JZB"/>
</view>
<connections>
<outlet property="informationLabel" destination="Ljr-lR-H2p" id="Ggr-pn-LAv"/>
<outlet property="resetButton" destination="Fps-LF-Ix9" id="bsL-hw-eLm"/>
<outlet property="scrollView" destination="9U2-KL-ZVA" id="ojG-2y-X7b"/>
<outlet property="warningImage" destination="WeW-92-lD0" id="NNJ-jZ-e9r"/>
<outlet property="warningMessage" destination="kvV-8I-XXw" id="2OO-Rt-qjD"/>
<outlet property="warningTitle" destination="Gry-K5-URB" id="F9g-eu-1JD"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="zK0-v6-7Wt" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3198" y="-647"/>
</scene>
</scenes>
<resources>
<image name="secrets_reset_warning" width="44" height="44"/>
</resources>
</document>
@@ -0,0 +1,202 @@
// File created from ScreenTemplate
// $ createScreen.sh Secrets/Reset SecretsReset
/*
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
final class SecretsResetViewController: UIViewController {
// MARK: - Constants
// MARK: - Properties
// MARK: Outlets
@IBOutlet private weak var scrollView: UIScrollView!
@IBOutlet private weak var warningImage: UIImageView!
@IBOutlet private weak var informationLabel: UILabel!
@IBOutlet private weak var warningTitle: UILabel!
@IBOutlet private weak var warningMessage: UILabel!
@IBOutlet private weak var resetButton: RoundedButton!
// MARK: Private
private var viewModel: SecretsResetViewModelType!
private var theme: Theme!
private var errorPresenter: MXKErrorPresentation!
private var activityPresenter: ActivityIndicatorPresenter!
private var authenticatedSessionFactory: AuthenticatedSessionViewControllerFactory?
// MARK: - Setup
class func instantiate(with viewModel: SecretsResetViewModelType) -> SecretsResetViewController {
let viewController = StoryboardScene.SecretsResetViewController.initialScene.instantiate()
viewController.viewModel = viewModel
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.activityPresenter = ActivityIndicatorPresenter()
self.errorPresenter = MXKErrorAlertPresentation()
self.registerThemeServiceDidChangeThemeNotification()
self.update(theme: self.theme)
self.viewModel.viewDelegate = self
self.viewModel.process(viewAction: .loadData)
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return self.theme.statusBarStyle
}
// MARK: - Private
private func update(theme: Theme) {
self.theme = theme
self.view.backgroundColor = theme.headerBackgroundColor
if let navigationBar = self.navigationController?.navigationBar {
theme.applyStyle(onNavigationBar: navigationBar)
}
self.warningImage.tintColor = theme.warningColor
self.informationLabel.textColor = theme.textPrimaryColor
self.warningTitle.textColor = theme.warningColor
self.warningMessage.textColor = theme.textPrimaryColor
self.resetButton.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)
}
private func setupViews() {
let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in
self?.cancelButtonAction()
}
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
self.title = VectorL10n.secretsResetTitle
self.scrollView.keyboardDismissMode = .interactive
self.informationLabel.text = VectorL10n.secretsResetInformation
self.warningTitle.text = VectorL10n.secretsResetWarningTitle
self.warningMessage.text = VectorL10n.secretsResetWarningMessage
self.resetButton.setTitle(VectorL10n.secretsResetResetAction, for: .normal)
}
private func render(viewState: SecretsResetViewState) {
switch viewState {
case .resetting:
self.renderLoading()
case .resetDone:
self.renderLoaded()
case .showAuthentication(authData: let authData):
self.showAuthentication(authData: authData)
case .error(let error):
self.render(error: error)
}
}
private func renderLoading() {
self.activityPresenter.presentActivityIndicator(on: self.view, animated: true)
}
private func renderLoaded() {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
}
private func render(error: Error) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil)
}
private func showAuthentication(authData: SecretsResetAuthData) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
let authenticatedSessionFactory = authData.authenticatedSessionViewControllerFactory
authenticatedSessionFactory.viewController(forPath: authData.path, httpMethod: authData.httpMethod, title: nil, message: VectorL10n.secretsResetAuthenticationMessage, onViewController: { [weak self] (viewController) in
guard let self = self else {
return
}
self.present(viewController, animated: true, completion: nil)
}, onAuthenticated: { [weak self] (authInfo) in
guard let self = self else {
return
}
self.viewModel.process(viewAction: .authenticationInfoEntered(authInfo))
}, onCancelled: {
}, onFailure: { [weak self] (error) in
guard let self = self else {
return
}
self.render(error: error)
})
self.authenticatedSessionFactory = authenticatedSessionFactory
}
// MARK: - Actions
private func cancelButtonAction() {
self.viewModel.process(viewAction: .cancel)
}
@IBAction private func resetAction(_ sender: Any) {
self.viewModel.process(viewAction: .reset)
}
}
// MARK: - SecretsResetViewModelViewDelegate
extension SecretsResetViewController: SecretsResetViewModelViewDelegate {
func secretsResetViewModel(_ viewModel: SecretsResetViewModelType, didUpdateViewState viewSate: SecretsResetViewState) {
self.render(viewState: viewSate)
}
}
@@ -0,0 +1,103 @@
// File created from ScreenTemplate
// $ createScreen.sh Secrets/Reset SecretsReset
/*
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
final class SecretsResetViewModel: SecretsResetViewModelType {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private let recoveryService: MXRecoveryService
// MARK: Public
weak var viewDelegate: SecretsResetViewModelViewDelegate?
weak var coordinatorDelegate: SecretsResetViewModelCoordinatorDelegate?
// MARK: - Setup
init(session: MXSession) {
self.session = session
self.recoveryService = session.crypto.recoveryService
}
// MARK: - Public
func process(viewAction: SecretsResetViewAction) {
switch viewAction {
case .loadData:
break
case .reset:
self.askAuthentication()
case .authenticationInfoEntered(let authInfo):
self.resetSecrets(with: authInfo)
case .cancel:
self.coordinatorDelegate?.secretsResetViewModelDidCancel(self)
}
}
// MARK: - Private
private func update(viewState: SecretsResetViewState) {
self.viewDelegate?.secretsResetViewModel(self, didUpdateViewState: viewState)
}
private func resetSecrets(with authInfo: [String: Any]) {
guard let crossSigning = self.session.crypto.crossSigning else {
return
}
self.update(viewState: .resetting)
crossSigning.setup(withAuthParams: authInfo, success: { [weak self] in
guard let self = self else {
return
}
self.recoveryService.deleteRecovery(withDeleteServicesBackups: true, success: { [weak self] in
guard let self = self else {
return
}
self.update(viewState: .resetDone)
self.coordinatorDelegate?.secretsResetViewModelDidResetSecrets(self)
}, failure: { [weak self] error in
guard let self = self else {
return
}
self.update(viewState: .error(error))
})
}, failure: { [weak self] error in
guard let self = self else {
return
}
self.update(viewState: .error(error))
})
}
// NOTE: Use a Coordinator instead of AuthenticatedSessionViewControllerFactory and delegate the presentation to SecretsResetCoordinator
private func askAuthentication() {
let path = "\(kMXAPIPrefixPathUnstable)/keys/device_signing/upload"
let authenticatedSessionFactory = AuthenticatedSessionViewControllerFactory(session: self.session)
let authData = SecretsResetAuthData(path: path, httpMethod: "POST", authenticatedSessionViewControllerFactory: authenticatedSessionFactory)
self.update(viewState: .showAuthentication(authData: authData))
}
}
@@ -0,0 +1,37 @@
// File created from ScreenTemplate
// $ createScreen.sh Secrets/Reset SecretsReset
/*
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 SecretsResetViewModelViewDelegate: class {
func secretsResetViewModel(_ viewModel: SecretsResetViewModelType, didUpdateViewState viewSate: SecretsResetViewState)
}
protocol SecretsResetViewModelCoordinatorDelegate: class {
func secretsResetViewModelDidResetSecrets(_ viewModel: SecretsResetViewModelType)
func secretsResetViewModelDidCancel(_ viewModel: SecretsResetViewModelType)
}
/// Protocol describing the view model used by `SecretsResetViewController`
protocol SecretsResetViewModelType {
var viewDelegate: SecretsResetViewModelViewDelegate? { get set }
var coordinatorDelegate: SecretsResetViewModelCoordinatorDelegate? { get set }
func process(viewAction: SecretsResetViewAction)
}
@@ -0,0 +1,33 @@
// File created from ScreenTemplate
// $ createScreen.sh Secrets/Reset SecretsReset
/*
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
struct SecretsResetAuthData {
let path: String
let httpMethod: String
let authenticatedSessionViewControllerFactory: AuthenticatedSessionViewControllerFactory
}
/// SecretsResetViewController view state
enum SecretsResetViewState {
case showAuthentication(authData: SecretsResetAuthData)
case resetting
case resetDone
case error(Error)
}