Purge cache (IOS-14)
This commit is contained in:
parent
951f46353f
commit
6b12224578
|
@ -10,7 +10,7 @@ protocol AboutViewControllerDelegate: AnyObject {
|
||||||
class AboutViewController: UIViewController {
|
class AboutViewController: UIViewController {
|
||||||
|
|
||||||
let tableView: UITableView
|
let tableView: UITableView
|
||||||
let sections: [AboutSettingsSection]
|
private(set) var sections: [AboutSettingsSection] = []
|
||||||
var tableViewDataSource: UITableViewDiffableDataSource<AboutSettingsSection, AboutSettingsEntry>?
|
var tableViewDataSource: UITableViewDiffableDataSource<AboutSettingsSection, AboutSettingsEntry>?
|
||||||
weak var delegate: AboutViewControllerDelegate?
|
weak var delegate: AboutViewControllerDelegate?
|
||||||
|
|
||||||
|
@ -20,17 +20,6 @@ class AboutViewController: UIViewController {
|
||||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
tableView.register(AboutMastodonTableViewCell.self, forCellReuseIdentifier: AboutMastodonTableViewCell.reuseIdentifier)
|
tableView.register(AboutMastodonTableViewCell.self, forCellReuseIdentifier: AboutMastodonTableViewCell.reuseIdentifier)
|
||||||
|
|
||||||
sections = [
|
|
||||||
AboutSettingsSection(entries: [
|
|
||||||
.evenMoreSettings,
|
|
||||||
.contributeToMastodon,
|
|
||||||
.privacyPolicy
|
|
||||||
]),
|
|
||||||
AboutSettingsSection(entries: [
|
|
||||||
.clearMediaCache(AppContext.shared.currentDiskUsage())
|
|
||||||
])
|
|
||||||
]
|
|
||||||
|
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
|
||||||
let tableViewDataSource = UITableViewDiffableDataSource<AboutSettingsSection, AboutSettingsEntry>(tableView: tableView) { [weak self] tableView, indexPath, itemIdentifier in
|
let tableViewDataSource = UITableViewDiffableDataSource<AboutSettingsSection, AboutSettingsEntry>(tableView: tableView) { [weak self] tableView, indexPath, itemIdentifier in
|
||||||
|
@ -58,6 +47,20 @@ class AboutViewController: UIViewController {
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
update(with:
|
||||||
|
[AboutSettingsSection(entries: [
|
||||||
|
.evenMoreSettings,
|
||||||
|
.contributeToMastodon,
|
||||||
|
.privacyPolicy
|
||||||
|
]),
|
||||||
|
AboutSettingsSection(entries: [
|
||||||
|
.clearMediaCache(AppContext.shared.currentDiskUsage())
|
||||||
|
])]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(with sections: [AboutSettingsSection]) {
|
||||||
|
self.sections = sections
|
||||||
|
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<AboutSettingsSection, AboutSettingsEntry>()
|
var snapshot = NSDiffableDataSourceSnapshot<AboutSettingsSection, AboutSettingsEntry>()
|
||||||
|
|
||||||
|
@ -66,7 +69,7 @@ class AboutViewController: UIViewController {
|
||||||
snapshot.appendItems(section.entries)
|
snapshot.appendItems(section.entries)
|
||||||
}
|
}
|
||||||
|
|
||||||
tableViewDataSource?.apply(snapshot)
|
tableViewDataSource?.apply(snapshot, animatingDifferences: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import AuthenticationServices
|
import AuthenticationServices
|
||||||
|
import MastodonCore
|
||||||
|
|
||||||
protocol SettingsCoordinatorDelegate: AnyObject {
|
protocol SettingsCoordinatorDelegate: AnyObject {
|
||||||
func logout(_ settingsCoordinator: SettingsCoordinator)
|
func logout(_ settingsCoordinator: SettingsCoordinator)
|
||||||
|
@ -71,9 +72,18 @@ extension SettingsCoordinator: AboutViewControllerDelegate {
|
||||||
case .privacyPolicy:
|
case .privacyPolicy:
|
||||||
delegate?.openPrivacyURL(self)
|
delegate?.openPrivacyURL(self)
|
||||||
case .clearMediaCache(_):
|
case .clearMediaCache(_):
|
||||||
//TODO: appContext.purgeCache()
|
|
||||||
//FIXME: maybe we should inject an AppContext/AuthContext here instead of delegating everything to SceneCoordinator?
|
//FIXME: maybe we should inject an AppContext/AuthContext here instead of delegating everything to SceneCoordinator?
|
||||||
break
|
AppContext.shared.purgeCache()
|
||||||
|
viewController.update(with:
|
||||||
|
[AboutSettingsSection(entries: [
|
||||||
|
.evenMoreSettings,
|
||||||
|
.contributeToMastodon,
|
||||||
|
.privacyPolicy
|
||||||
|
]),
|
||||||
|
AboutSettingsSection(entries: [
|
||||||
|
.clearMediaCache(AppContext.shared.currentDiskUsage())
|
||||||
|
])]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,76 +126,51 @@ extension AppContext {
|
||||||
return formatter
|
return formatter
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private static let purgeCacheWorkingQueue = DispatchQueue(label: "org.joinmastodon.app.AppContext.purgeCacheWorkingQueue")
|
public func purgeCache() {
|
||||||
|
ImageDownloader.defaultURLCache().removeAllCachedResponses()
|
||||||
|
|
||||||
public func purgeCache() -> AnyPublisher<ByteCount, Never> {
|
let fileManager = FileManager.default
|
||||||
Publishers.MergeMany([
|
let temporaryDirectoryURL = fileManager.temporaryDirectory
|
||||||
AppContext.purgeAlamofireImageCache(),
|
let fileKeys: [URLResourceKey] = [.fileSizeKey, .isDirectoryKey]
|
||||||
AppContext.purgeTemporaryDirectory(),
|
|
||||||
])
|
if let directoryEnumerator = fileManager.enumerator(
|
||||||
.reduce(0, +)
|
at: temporaryDirectoryURL,
|
||||||
.eraseToAnyPublisher()
|
includingPropertiesForKeys: fileKeys,
|
||||||
|
options: .skipsHiddenFiles) {
|
||||||
|
for case let fileURL as URL in directoryEnumerator {
|
||||||
|
guard let resourceValues = try? fileURL.resourceValues(forKeys: Set(fileKeys)),
|
||||||
|
resourceValues.isDirectory == false else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
try? fileManager.removeItem(at: fileURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In Bytes
|
||||||
public func currentDiskUsage() -> Int {
|
public func currentDiskUsage() -> Int {
|
||||||
let alamoFireDiskBytes = ImageDownloader.defaultURLCache().currentDiskUsage
|
let alamoFireDiskBytes = ImageDownloader.defaultURLCache().currentDiskUsage
|
||||||
//TODO: Add temp directory files
|
|
||||||
return alamoFireDiskBytes
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func purgeAlamofireImageCache() -> AnyPublisher<ByteCount, Never> {
|
var tempFilesDiskBytes = 0
|
||||||
Future<ByteCount, Never> { promise in
|
let fileManager = FileManager.default
|
||||||
AppContext.purgeCacheWorkingQueue.async {
|
let temporaryDirectoryURL = fileManager.temporaryDirectory
|
||||||
// clean image cache for AlamofireImage
|
let fileKeys: [URLResourceKey] = [.fileSizeKey, .isDirectoryKey]
|
||||||
let diskBytes = ImageDownloader.defaultURLCache().currentDiskUsage
|
|
||||||
ImageDownloader.defaultURLCache().removeAllCachedResponses()
|
if let directoryEnumerator = fileManager.enumerator(
|
||||||
let currentDiskBytes = ImageDownloader.defaultURLCache().currentDiskUsage
|
at: temporaryDirectoryURL,
|
||||||
let purgedDiskBytes = max(0, diskBytes - currentDiskBytes)
|
includingPropertiesForKeys: fileKeys,
|
||||||
promise(.success(purgedDiskBytes))
|
options: .skipsHiddenFiles) {
|
||||||
|
for case let fileURL as URL in directoryEnumerator {
|
||||||
|
guard let resourceValues = try? fileURL.resourceValues(forKeys: Set(fileKeys)),
|
||||||
|
resourceValues.isDirectory == false else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tempFilesDiskBytes += resourceValues.fileSize ?? 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.eraseToAnyPublisher()
|
|
||||||
|
return alamoFireDiskBytes + tempFilesDiskBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func purgeTemporaryDirectory() -> AnyPublisher<ByteCount, Never> {
|
|
||||||
Future<ByteCount, Never> { promise in
|
|
||||||
AppContext.purgeCacheWorkingQueue.async {
|
|
||||||
let fileManager = FileManager.default
|
|
||||||
let temporaryDirectoryURL = fileManager.temporaryDirectory
|
|
||||||
|
|
||||||
let resourceKeys = Set<URLResourceKey>([.fileSizeKey, .isDirectoryKey])
|
|
||||||
guard let directoryEnumerator = fileManager.enumerator(
|
|
||||||
at: temporaryDirectoryURL,
|
|
||||||
includingPropertiesForKeys: Array(resourceKeys),
|
|
||||||
options: .skipsHiddenFiles
|
|
||||||
) else {
|
|
||||||
promise(.success(0))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileURLs: [URL] = []
|
|
||||||
var totalFileSizeInBytes = 0
|
|
||||||
for case let fileURL as URL in directoryEnumerator {
|
|
||||||
guard let resourceValues = try? fileURL.resourceValues(forKeys: resourceKeys),
|
|
||||||
let isDirectory = resourceValues.isDirectory else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
guard !isDirectory else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fileURLs.append(fileURL)
|
|
||||||
totalFileSizeInBytes += resourceValues.fileSize ?? 0
|
|
||||||
}
|
|
||||||
|
|
||||||
for fileURL in fileURLs {
|
|
||||||
try? fileManager.removeItem(at: fileURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
promise(.success(totalFileSizeInBytes))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.eraseToAnyPublisher()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue