mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-20 04:03:26 +01:00
Supports removing inactive apps from My Apps
This commit is contained in:
@@ -22,6 +22,8 @@ extension UserDefaults
|
|||||||
|
|
||||||
@NSManaged var legacySideloadedApps: [String]?
|
@NSManaged var legacySideloadedApps: [String]?
|
||||||
|
|
||||||
|
@NSManaged var isLegacyDeactivationSupported: Bool
|
||||||
|
|
||||||
var activeAppsLimit: Int? {
|
var activeAppsLimit: Int? {
|
||||||
get {
|
get {
|
||||||
return self._activeAppsLimit?.intValue
|
return self._activeAppsLimit?.intValue
|
||||||
@@ -41,6 +43,9 @@ extension UserDefaults
|
|||||||
|
|
||||||
func registerDefaults()
|
func registerDefaults()
|
||||||
{
|
{
|
||||||
self.register(defaults: [#keyPath(UserDefaults.isBackgroundRefreshEnabled): true])
|
self.register(defaults: [
|
||||||
|
#keyPath(UserDefaults.isBackgroundRefreshEnabled): true,
|
||||||
|
#keyPath(UserDefaults.isLegacyDeactivationSupported): false
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -344,6 +344,48 @@ extension AppManager
|
|||||||
self.run([deactivateAppOperation], context: context, requiresSerialQueue: true)
|
self.run([deactivateAppOperation], context: context, requiresSerialQueue: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func remove(_ installedApp: InstalledApp, completionHandler: @escaping (Result<Void, Error>) -> Void)
|
||||||
|
{
|
||||||
|
let authenticationContext = AuthenticatedOperationContext()
|
||||||
|
let appContext = InstallAppOperationContext(bundleIdentifier: installedApp.bundleIdentifier, authenticatedContext: authenticationContext)
|
||||||
|
appContext.installedApp = installedApp
|
||||||
|
|
||||||
|
let removeAppOperation = RSTAsyncBlockOperation { (operation) in
|
||||||
|
DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in
|
||||||
|
let installedApp = context.object(with: installedApp.objectID) as! InstalledApp
|
||||||
|
context.delete(installedApp)
|
||||||
|
|
||||||
|
do { try context.save() }
|
||||||
|
catch { appContext.error = error }
|
||||||
|
|
||||||
|
operation.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let removeAppBackupOperation = RemoveAppBackupOperation(context: appContext)
|
||||||
|
removeAppBackupOperation.resultHandler = { (result) in
|
||||||
|
switch result
|
||||||
|
{
|
||||||
|
case .success: break
|
||||||
|
case .failure(let error): print("Failed to remove app backup.", error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw the error from removeAppOperation,
|
||||||
|
// since that's the error we really care about.
|
||||||
|
if let error = appContext.error
|
||||||
|
{
|
||||||
|
completionHandler(.failure(error))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
completionHandler(.success(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeAppBackupOperation.addDependency(removeAppOperation)
|
||||||
|
|
||||||
|
self.run([removeAppOperation, removeAppBackupOperation], context: authenticationContext)
|
||||||
|
}
|
||||||
|
|
||||||
func installationProgress(for app: AppProtocol) -> Progress?
|
func installationProgress(for app: AppProtocol) -> Progress?
|
||||||
{
|
{
|
||||||
let progress = self.installationProgress[app.bundleIdentifier]
|
let progress = self.installationProgress[app.bundleIdentifier]
|
||||||
|
|||||||
@@ -960,15 +960,31 @@ private extension MyAppsViewController
|
|||||||
|
|
||||||
func remove(_ installedApp: InstalledApp)
|
func remove(_ installedApp: InstalledApp)
|
||||||
{
|
{
|
||||||
let alertController = UIAlertController(title: nil, message: NSLocalizedString("Removing a sideloaded app only removes it from AltStore. You must also delete it from the home screen to fully uninstall the app.", comment: ""), preferredStyle: .actionSheet)
|
let title = String(format: NSLocalizedString("Remove “%@” from AltStore?", comment: ""), installedApp.name)
|
||||||
|
let message: String
|
||||||
|
|
||||||
|
if UserDefaults.standard.isLegacyDeactivationSupported
|
||||||
|
{
|
||||||
|
message = NSLocalizedString("You must also delete it from the home screen to fully uninstall the app.", comment: "")
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = NSLocalizedString("This will also erase all backup data for this app.", comment: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
let alertController = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)
|
||||||
alertController.addAction(.cancel)
|
alertController.addAction(.cancel)
|
||||||
alertController.addAction(UIAlertAction(title: NSLocalizedString("Remove", comment: ""), style: .destructive, handler: { (action) in
|
alertController.addAction(UIAlertAction(title: NSLocalizedString("Remove", comment: ""), style: .destructive, handler: { (action) in
|
||||||
DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in
|
AppManager.shared.remove(installedApp) { (result) in
|
||||||
let installedApp = context.object(with: installedApp.objectID) as! InstalledApp
|
switch result
|
||||||
context.delete(installedApp)
|
{
|
||||||
|
case .success: break
|
||||||
do { try context.save() }
|
case .failure(let error):
|
||||||
catch { print("Failed to remove sideloaded app.", error) }
|
DispatchQueue.main.async {
|
||||||
|
let toastView = ToastView(error: error)
|
||||||
|
toastView.show(in: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@@ -1161,39 +1177,43 @@ extension MyAppsViewController
|
|||||||
self.remove(installedApp)
|
self.remove(installedApp)
|
||||||
}
|
}
|
||||||
|
|
||||||
if installedApp.bundleIdentifier == StoreApp.altstoreAppID
|
guard installedApp.bundleIdentifier != StoreApp.altstoreAppID else {
|
||||||
|
return [refreshAction]
|
||||||
|
}
|
||||||
|
|
||||||
|
if installedApp.isActive
|
||||||
{
|
{
|
||||||
actions = [refreshAction]
|
actions.append(refreshAction)
|
||||||
|
actions.append(deactivateAction)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if installedApp.isActive
|
actions.append(activateAction)
|
||||||
{
|
|
||||||
if UserDefaults.standard.activeAppsLimit != nil
|
|
||||||
{
|
|
||||||
actions = [refreshAction, deactivateAction]
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
actions = [refreshAction]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
actions.append(activateAction)
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
actions.append(removeAction)
|
|
||||||
#else
|
|
||||||
if (UserDefaults.standard.legacySideloadedApps ?? []).contains(installedApp.bundleIdentifier)
|
|
||||||
{
|
|
||||||
// Only display option for legacy sideloaded apps.
|
|
||||||
actions.append(removeAction)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
|
||||||
|
if installedApp.bundleIdentifier != StoreApp.altstoreAppID
|
||||||
|
{
|
||||||
|
actions.append(removeAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
if (UserDefaults.standard.legacySideloadedApps ?? []).contains(installedApp.bundleIdentifier)
|
||||||
|
{
|
||||||
|
// Legacy sideloaded app, so can't detect if it's deleted.
|
||||||
|
actions.append(removeAction)
|
||||||
|
}
|
||||||
|
else if !UserDefaults.standard.isLegacyDeactivationSupported && !installedApp.isActive
|
||||||
|
{
|
||||||
|
// Inactive apps are actually deleted, so we need another way
|
||||||
|
// for user to remove them from AltStore.
|
||||||
|
actions.append(removeAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
return actions
|
return actions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user