340 lines
14 KiB
Swift
340 lines
14 KiB
Swift
/*
|
|
Copyright 2021-2024 New Vector Ltd.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
Please see LICENSE in the repository root for full details.
|
|
*/
|
|
|
|
import UIKit
|
|
|
|
@objc protocol SettingsSecureBackupTableViewSectionDelegate: AnyObject {
|
|
// Table view rendering
|
|
func settingsSecureBackupTableViewSectionDidUpdate(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection)
|
|
|
|
func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, textCellForRow: Int) -> MXKTableViewCellWithTextView
|
|
func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, buttonCellForRow: Int) -> MXKTableViewCellWithButton
|
|
|
|
// Secure backup
|
|
func settingsSecureBackupTableViewSectionShowSecureBackupReset(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection)
|
|
|
|
// Key backup
|
|
func settingsSecureBackupTableViewSectionShowKeyBackupCreate(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection)
|
|
func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, showKeyBackupRecover keyBackupVersion: MXKeyBackupVersion)
|
|
func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, showKeyBackupDeleteConfirm keyBackupVersion: MXKeyBackupVersion)
|
|
|
|
// Life cycle
|
|
func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, showActivityIndicator show: Bool)
|
|
func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, showError error: Error)
|
|
}
|
|
|
|
private enum BackupRows {
|
|
case info(text: String)
|
|
case createSecureBackupAction
|
|
case resetSecureBackupAction
|
|
case createKeyBackupAction
|
|
case restoreFromKeyBackupAction(keyBackupVersion: MXKeyBackupVersion, title: String)
|
|
case deleteKeyBackupAction(keyBackupVersion: MXKeyBackupVersion)
|
|
}
|
|
|
|
/// SettingsSecureBackupTableViewSection provides UITableViewCells to manage secure backup and key backup.
|
|
///
|
|
/// All states are described in SettingsSecureBackupViewState.
|
|
/// All actions in SettingsSecureBackupViewAction.
|
|
@objc final class SettingsSecureBackupTableViewSection: NSObject {
|
|
|
|
// MARK: - Properties
|
|
|
|
@objc weak var delegate: SettingsSecureBackupTableViewSectionDelegate?
|
|
|
|
// MARK: Private
|
|
|
|
// This view class holds the model because the model is in pure Swift
|
|
// whereas this class can be used from objC
|
|
private var viewModel: SettingsSecureBackupViewModelType!
|
|
|
|
// Need to know the state to make `cellForRow` deliver cells accordingly
|
|
private var viewState: SettingsSecureBackupViewState = .loading {
|
|
didSet {
|
|
self.updateBackupRows()
|
|
}
|
|
}
|
|
|
|
private var userDevice: MXDeviceInfo
|
|
|
|
private var backupRows: [BackupRows] = []
|
|
|
|
// MARK: - Public
|
|
|
|
@objc init(withRecoveryService recoveryService: MXRecoveryService, keyBackup: MXKeyBackup, userDevice: MXDeviceInfo) {
|
|
self.viewModel = SettingsSecureBackupViewModel(recoveryService: recoveryService, keyBackup: keyBackup)
|
|
self.userDevice = userDevice
|
|
super.init()
|
|
self.viewModel.viewDelegate = self
|
|
|
|
self.viewModel.process(viewAction: .load)
|
|
}
|
|
|
|
@objc func numberOfRows() -> Int {
|
|
return self.backupRows.count
|
|
}
|
|
|
|
@objc func cellForRow(atRow row: Int) -> UITableViewCell {
|
|
let backupRow = self.backupRows[row]
|
|
|
|
var cell: UITableViewCell
|
|
switch backupRow {
|
|
case .info(let text):
|
|
cell = self.textCell(atRow: row, text: text)
|
|
case .createSecureBackupAction:
|
|
cell = self.buttonCellForCreateSecureBackup(atRow: row)
|
|
case .resetSecureBackupAction:
|
|
cell = self.buttonCellForResetSecureBackup(atRow: row)
|
|
case .createKeyBackupAction:
|
|
cell = self.buttonCellForCreateKeyBackup(atRow: row)
|
|
case .restoreFromKeyBackupAction(keyBackupVersion: let keyBackupVersion, let title):
|
|
cell = self.buttonCellForRestoreFromKeyBackup(keyBackupVersion: keyBackupVersion, title: title, atRow: row)
|
|
case .deleteKeyBackupAction(keyBackupVersion: let keyBackupVersion):
|
|
cell = self.buttonCellForDeleteKeyBackup(keyBackupVersion: keyBackupVersion, atRow: row)
|
|
}
|
|
|
|
return cell
|
|
}
|
|
|
|
@objc func reload() {
|
|
self.viewModel.process(viewAction: .load)
|
|
}
|
|
|
|
@objc func deleteKeyBackup(keyBackupVersion: MXKeyBackupVersion) {
|
|
self.viewModel.process(viewAction: .deleteKeyBackup(keyBackupVersion))
|
|
}
|
|
|
|
// MARK: - Data Computing
|
|
|
|
private func updateBackupRows() {
|
|
|
|
let backupRows: [BackupRows]
|
|
|
|
switch self.viewState {
|
|
case .loading:
|
|
backupRows = [
|
|
.info(text: VectorL10n.securitySettingsSecureBackupInfoChecking)
|
|
]
|
|
|
|
case .noSecureBackup(let keyBackupState):
|
|
switch keyBackupState {
|
|
case .noKeyBackup:
|
|
let noBackup = VectorL10n.settingsKeyBackupInfoNone
|
|
let signoutWarning = VectorL10n.settingsKeyBackupInfoSignoutWarning
|
|
let infoText = [noBackup, signoutWarning].joined(separator: "\n")
|
|
|
|
backupRows = [
|
|
.info(text: infoText),
|
|
.createSecureBackupAction
|
|
]
|
|
case .keyBackup(let keyBackupVersion, _, let progress):
|
|
if let progress = progress {
|
|
backupRows = [
|
|
.info(text: importProgressText(for: progress)),
|
|
.deleteKeyBackupAction(keyBackupVersion: keyBackupVersion)
|
|
]
|
|
} else {
|
|
backupRows = [
|
|
.info(text: VectorL10n.securitySettingsSecureBackupInfoValid),
|
|
.restoreFromKeyBackupAction(keyBackupVersion: keyBackupVersion, title: VectorL10n.securitySettingsSecureBackupRestore),
|
|
.deleteKeyBackupAction(keyBackupVersion: keyBackupVersion)
|
|
]
|
|
}
|
|
case .keyBackupNotTrusted(let keyBackupVersion, _):
|
|
backupRows = [
|
|
.info(text: VectorL10n.securitySettingsSecureBackupInfoValid),
|
|
.restoreFromKeyBackupAction(keyBackupVersion: keyBackupVersion, title: VectorL10n.securitySettingsSecureBackupRestore),
|
|
.deleteKeyBackupAction(keyBackupVersion: keyBackupVersion)
|
|
]
|
|
}
|
|
case .secureBackup(let keyBackupState):
|
|
switch keyBackupState {
|
|
case .noKeyBackup:
|
|
let noBackup = VectorL10n.settingsKeyBackupInfoNone
|
|
let signoutWarning = VectorL10n.settingsKeyBackupInfoSignoutWarning
|
|
let infoText = [noBackup, signoutWarning].joined(separator: "\n")
|
|
|
|
backupRows = [
|
|
.info(text: infoText),
|
|
.createKeyBackupAction,
|
|
.resetSecureBackupAction
|
|
]
|
|
case .keyBackup(let keyBackupVersion, _, let progress):
|
|
if let progress = progress {
|
|
backupRows = [
|
|
.info(text: importProgressText(for: progress)),
|
|
.deleteKeyBackupAction(keyBackupVersion: keyBackupVersion),
|
|
.resetSecureBackupAction
|
|
]
|
|
} else {
|
|
backupRows = [
|
|
.info(text: VectorL10n.securitySettingsSecureBackupInfoValid),
|
|
.restoreFromKeyBackupAction(keyBackupVersion: keyBackupVersion, title: VectorL10n.securitySettingsSecureBackupRestore),
|
|
.deleteKeyBackupAction(keyBackupVersion: keyBackupVersion),
|
|
.resetSecureBackupAction
|
|
]
|
|
}
|
|
case .keyBackupNotTrusted(let keyBackupVersion, _):
|
|
backupRows = [
|
|
.info(text: VectorL10n.securitySettingsSecureBackupInfoValid),
|
|
.restoreFromKeyBackupAction(keyBackupVersion: keyBackupVersion, title: VectorL10n.securitySettingsSecureBackupRestore),
|
|
.deleteKeyBackupAction(keyBackupVersion: keyBackupVersion),
|
|
.resetSecureBackupAction
|
|
]
|
|
}
|
|
}
|
|
self.backupRows = backupRows
|
|
}
|
|
|
|
private func importProgressText(for progress: Progress) -> String {
|
|
let percentage = Int(round(progress.fractionCompleted * 100))
|
|
return VectorL10n.keyBackupRecoverFromPrivateKeyInfo + " \(percentage)%"
|
|
}
|
|
|
|
// MARK: - Cells -
|
|
|
|
private func textCell(atRow row: Int, text: String) -> UITableViewCell {
|
|
guard let delegate = self.delegate else {
|
|
return UITableViewCell()
|
|
}
|
|
|
|
let cell = delegate.settingsSecureBackupTableViewSection(self, textCellForRow: row)
|
|
cell.mxkTextView.text = text
|
|
return cell
|
|
}
|
|
|
|
// MARK: - Button cells
|
|
|
|
private func buttonCellForCreateSecureBackup(atRow row: Int) -> UITableViewCell {
|
|
|
|
guard let delegate = self.delegate else {
|
|
return UITableViewCell()
|
|
}
|
|
|
|
let cell: MXKTableViewCellWithButton = delegate.settingsSecureBackupTableViewSection(self, buttonCellForRow: row)
|
|
|
|
let btnTitle = VectorL10n.securitySettingsSecureBackupSetup
|
|
cell.mxkButton.setTitle(btnTitle, for: .normal)
|
|
cell.mxkButton.setTitle(btnTitle, for: .highlighted)
|
|
|
|
cell.mxkButton.vc_addAction {
|
|
self.viewModel.process(viewAction: .createSecureBackup)
|
|
}
|
|
|
|
return cell
|
|
}
|
|
|
|
private func buttonCellForResetSecureBackup(atRow row: Int) -> UITableViewCell {
|
|
|
|
guard let delegate = self.delegate else {
|
|
return UITableViewCell()
|
|
}
|
|
|
|
let cell: MXKTableViewCellWithButton = delegate.settingsSecureBackupTableViewSection(self, buttonCellForRow: row)
|
|
|
|
let btnTitle = VectorL10n.securitySettingsSecureBackupReset
|
|
cell.mxkButton.setTitle(btnTitle, for: .normal)
|
|
cell.mxkButton.setTitle(btnTitle, for: .highlighted)
|
|
cell.mxkButton.tintColor = ThemeService.shared().theme.warningColor
|
|
|
|
cell.mxkButton.vc_addAction {
|
|
self.viewModel.process(viewAction: .resetSecureBackup)
|
|
}
|
|
|
|
return cell
|
|
}
|
|
|
|
private func buttonCellForCreateKeyBackup(atRow row: Int) -> UITableViewCell {
|
|
|
|
guard let delegate = self.delegate else {
|
|
return UITableViewCell()
|
|
}
|
|
|
|
let cell: MXKTableViewCellWithButton = delegate.settingsSecureBackupTableViewSection(self, buttonCellForRow: row)
|
|
|
|
let btnTitle = VectorL10n.securitySettingsSecureBackupSetup
|
|
cell.mxkButton.setTitle(btnTitle, for: .normal)
|
|
cell.mxkButton.setTitle(btnTitle, for: .highlighted)
|
|
|
|
cell.mxkButton.vc_addAction {
|
|
self.viewModel.process(viewAction: .createKeyBackup)
|
|
}
|
|
|
|
return cell
|
|
}
|
|
|
|
private func buttonCellForRestoreFromKeyBackup(keyBackupVersion: MXKeyBackupVersion, title: String, atRow row: Int) -> UITableViewCell {
|
|
guard let delegate = self.delegate else {
|
|
return UITableViewCell()
|
|
}
|
|
|
|
let cell: MXKTableViewCellWithButton = delegate.settingsSecureBackupTableViewSection(self, buttonCellForRow: row)
|
|
cell.mxkButton.setTitle(title, for: .normal)
|
|
cell.mxkButton.setTitle(title, for: .highlighted)
|
|
cell.mxkButton.vc_addAction {
|
|
self.viewModel.process(viewAction: .restoreFromKeyBackup(keyBackupVersion))
|
|
}
|
|
return cell
|
|
}
|
|
|
|
private func buttonCellForDeleteKeyBackup(keyBackupVersion: MXKeyBackupVersion, atRow row: Int) -> UITableViewCell {
|
|
guard let delegate = self.delegate else {
|
|
return UITableViewCell()
|
|
}
|
|
|
|
let cell: MXKTableViewCellWithButton = delegate.settingsSecureBackupTableViewSection(self, buttonCellForRow: row)
|
|
let btnTitle = VectorL10n.securitySettingsSecureBackupDelete
|
|
cell.mxkButton.setTitle(btnTitle, for: .normal)
|
|
cell.mxkButton.setTitle(btnTitle, for: .highlighted)
|
|
cell.mxkButton.tintColor = ThemeService.shared().theme.warningColor
|
|
cell.mxkButton.vc_addAction {
|
|
self.viewModel.process(viewAction: .confirmDeleteKeyBackup(keyBackupVersion))
|
|
}
|
|
|
|
return cell
|
|
}
|
|
}
|
|
|
|
|
|
// MARK: - KeyBackupSetupRecoveryKeyViewModelViewDelegate
|
|
extension SettingsSecureBackupTableViewSection: SettingsSecureBackupViewModelViewDelegate {
|
|
|
|
func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, didUpdateViewState viewState: SettingsSecureBackupViewState) {
|
|
self.viewState = viewState
|
|
|
|
// The tableview datasource will call `self.cellForRow()`
|
|
self.delegate?.settingsSecureBackupTableViewSectionDidUpdate(self)
|
|
}
|
|
|
|
func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, didUpdateNetworkRequestViewState networkRequestViewSate: SettingsSecureBackupNetworkRequestViewState) {
|
|
switch networkRequestViewSate {
|
|
case .loading:
|
|
self.delegate?.settingsSecureBackupTableViewSection(self, showActivityIndicator: true)
|
|
case .loaded:
|
|
self.delegate?.settingsSecureBackupTableViewSection(self, showActivityIndicator: false)
|
|
case .error(let error):
|
|
self.delegate?.settingsSecureBackupTableViewSection(self, showError: error)
|
|
}
|
|
}
|
|
|
|
func settingsSecureBackupViewModelShowSecureBackupReset(_ viewModel: SettingsSecureBackupViewModelType) {
|
|
self.delegate?.settingsSecureBackupTableViewSectionShowSecureBackupReset(self)
|
|
}
|
|
|
|
func settingsSecureBackupViewModelShowKeyBackupCreate(_ viewModel: SettingsSecureBackupViewModelType) {
|
|
self.delegate?.settingsSecureBackupTableViewSectionShowKeyBackupCreate(self)
|
|
}
|
|
|
|
func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, showKeyBackupRecover keyBackupVersion: MXKeyBackupVersion) {
|
|
self.delegate?.settingsSecureBackupTableViewSection(self, showKeyBackupRecover: keyBackupVersion)
|
|
}
|
|
|
|
func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, showKeyBackupDeleteConfirm keyBackupVersion: MXKeyBackupVersion) {
|
|
self.delegate?.settingsSecureBackupTableViewSection(self, showKeyBackupDeleteConfirm: keyBackupVersion)
|
|
}
|
|
}
|