Adds option to manually restore backup for active apps that have one

This commit is contained in:
Riley Testut
2020-05-16 16:39:02 -07:00
parent 4a893d3c80
commit 60abb9ee07
2 changed files with 81 additions and 4 deletions

View File

@@ -389,6 +389,32 @@ extension AppManager
} }
} }
func restore(_ installedApp: InstalledApp, presentingViewController: UIViewController?, completionHandler: @escaping (Result<InstalledApp, Error>) -> Void)
{
let group = RefreshGroup()
group.completionHandler = { (results) in
do
{
guard let result = results.values.first else { throw OperationError.unknown }
let installedApp = try result.get()
assert(installedApp.managedObjectContext != nil)
installedApp.managedObjectContext?.perform {
installedApp.isActive = true
completionHandler(.success(installedApp))
}
}
catch
{
completionHandler(.failure(error))
}
}
let operation = AppOperation.restore(installedApp)
self.perform([operation], presentingViewController: presentingViewController, group: group)
}
func remove(_ installedApp: InstalledApp, completionHandler: @escaping (Result<Void, Error>) -> Void) func remove(_ installedApp: InstalledApp, completionHandler: @escaping (Result<Void, Error>) -> Void)
{ {
let authenticationContext = AuthenticatedOperationContext() let authenticationContext = AuthenticatedOperationContext()
@@ -453,13 +479,14 @@ private extension AppManager
case refresh(InstalledApp) case refresh(InstalledApp)
case activate(InstalledApp) case activate(InstalledApp)
case deactivate(InstalledApp) case deactivate(InstalledApp)
case restore(InstalledApp)
var app: AppProtocol { var app: AppProtocol {
switch self switch self
{ {
case .install(let app), .update(let app), case .install(let app), .update(let app),
.refresh(let app as AppProtocol), .activate(let app as AppProtocol), .refresh(let app as AppProtocol), .activate(let app as AppProtocol),
.deactivate(let app as AppProtocol): .deactivate(let app as AppProtocol), .restore(let app as AppProtocol):
return app return app
} }
} }
@@ -578,6 +605,14 @@ private extension AppManager
self.finish(operation, result: result, group: group, progress: progress) self.finish(operation, result: result, group: group, progress: progress)
} }
progress?.addChild(deactivateProgress, withPendingUnitCount: 80) progress?.addChild(deactivateProgress, withPendingUnitCount: 80)
case .restore(let app):
// Restoring, which is effectively just activating an app.
let activateProgress = self._activate(app, operation: operation, group: group) { (result) in
self.finish(operation, result: result, group: group, progress: progress)
}
progress?.addChild(activateProgress, withPendingUnitCount: 80)
} }
} }
} }
@@ -1121,7 +1156,7 @@ private extension AppManager
event = nil event = nil
case .update: event = .updatedApp(installedApp) case .update: event = .updatedApp(installedApp)
case .activate, .deactivate: event = nil case .activate, .deactivate, .restore: event = nil
} }
if let event = event if let event = event
@@ -1179,7 +1214,7 @@ private extension AppManager
switch operation switch operation
{ {
case .install, .update: return self.installationProgress[operation.bundleIdentifier] case .install, .update: return self.installationProgress[operation.bundleIdentifier]
case .refresh, .activate, .deactivate: return self.refreshProgress[operation.bundleIdentifier] case .refresh, .activate, .deactivate, .restore: return self.refreshProgress[operation.bundleIdentifier]
} }
} }
@@ -1188,7 +1223,7 @@ private extension AppManager
switch operation switch operation
{ {
case .install, .update: self.installationProgress[operation.bundleIdentifier] = progress case .install, .update: self.installationProgress[operation.bundleIdentifier] = progress
case .refresh, .activate, .deactivate: self.refreshProgress[operation.bundleIdentifier] = progress case .refresh, .activate, .deactivate, .restore: self.refreshProgress[operation.bundleIdentifier] = progress
} }
} }
} }

View File

@@ -1002,6 +1002,39 @@ private extension MyAppsViewController
self.present(alertController, animated: true, completion: nil) self.present(alertController, animated: true, completion: nil)
} }
func restore(_ installedApp: InstalledApp)
{
let message = String(format: NSLocalizedString("This will replace all data you currently have in %@.", comment: ""), installedApp.name)
let alertController = UIAlertController(title: NSLocalizedString("Are you sure you want to restore this backup?", comment: ""), message: message, preferredStyle: .actionSheet)
alertController.addAction(.cancel)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Restore Backup", comment: ""), style: .destructive, handler: { (action) in
AppManager.shared.restore(installedApp, presentingViewController: self) { (result) in
do
{
let app = try result.get()
try? app.managedObjectContext?.save()
print("Finished restoring app:", app.bundleIdentifier)
}
catch
{
print("Failed to restore app:", error)
DispatchQueue.main.async {
let toastView = ToastView(error: error)
toastView.show(in: self)
}
}
}
DispatchQueue.main.async {
self.collectionView.reloadSections([Section.activeApps.rawValue])
}
}))
self.present(alertController, animated: true, completion: nil)
}
func exportBackup(for installedApp: InstalledApp) func exportBackup(for installedApp: InstalledApp)
{ {
guard let backupURL = FileManager.default.backupDirectoryURL(for: installedApp) else { return } guard let backupURL = FileManager.default.backupDirectoryURL(for: installedApp) else { return }
@@ -1201,6 +1234,10 @@ extension MyAppsViewController
self.exportBackup(for: installedApp) self.exportBackup(for: installedApp)
} }
let restoreBackupAction = UIAction(title: NSLocalizedString("Restore Backup", comment: ""), image: UIImage(systemName: "arrow.down.doc")) { (action) in
self.restore(installedApp)
}
guard installedApp.bundleIdentifier != StoreApp.altstoreAppID else { guard installedApp.bundleIdentifier != StoreApp.altstoreAppID else {
return [refreshAction] return [refreshAction]
} }
@@ -1231,6 +1268,11 @@ extension MyAppsViewController
if backupExists if backupExists
{ {
actions.append(exportBackupAction) actions.append(exportBackupAction)
if installedApp.isActive
{
actions.append(restoreBackupAction)
}
} }
else if let error = outError else if let error = outError
{ {