mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-19 19:53:25 +01:00
Adds “Clear Cache” button to remove temporary files and uninstalled app backups
This commit is contained in:
@@ -369,6 +369,7 @@
|
|||||||
D58916FE28C7C55C00E39C8B /* LoggedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58916FD28C7C55C00E39C8B /* LoggedError.swift */; };
|
D58916FE28C7C55C00E39C8B /* LoggedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58916FD28C7C55C00E39C8B /* LoggedError.swift */; };
|
||||||
D58D5F2E26DFE68E00E55E38 /* LaunchAtLogin in Frameworks */ = {isa = PBXBuildFile; productRef = D58D5F2D26DFE68E00E55E38 /* LaunchAtLogin */; };
|
D58D5F2E26DFE68E00E55E38 /* LaunchAtLogin in Frameworks */ = {isa = PBXBuildFile; productRef = D58D5F2D26DFE68E00E55E38 /* LaunchAtLogin */; };
|
||||||
D593F1942717749A006E82DE /* PatchAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D593F1932717749A006E82DE /* PatchAppOperation.swift */; };
|
D593F1942717749A006E82DE /* PatchAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D593F1932717749A006E82DE /* PatchAppOperation.swift */; };
|
||||||
|
D5ACE84528E3B8450021CAB9 /* ClearAppCacheOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACE84428E3B8450021CAB9 /* ClearAppCacheOperation.swift */; };
|
||||||
D5CA0C4B280E141900469595 /* ManagedPatron.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5CA0C4A280E141900469595 /* ManagedPatron.swift */; };
|
D5CA0C4B280E141900469595 /* ManagedPatron.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5CA0C4A280E141900469595 /* ManagedPatron.swift */; };
|
||||||
D5CA0C4E280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = D5CA0C4D280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel */; };
|
D5CA0C4E280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = D5CA0C4D280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel */; };
|
||||||
D5DAE0942804B0B80034D8D4 /* ScreenshotProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DAE0932804B0B80034D8D4 /* ScreenshotProcessor.swift */; };
|
D5DAE0942804B0B80034D8D4 /* ScreenshotProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DAE0932804B0B80034D8D4 /* ScreenshotProcessor.swift */; };
|
||||||
@@ -870,6 +871,7 @@
|
|||||||
D586D39A28EF58B0000E101F /* AltTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AltTests.swift; sourceTree = "<group>"; };
|
D586D39A28EF58B0000E101F /* AltTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AltTests.swift; sourceTree = "<group>"; };
|
||||||
D58916FD28C7C55C00E39C8B /* LoggedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggedError.swift; sourceTree = "<group>"; };
|
D58916FD28C7C55C00E39C8B /* LoggedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggedError.swift; sourceTree = "<group>"; };
|
||||||
D593F1932717749A006E82DE /* PatchAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatchAppOperation.swift; sourceTree = "<group>"; };
|
D593F1932717749A006E82DE /* PatchAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatchAppOperation.swift; sourceTree = "<group>"; };
|
||||||
|
D5ACE84428E3B8450021CAB9 /* ClearAppCacheOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearAppCacheOperation.swift; sourceTree = "<group>"; };
|
||||||
D5CA0C4A280E141900469595 /* ManagedPatron.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedPatron.swift; sourceTree = "<group>"; };
|
D5CA0C4A280E141900469595 /* ManagedPatron.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedPatron.swift; sourceTree = "<group>"; };
|
||||||
D5CA0C4C280E242500469595 /* AltStore 10.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 10.xcdatamodel"; sourceTree = "<group>"; };
|
D5CA0C4C280E242500469595 /* AltStore 10.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 10.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
D5CA0C4D280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore9ToAltStore10.xcmappingmodel; sourceTree = "<group>"; };
|
D5CA0C4D280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore9ToAltStore10.xcmappingmodel; sourceTree = "<group>"; };
|
||||||
@@ -1760,6 +1762,7 @@
|
|||||||
D57F2C9026E0070200B9FA39 /* EnableJITOperation.swift */,
|
D57F2C9026E0070200B9FA39 /* EnableJITOperation.swift */,
|
||||||
D5DAE0952804DF430034D8D4 /* UpdatePatronsOperation.swift */,
|
D5DAE0952804DF430034D8D4 /* UpdatePatronsOperation.swift */,
|
||||||
D5E1E7C028077DE90016FC96 /* FetchTrustedSourcesOperation.swift */,
|
D5E1E7C028077DE90016FC96 /* FetchTrustedSourcesOperation.swift */,
|
||||||
|
D5ACE84428E3B8450021CAB9 /* ClearAppCacheOperation.swift */,
|
||||||
BF7B44062725A4B8005288A4 /* Patch App */,
|
BF7B44062725A4B8005288A4 /* Patch App */,
|
||||||
);
|
);
|
||||||
path = Operations;
|
path = Operations;
|
||||||
@@ -2748,6 +2751,7 @@
|
|||||||
BFD6B03322DFF20800B86064 /* MyAppsComponents.swift in Sources */,
|
BFD6B03322DFF20800B86064 /* MyAppsComponents.swift in Sources */,
|
||||||
BF41B808233433C100C593A3 /* LoadingState.swift in Sources */,
|
BF41B808233433C100C593A3 /* LoadingState.swift in Sources */,
|
||||||
BFF0B69A2322D7D0007A79E1 /* UIScreen+CompactHeight.swift in Sources */,
|
BFF0B69A2322D7D0007A79E1 /* UIScreen+CompactHeight.swift in Sources */,
|
||||||
|
D5ACE84528E3B8450021CAB9 /* ClearAppCacheOperation.swift in Sources */,
|
||||||
D5F2F6A92720B7C20081CCF5 /* PatchViewController.swift in Sources */,
|
D5F2F6A92720B7C20081CCF5 /* PatchViewController.swift in Sources */,
|
||||||
BF8F69C222E659F700049BA1 /* AppContentViewController.swift in Sources */,
|
BF8F69C222E659F700049BA1 /* AppContentViewController.swift in Sources */,
|
||||||
BF08858522DE7EC800DE9F1E /* UpdateCollectionViewCell.swift in Sources */,
|
BF08858522DE7EC800DE9F1E /* UpdateCollectionViewCell.swift in Sources */,
|
||||||
|
|||||||
@@ -344,6 +344,16 @@ extension AppManager
|
|||||||
presentingViewController.present(alertController, animated: true, completion: nil)
|
presentingViewController.present(alertController, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func clearAppCache(completion: @escaping (Result<Void, Error>) -> Void)
|
||||||
|
{
|
||||||
|
let clearAppCacheOperation = ClearAppCacheOperation()
|
||||||
|
clearAppCacheOperation.resultHandler = { result in
|
||||||
|
completion(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.run([clearAppCacheOperation], context: nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppManager
|
extension AppManager
|
||||||
@@ -822,6 +832,12 @@ extension AppManager
|
|||||||
let progress = self.refreshProgress[app.bundleIdentifier]
|
let progress = self.refreshProgress[app.bundleIdentifier]
|
||||||
return progress
|
return progress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isActivelyManagingApp(withBundleID bundleID: String) -> Bool
|
||||||
|
{
|
||||||
|
let isActivelyManaging = self.installationProgress.keys.contains(bundleID) || self.refreshProgress.keys.contains(bundleID)
|
||||||
|
return isActivelyManaging
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppManager
|
extension AppManager
|
||||||
@@ -889,12 +905,6 @@ private extension AppManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isActivelyManagingApp(withBundleID bundleID: String) -> Bool
|
|
||||||
{
|
|
||||||
let isActivelyManaging = self.installationProgress.keys.contains(bundleID) || self.refreshProgress.keys.contains(bundleID)
|
|
||||||
return isActivelyManaging
|
|
||||||
}
|
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
private func perform(_ operations: [AppOperation], presentingViewController: UIViewController?, group: RefreshGroup) -> RefreshGroup
|
private func perform(_ operations: [AppOperation], presentingViewController: UIViewController?, group: RefreshGroup) -> RefreshGroup
|
||||||
{
|
{
|
||||||
|
|||||||
203
AltStore/Operations/ClearAppCacheOperation.swift
Normal file
203
AltStore/Operations/ClearAppCacheOperation.swift
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
//
|
||||||
|
// ClearAppCacheOperation.swift
|
||||||
|
// AltStore
|
||||||
|
//
|
||||||
|
// Created by Riley Testut on 9/27/22.
|
||||||
|
// Copyright © 2022 Riley Testut. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import AltStoreCore
|
||||||
|
|
||||||
|
struct BatchError: ALTLocalizedError
|
||||||
|
{
|
||||||
|
enum Code: Int, ALTErrorCode
|
||||||
|
{
|
||||||
|
typealias Error = BatchError
|
||||||
|
|
||||||
|
case batchError
|
||||||
|
}
|
||||||
|
|
||||||
|
var code: Code = .batchError
|
||||||
|
var underlyingErrors: [Error]
|
||||||
|
|
||||||
|
var errorTitle: String?
|
||||||
|
var errorFailure: String?
|
||||||
|
|
||||||
|
init(errors: [Error])
|
||||||
|
{
|
||||||
|
self.underlyingErrors = errors
|
||||||
|
}
|
||||||
|
|
||||||
|
var errorFailureReason: String {
|
||||||
|
guard !self.underlyingErrors.isEmpty else { return NSLocalizedString("An unknown error occured.", comment: "") }
|
||||||
|
|
||||||
|
let errorMessages = self.underlyingErrors.map { $0.localizedDescription }
|
||||||
|
|
||||||
|
let message = errorMessages.joined(separator: "\n\n")
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(ClearAppCacheOperation)
|
||||||
|
class ClearAppCacheOperation: ResultOperation<Void>
|
||||||
|
{
|
||||||
|
private let coordinator = NSFileCoordinator()
|
||||||
|
private let coordinatorQueue = OperationQueue()
|
||||||
|
|
||||||
|
override init()
|
||||||
|
{
|
||||||
|
self.coordinatorQueue.name = "AltStore - ClearAppCacheOperation Queue"
|
||||||
|
}
|
||||||
|
|
||||||
|
override func main()
|
||||||
|
{
|
||||||
|
super.main()
|
||||||
|
|
||||||
|
var allErrors = [Error]()
|
||||||
|
|
||||||
|
self.clearTemporaryDirectory { result in
|
||||||
|
switch result
|
||||||
|
{
|
||||||
|
case .failure(let batchError as BatchError): allErrors.append(contentsOf: batchError.underlyingErrors)
|
||||||
|
case .failure(let error): allErrors.append(error)
|
||||||
|
case .success: break
|
||||||
|
}
|
||||||
|
|
||||||
|
self.removeUninstalledAppBackupDirectories { result in
|
||||||
|
switch result
|
||||||
|
{
|
||||||
|
case .failure(let batchError as BatchError): allErrors.append(contentsOf: batchError.underlyingErrors)
|
||||||
|
case .failure(let error): allErrors.append(error)
|
||||||
|
case .success: break
|
||||||
|
}
|
||||||
|
|
||||||
|
if allErrors.isEmpty
|
||||||
|
{
|
||||||
|
self.finish(.success(()))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let error = BatchError(errors: allErrors)
|
||||||
|
self.finish(.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension ClearAppCacheOperation
|
||||||
|
{
|
||||||
|
func clearTemporaryDirectory(completion: @escaping (Result<Void, Error>) -> Void)
|
||||||
|
{
|
||||||
|
let intent = NSFileAccessIntent.writingIntent(with: FileManager.default.temporaryDirectory, options: [.forDeleting])
|
||||||
|
self.coordinator.coordinate(with: [intent], queue: self.coordinatorQueue) { (error) in
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if let error
|
||||||
|
{
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileURLs = try FileManager.default.contentsOfDirectory(at: intent.url,
|
||||||
|
includingPropertiesForKeys: [],
|
||||||
|
options: [.skipsSubdirectoryDescendants, .skipsHiddenFiles])
|
||||||
|
var errors = [Error]()
|
||||||
|
|
||||||
|
for fileURL in fileURLs
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
print("[ALTLog] Removing item from temporary directory:", fileURL.lastPathComponent)
|
||||||
|
try FileManager.default.removeItem(at: fileURL)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print("[ALTLog] Failed to remove \(fileURL.lastPathComponent) from temporary directory.", error)
|
||||||
|
errors.append(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !errors.isEmpty
|
||||||
|
{
|
||||||
|
let error = BatchError(errors: errors)
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
completion(.success(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeUninstalledAppBackupDirectories(completion: @escaping (Result<Void, Error>) -> Void)
|
||||||
|
{
|
||||||
|
guard let backupsDirectory = FileManager.default.appBackupsDirectory else { return completion(.failure(OperationError.missingAppGroup)) }
|
||||||
|
|
||||||
|
DatabaseManager.shared.persistentContainer.performBackgroundTask { context in
|
||||||
|
let installedAppBundleIDs = Set(InstalledApp.all(in: context).map { $0.bundleIdentifier })
|
||||||
|
|
||||||
|
let intent = NSFileAccessIntent.writingIntent(with: backupsDirectory, options: [.forDeleting])
|
||||||
|
self.coordinator.coordinate(with: [intent], queue: self.coordinatorQueue) { (error) in
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if let error
|
||||||
|
{
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
|
||||||
|
var isDirectory: ObjCBool = false
|
||||||
|
guard FileManager.default.fileExists(atPath: intent.url.path, isDirectory: &isDirectory), isDirectory.boolValue else {
|
||||||
|
completion(.success(()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileURLs = try FileManager.default.contentsOfDirectory(at: intent.url,
|
||||||
|
includingPropertiesForKeys: [.isDirectoryKey, .nameKey],
|
||||||
|
options: [.skipsSubdirectoryDescendants, .skipsHiddenFiles])
|
||||||
|
var errors = [Error]()
|
||||||
|
|
||||||
|
for backupDirectory in fileURLs
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
let resourceValues = try backupDirectory.resourceValues(forKeys: [.isDirectoryKey, .nameKey])
|
||||||
|
guard let isDirectory = resourceValues.isDirectory, let bundleID = resourceValues.name else { continue }
|
||||||
|
|
||||||
|
if isDirectory && !installedAppBundleIDs.contains(bundleID) && !AppManager.shared.isActivelyManagingApp(withBundleID: bundleID)
|
||||||
|
{
|
||||||
|
print("[ALTLog] Removing backup directory for uninstalled app:", bundleID)
|
||||||
|
try FileManager.default.removeItem(at: backupDirectory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print("[ALTLog] Failed to remove app backup directory:", error)
|
||||||
|
errors.append(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !errors.isEmpty
|
||||||
|
{
|
||||||
|
let error = BatchError(errors: errors)
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
completion(.success(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print("[ALTLog] Failed to remove app backup directory:", error)
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -344,6 +344,34 @@
|
|||||||
<segue destination="g8a-Rf-zWa" kind="show" identifier="showErrorLog" id="z7r-Rq-qJY"/>
|
<segue destination="g8a-Rf-zWa" kind="show" identifier="showErrorLog" id="z7r-Rq-qJY"/>
|
||||||
</connections>
|
</connections>
|
||||||
</tableViewCell>
|
</tableViewCell>
|
||||||
|
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="hFh-X1-ZAi" customClass="InsetGroupTableViewCell" customModule="AltStore" customModuleProvider="target">
|
||||||
|
<rect key="frame" x="0.0" y="673" width="375" height="51"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hFh-X1-ZAi" id="nCs-Ro-A6t">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<subviews>
|
||||||
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Clear Cache…" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="j4e-Mz-DlL">
|
||||||
|
<rect key="frame" x="30" y="15.5" width="114.5" height="20.5"/>
|
||||||
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
||||||
|
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="j4e-Mz-DlL" firstAttribute="centerY" secondItem="nCs-Ro-A6t" secondAttribute="centerY" id="5Rf-51-szq"/>
|
||||||
|
<constraint firstItem="j4e-Mz-DlL" firstAttribute="leading" secondItem="nCs-Ro-A6t" secondAttribute="leadingMargin" id="Gx3-gM-kRK"/>
|
||||||
|
</constraints>
|
||||||
|
</tableViewCellContentView>
|
||||||
|
<color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
|
||||||
|
<userDefinedRuntimeAttributes>
|
||||||
|
<userDefinedRuntimeAttribute type="number" keyPath="style">
|
||||||
|
<integer key="value" value="3"/>
|
||||||
|
</userDefinedRuntimeAttribute>
|
||||||
|
<userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/>
|
||||||
|
</userDefinedRuntimeAttributes>
|
||||||
|
</tableViewCell>
|
||||||
</cells>
|
</cells>
|
||||||
</tableViewSection>
|
</tableViewSection>
|
||||||
<tableViewSection headerTitle="" id="J90-vn-u2O">
|
<tableViewSection headerTitle="" id="J90-vn-u2O">
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ extension SettingsViewController
|
|||||||
case softwareLicenses
|
case softwareLicenses
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileprivate enum TechyThingsRow: Int, CaseIterable
|
||||||
|
{
|
||||||
|
case errorLog
|
||||||
|
case clearCache
|
||||||
|
}
|
||||||
|
|
||||||
fileprivate enum DebugRow: Int, CaseIterable
|
fileprivate enum DebugRow: Int, CaseIterable
|
||||||
{
|
{
|
||||||
case sendFeedback
|
case sendFeedback
|
||||||
@@ -327,6 +333,34 @@ private extension SettingsViewController
|
|||||||
self.present(viewController, animated: true, completion: nil)
|
self.present(viewController, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func clearCache()
|
||||||
|
{
|
||||||
|
let alertController = UIAlertController(title: NSLocalizedString("Are you sure you want to clear AltStore's cache?", comment: ""),
|
||||||
|
message: NSLocalizedString("This will remove all temporary files as well as backups for uninstalled apps.", comment: ""),
|
||||||
|
preferredStyle: .actionSheet)
|
||||||
|
alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style) { [weak self] _ in
|
||||||
|
self?.tableView.indexPathForSelectedRow.map { self?.tableView.deselectRow(at: $0, animated: true) }
|
||||||
|
})
|
||||||
|
alertController.addAction(UIAlertAction(title: NSLocalizedString("Clear Cache", comment: ""), style: .destructive) { [weak self] _ in
|
||||||
|
AppManager.shared.clearAppCache { result in
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self?.tableView.indexPathForSelectedRow.map { self?.tableView.deselectRow(at: $0, animated: true) }
|
||||||
|
|
||||||
|
switch result
|
||||||
|
{
|
||||||
|
case .success: break
|
||||||
|
case .failure(let error):
|
||||||
|
let alertController = UIAlertController(title: NSLocalizedString("Unable to Clear Cache", comment: ""), message: error.localizedDescription, preferredStyle: .alert)
|
||||||
|
alertController.addAction(.ok)
|
||||||
|
self?.present(alertController, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.present(alertController, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
@IBAction func handleDebugModeGesture(_ gestureRecognizer: UISwipeGestureRecognizer)
|
@IBAction func handleDebugModeGesture(_ gestureRecognizer: UISwipeGestureRecognizer)
|
||||||
{
|
{
|
||||||
self.debugGestureCounter += 1
|
self.debugGestureCounter += 1
|
||||||
@@ -521,6 +555,14 @@ extension SettingsViewController
|
|||||||
self.addRefreshAppsShortcut()
|
self.addRefreshAppsShortcut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case .techyThings:
|
||||||
|
let row = TechyThingsRow.allCases[indexPath.row]
|
||||||
|
switch row
|
||||||
|
{
|
||||||
|
case .errorLog: break
|
||||||
|
case .clearCache: self.clearCache()
|
||||||
|
}
|
||||||
|
|
||||||
case .credits:
|
case .credits:
|
||||||
let row = CreditsRow.allCases[indexPath.row]
|
let row = CreditsRow.allCases[indexPath.row]
|
||||||
switch row
|
switch row
|
||||||
@@ -562,7 +604,7 @@ extension SettingsViewController
|
|||||||
case .refreshAttempts: break
|
case .refreshAttempts: break
|
||||||
}
|
}
|
||||||
|
|
||||||
case .account, .patreon, .instructions, .techyThings, .macDirtyCow: break
|
case .account, .patreon, .instructions, .macDirtyCow: break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user