mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-19 19:53:25 +01:00
Removes active app extension limits on 13.5 or later
This commit is contained in:
@@ -23,6 +23,7 @@ extension UserDefaults
|
|||||||
@NSManaged var legacySideloadedApps: [String]?
|
@NSManaged var legacySideloadedApps: [String]?
|
||||||
|
|
||||||
@NSManaged var isLegacyDeactivationSupported: Bool
|
@NSManaged var isLegacyDeactivationSupported: Bool
|
||||||
|
@NSManaged var activeAppLimitIncludesExtensions: Bool
|
||||||
|
|
||||||
var activeAppsLimit: Int? {
|
var activeAppsLimit: Int? {
|
||||||
get {
|
get {
|
||||||
@@ -43,9 +44,13 @@ extension UserDefaults
|
|||||||
|
|
||||||
func registerDefaults()
|
func registerDefaults()
|
||||||
{
|
{
|
||||||
|
let ios13_5 = OperatingSystemVersion(majorVersion: 13, minorVersion: 5, patchVersion: 0)
|
||||||
|
let activeAppLimitIncludesExtensions = !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios13_5)
|
||||||
|
|
||||||
self.register(defaults: [
|
self.register(defaults: [
|
||||||
#keyPath(UserDefaults.isBackgroundRefreshEnabled): true,
|
#keyPath(UserDefaults.isBackgroundRefreshEnabled): true,
|
||||||
#keyPath(UserDefaults.isLegacyDeactivationSupported): false
|
#keyPath(UserDefaults.isLegacyDeactivationSupported): false,
|
||||||
|
#keyPath(UserDefaults.activeAppLimitIncludesExtensions): activeAppLimitIncludesExtensions
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ class InstalledApp: NSManagedObject, InstalledAppProtocol
|
|||||||
return 1 + self.appExtensions.count
|
return 1 + self.appExtensions.count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var requiredActiveSlots: Int {
|
||||||
|
let requiredActiveSlots = UserDefaults.standard.activeAppLimitIncludesExtensions ? self.appIDCount : 1
|
||||||
|
return requiredActiveSlots
|
||||||
|
}
|
||||||
|
|
||||||
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)
|
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)
|
||||||
{
|
{
|
||||||
super.init(entity: entity, insertInto: context)
|
super.init(entity: entity, insertInto: context)
|
||||||
|
|||||||
@@ -809,7 +809,18 @@ private extension MyAppsViewController
|
|||||||
|
|
||||||
@objc func presentInactiveAppsAlert()
|
@objc func presentInactiveAppsAlert()
|
||||||
{
|
{
|
||||||
let alertController = UIAlertController(title: NSLocalizedString("What are inactive apps?", comment: ""), message: NSLocalizedString("Free developer accounts are limited to 3 apps and app extensions. Inactive apps don't count towards your total, but cannot be opened until activated.", comment: ""), preferredStyle: .alert)
|
let message: String
|
||||||
|
|
||||||
|
if UserDefaults.standard.activeAppLimitIncludesExtensions
|
||||||
|
{
|
||||||
|
message = NSLocalizedString("Free developer accounts are limited to 3 apps and app extensions. Inactive apps don't count towards your total, but cannot be opened until activated.", comment: "")
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = NSLocalizedString("Free developer accounts are limited to 3 apps. Inactive apps are backed up and uninstalled so they don't count towards your total, but will be reinstalled with all their data when activated again.", comment: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
let alertController = UIAlertController(title: NSLocalizedString("What are inactive apps?", comment: ""), message: message, preferredStyle: .alert)
|
||||||
alertController.addAction(.ok)
|
alertController.addAction(.ok)
|
||||||
self.present(alertController, animated: true, completion: nil)
|
self.present(alertController, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
@@ -929,12 +940,34 @@ private extension MyAppsViewController
|
|||||||
let activeApps = InstalledApp.fetchActiveApps(in: DatabaseManager.shared.viewContext)
|
let activeApps = InstalledApp.fetchActiveApps(in: DatabaseManager.shared.viewContext)
|
||||||
.filter { $0.bundleIdentifier != installedApp.bundleIdentifier } // Don't count app towards total if it matches activating app
|
.filter { $0.bundleIdentifier != installedApp.bundleIdentifier } // Don't count app towards total if it matches activating app
|
||||||
|
|
||||||
let activeAppsCount = activeApps.map { $0.appIDCount }.reduce(0, +)
|
var title: String = NSLocalizedString("Cannot Activate More than 3 Apps", comment: "")
|
||||||
|
let message: String
|
||||||
|
|
||||||
|
if UserDefaults.standard.activeAppLimitIncludesExtensions
|
||||||
|
{
|
||||||
|
if installedApp.appExtensions.isEmpty
|
||||||
|
{
|
||||||
|
message = NSLocalizedString("Free developer accounts are limited to 3 active apps and app extensions. Please choose an app to deactivate.", comment: "")
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
title = NSLocalizedString("Cannot Activate More than 3 Apps and App Extensions", comment: "")
|
||||||
|
|
||||||
|
let appExtensionText = installedApp.appExtensions.count == 1 ? NSLocalizedString("app extension", comment: "") : NSLocalizedString("app extensions", comment: "")
|
||||||
|
message = String(format: NSLocalizedString("Free developer accounts are limited to 3 active apps and app extensions, and “%@” contains %@ %@. Please choose an app to deactivate.", comment: ""), installedApp.name, NSNumber(value: installedApp.appExtensions.count), appExtensionText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = NSLocalizedString("Free developer accounts are limited to 3 active apps. Please choose an app to deactivate.", comment: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
let activeAppsCount = activeApps.map { $0.requiredActiveSlots }.reduce(0, +)
|
||||||
|
|
||||||
let availableActiveApps = max(activeAppsLimit - activeAppsCount, 0)
|
let availableActiveApps = max(activeAppsLimit - activeAppsCount, 0)
|
||||||
guard installedApp.appIDCount > availableActiveApps else { return completion(true) }
|
guard installedApp.requiredActiveSlots > availableActiveApps else { return completion(true) }
|
||||||
|
|
||||||
let alertController = UIAlertController(title: NSLocalizedString("Cannot Activate More than 3 Apps", comment: ""), message: NSLocalizedString("Free developer accounts are limited to 3 active apps and app extensions. Please choose an app to deactivate.", comment: ""), preferredStyle: .alert)
|
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
||||||
alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style) { (action) in
|
alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style) { (action) in
|
||||||
completion(false)
|
completion(false)
|
||||||
})
|
})
|
||||||
@@ -942,8 +975,8 @@ private extension MyAppsViewController
|
|||||||
for app in activeApps where app.bundleIdentifier != StoreApp.altstoreAppID
|
for app in activeApps where app.bundleIdentifier != StoreApp.altstoreAppID
|
||||||
{
|
{
|
||||||
alertController.addAction(UIAlertAction(title: app.name, style: .default) { (action) in
|
alertController.addAction(UIAlertAction(title: app.name, style: .default) { (action) in
|
||||||
let availableActiveApps = availableActiveApps + app.appIDCount
|
let availableActiveApps = availableActiveApps + app.requiredActiveSlots
|
||||||
if availableActiveApps >= installedApp.appIDCount
|
if availableActiveApps >= installedApp.requiredActiveSlots
|
||||||
{
|
{
|
||||||
// There are enough slots now to activate the app, so pre-emptively
|
// There are enough slots now to activate the app, so pre-emptively
|
||||||
// mark it as active to provide visual feedback sooner.
|
// mark it as active to provide visual feedback sooner.
|
||||||
@@ -1572,10 +1605,10 @@ extension MyAppsViewController: UICollectionViewDropDelegate
|
|||||||
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
|
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
let activeAppsCount = (self.activeAppsDataSource.fetchedResultsController.fetchedObjects ?? []).map { $0.appIDCount }.reduce(0, +)
|
let activeAppsCount = (self.activeAppsDataSource.fetchedResultsController.fetchedObjects ?? []).map { $0.requiredActiveSlots }.reduce(0, +)
|
||||||
let availableActiveApps = max(activeAppsLimit - activeAppsCount, 0)
|
let availableActiveApps = max(activeAppsLimit - activeAppsCount, 0)
|
||||||
|
|
||||||
if installedApp.appIDCount <= availableActiveApps
|
if installedApp.requiredActiveSlots <= availableActiveApps
|
||||||
{
|
{
|
||||||
// Enough active app slots, so no need to deactivate app first.
|
// Enough active app slots, so no need to deactivate app first.
|
||||||
return UICollectionViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath)
|
return UICollectionViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath)
|
||||||
|
|||||||
@@ -122,10 +122,10 @@ class InstallAppOperation: ResultOperation<InstalledApp>
|
|||||||
var activeApps = InstalledApp.fetch(fetchRequest, in: backgroundContext)
|
var activeApps = InstalledApp.fetch(fetchRequest, in: backgroundContext)
|
||||||
if !activeApps.contains(installedApp)
|
if !activeApps.contains(installedApp)
|
||||||
{
|
{
|
||||||
let availableActiveApps = max(sideloadedAppsLimit - activeApps.count, 0)
|
let activeAppsCount = activeApps.map { $0.requiredActiveSlots }.reduce(0, +)
|
||||||
let requiredActiveAppSlots = 1 + installedExtensions.count // As of iOS 13.3.1, app extensions count as "apps"
|
|
||||||
|
|
||||||
if requiredActiveAppSlots <= availableActiveApps
|
let availableActiveApps = max(sideloadedAppsLimit - activeAppsCount, 0)
|
||||||
|
if installedApp.requiredActiveSlots <= availableActiveApps
|
||||||
{
|
{
|
||||||
// This app has not been explicitly activated, but there are enough slots available,
|
// This app has not been explicitly activated, but there are enough slots available,
|
||||||
// so implicitly activate it.
|
// so implicitly activate it.
|
||||||
|
|||||||
Reference in New Issue
Block a user