// // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // import UIKit @objc public class BackupRestoreViewController: OWSTableViewController { private var hasBegunImport = false // MARK: - Dependencies private var backup: OWSBackup { return AppEnvironment.shared.backup } // MARK: - override public func loadView() { super.loadView() navigationItem.title = NSLocalizedString("SETTINGS_BACKUP", comment: "Label for the backup view in app settings.") navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(didPressCancelButton)) } override public func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(backupStateDidChange), name: NSNotification.Name(NSNotificationNameBackupStateDidChange), object: nil) updateTableContents() } private func updateTableContents() { if hasBegunImport { updateProgressContents() } else { updateDecisionContents() } } private func updateDecisionContents() { let contents = OWSTableContents() let section = OWSTableSection() section.headerTitle = NSLocalizedString("BACKUP_RESTORE_DECISION_TITLE", comment: "Label for the backup restore decision section.") section.add(OWSTableItem.actionItem(withText: NSLocalizedString("CHECK_FOR_BACKUP_DO_NOT_RESTORE", comment: "The label for the 'do not restore backup' button."), actionBlock: { [weak self] in guard let strongSelf = self else { return } strongSelf.cancelAndDismiss() })) section.add(OWSTableItem.actionItem(withText: NSLocalizedString("CHECK_FOR_BACKUP_RESTORE", comment: "The label for the 'restore backup' button."), actionBlock: { [weak self] in guard let strongSelf = self else { return } strongSelf.startImport() })) contents.addSection(section) self.contents = contents } private var progressFormatter: NumberFormatter = { let numberFormatter = NumberFormatter() numberFormatter.numberStyle = .percent numberFormatter.maximumFractionDigits = 0 numberFormatter.multiplier = 1 return numberFormatter }() private func updateProgressContents() { let contents = OWSTableContents() let section = OWSTableSection() section.add(OWSTableItem.label(withText: NSLocalizedString("BACKUP_RESTORE_STATUS", comment: "Label for the backup restore status."), accessoryText: NSStringForBackupImportState(backup.backupImportState))) if backup.backupImportState == .inProgress { if let backupImportDescription = backup.backupImportDescription { section.add(OWSTableItem.label(withText: NSLocalizedString("BACKUP_RESTORE_DESCRIPTION", comment: "Label for the backup restore description."), accessoryText: backupImportDescription)) } if let backupImportProgress = backup.backupImportProgress { let progressInt = backupImportProgress.floatValue * 100 if let progressString = progressFormatter.string(from: NSNumber(value: progressInt)) { section.add(OWSTableItem.label(withText: NSLocalizedString("BACKUP_RESTORE_PROGRESS", comment: "Label for the backup restore progress."), accessoryText: progressString)) } else { owsFailDebug("Could not format progress: \(progressInt)") } } } contents.addSection(section) self.contents = contents // TODO: Add cancel button. } // MARK: Helpers @objc private func didPressCancelButton(sender: UIButton) { Logger.info("") // TODO: Cancel import. cancelAndDismiss() } @objc private func cancelAndDismiss() { Logger.info("") backup.setHasPendingRestoreDecision(false) showHomeView() } @objc private func startImport() { Logger.info("") hasBegunImport = true backup.tryToImport() } private func showHomeView() { // In production, this view will never be presented in a modal. // During testing (debug UI, etc.), it may be a modal. let isModal = navigationController?.presentingViewController != nil if isModal { dismiss(animated: true, completion: { SignalApp.shared().showHomeView() }) } else { SignalApp.shared().showHomeView() } NotificationCenter.default.removeObserver(self) } // MARK: - Notifications @objc func backupStateDidChange() { AssertIsOnMainThread() Logger.verbose("backup.backupImportState: \(NSStringForBackupImportState(backup.backupImportState))") Logger.flush() if backup.backupImportState == .succeeded { backup.setHasPendingRestoreDecision(false) showHomeView() } else { updateTableContents() } } // MARK: Orientation public override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } }