mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Merge pull request #1844 from sixten/clear-local-files
Clear local files when reseting local storage
This commit is contained in:
commit
ad5b6eac85
10 changed files with 107 additions and 29 deletions
|
|
@ -6,8 +6,6 @@ import Utils
|
|||
import Views
|
||||
|
||||
@MainActor final class HomeFeedViewModel: NSObject, ObservableObject {
|
||||
let dateFormatter = DateFormatter.formatterISO8601
|
||||
|
||||
var currentDetailViewModel: LinkItemDetailViewModel?
|
||||
|
||||
private var fetchedResultsController: NSFetchedResultsController<LinkedItem>?
|
||||
|
|
@ -110,7 +108,7 @@ import Views
|
|||
|
||||
func syncItems(dataService: DataService) async {
|
||||
let syncStart = Date.now
|
||||
let lastSyncDate = dateFormatter.date(from: dataService.lastItemSyncTime) ?? Date(timeIntervalSinceReferenceDate: 0)
|
||||
let lastSyncDate = dataService.lastItemSyncTime
|
||||
|
||||
try? await dataService.syncOfflineItemsWithServerIfNeeded()
|
||||
|
||||
|
|
@ -124,7 +122,7 @@ import Views
|
|||
self.isLoading = false
|
||||
}
|
||||
} else {
|
||||
dataService.lastItemSyncTime = DateFormatter.formatterISO8601.string(from: syncStart)
|
||||
dataService.lastItemSyncTime = syncStart
|
||||
}
|
||||
|
||||
// If possible start prefetching new pages in the background
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ struct ManageAccountView: View {
|
|||
)
|
||||
Button(
|
||||
action: {
|
||||
dataService.resetCoreData()
|
||||
dataService.resetLocalStorage()
|
||||
},
|
||||
label: { Text(LocalText.manageAccountResetCache) }
|
||||
)
|
||||
|
|
|
|||
|
|
@ -543,8 +543,7 @@
|
|||
}
|
||||
|
||||
public static func pathForAudioDirectory(itemID: String) -> URL {
|
||||
FileManager.default
|
||||
.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
URL.om_documentsDirectory
|
||||
.appendingPathComponent("audio-\(itemID)/")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,8 +56,7 @@ struct SpeechDocument: Decodable {
|
|||
}
|
||||
|
||||
static func audioDirectory(pageId: String) -> URL {
|
||||
FileManager.default
|
||||
.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
URL.om_documentsDirectory
|
||||
.appendingPathComponent("audio-\(pageId)")
|
||||
}
|
||||
}
|
||||
|
|
@ -213,12 +212,10 @@ struct SpeechSynthesizer {
|
|||
|
||||
let data = try await downloadData(session: session, request: speechItem.urlRequest)
|
||||
|
||||
let tempPath = FileManager.default
|
||||
.urls(for: .cachesDirectory, in: .userDomainMask)[0]
|
||||
let tempPath = URL.om_cachesDirectory
|
||||
.appendingPathComponent(UUID().uuidString + ".mp3")
|
||||
|
||||
let tempSMPath = FileManager.default
|
||||
.urls(for: .cachesDirectory, in: .userDomainMask)[0]
|
||||
let tempSMPath = URL.om_cachesDirectory
|
||||
.appendingPathComponent(UUID().uuidString + ".speechMarks")
|
||||
|
||||
do {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public final class Authenticator: ObservableObject {
|
|||
}
|
||||
|
||||
public func logout(dataService: DataService, isAccountDeletion: Bool = false) {
|
||||
dataService.resetCoreData()
|
||||
dataService.resetLocalStorage()
|
||||
clearCreds()
|
||||
Authenticator.unregisterIntercomUser?()
|
||||
isLoggedIn = false
|
||||
|
|
|
|||
|
|
@ -29,9 +29,22 @@ public final class DataService: ObservableObject {
|
|||
persistentContainer.viewContext
|
||||
}
|
||||
|
||||
@AppStorage(UserDefaultKey.lastItemSyncTime.rawValue) public var lastItemSyncTime: String = {
|
||||
DateFormatter.formatterISO8601.string(from: Date(timeIntervalSinceReferenceDate: 0))
|
||||
}()
|
||||
public var lastItemSyncTime: Date {
|
||||
get {
|
||||
guard
|
||||
let str = UserDefaults.standard.string(forKey: UserDefaultKey.lastItemSyncTime.rawValue),
|
||||
let date = DateFormatter.formatterISO8601.date(from: str)
|
||||
else {
|
||||
return Date(timeIntervalSinceReferenceDate: 0)
|
||||
}
|
||||
return date
|
||||
}
|
||||
set {
|
||||
logger.trace("last item sync updated to \(newValue)")
|
||||
let str = DateFormatter.formatterISO8601.string(from: newValue)
|
||||
UserDefaults.standard.set(str, forKey: UserDefaultKey.lastItemSyncTime.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
public init(appEnvironment: AppEnvironment, networker: Networker) {
|
||||
self.appEnvironment = appEnvironment
|
||||
|
|
@ -43,7 +56,7 @@ public final class DataService: ObservableObject {
|
|||
backgroundContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
||||
|
||||
if isFirstTimeRunningNewAppBuild() {
|
||||
resetCoreData()
|
||||
resetLocalStorage()
|
||||
} else {
|
||||
persistentContainer.loadPersistentStores { _, error in
|
||||
if let error = error {
|
||||
|
|
@ -102,10 +115,58 @@ public final class DataService: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
public func resetCoreData() {
|
||||
lastItemSyncTime = DateFormatter.formatterISO8601.string(from: Date(timeIntervalSinceReferenceDate: 0))
|
||||
private func clearDownloadedFiles() {
|
||||
let relevantTypes = ["pdf", "mp3", "speechMarks"]
|
||||
let fileMgr = FileManager()
|
||||
logger.trace("removing cached downloads")
|
||||
|
||||
// clear the temporary files in the caches directory…
|
||||
if let cacheFileURLs = try? fileMgr.contentsOfDirectory(
|
||||
at: URL.om_cachesDirectory,
|
||||
includingPropertiesForKeys: .none,
|
||||
options: .skipsHiddenFiles
|
||||
) {
|
||||
logger.trace("\(cacheFileURLs.count) file URLs in caches directory")
|
||||
for fileURL in cacheFileURLs where relevantTypes.contains(fileURL.pathExtension) {
|
||||
logger.trace("removing \(fileURL.absoluteString)")
|
||||
try? fileMgr.removeItem(at: fileURL)
|
||||
}
|
||||
}
|
||||
|
||||
// …and also the copies written to Documents
|
||||
let resourceKeys = Set<URLResourceKey>([.nameKey, .isDirectoryKey])
|
||||
if let documentsFileURLs = try? fileMgr.contentsOfDirectory(
|
||||
at: URL.om_documentsDirectory,
|
||||
includingPropertiesForKeys: Array(resourceKeys),
|
||||
options: .skipsHiddenFiles
|
||||
) {
|
||||
logger.trace("\(documentsFileURLs.count) file URLs in documents directory")
|
||||
for fileURL in documentsFileURLs {
|
||||
guard
|
||||
let resourceValues = try? fileURL.resourceValues(forKeys: resourceKeys),
|
||||
let isDirectory = resourceValues.isDirectory,
|
||||
let name = resourceValues.name
|
||||
else {
|
||||
continue
|
||||
}
|
||||
if isDirectory {
|
||||
if name.hasPrefix("audio-") {
|
||||
logger.trace("removing \(fileURL.absoluteString)")
|
||||
try? fileMgr.removeItem(at: fileURL)
|
||||
}
|
||||
} else if relevantTypes.contains(fileURL.pathExtension) {
|
||||
logger.trace("removing \(fileURL.absoluteString)")
|
||||
try? fileMgr.removeItem(at: fileURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func resetLocalStorage() {
|
||||
lastItemSyncTime = Date(timeIntervalSinceReferenceDate: 0)
|
||||
|
||||
clearCoreData()
|
||||
clearDownloadedFiles()
|
||||
|
||||
persistentContainer = PersistentContainer.make()
|
||||
persistentContainer.loadPersistentStores { _, error in
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public extension DataService {
|
|||
}
|
||||
}
|
||||
DispatchQueue.main.sync {
|
||||
self.lastItemSyncTime = DateFormatter.formatterISO8601.string(from: Date.now)
|
||||
self.lastItemSyncTime = Date.now
|
||||
onComplete()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@ public extension DataService {
|
|||
|
||||
var localPdfURL: URL?
|
||||
|
||||
let tempPath = FileManager.default
|
||||
.urls(for: .cachesDirectory, in: .userDomainMask)[0]
|
||||
let tempPath = URL.om_cachesDirectory
|
||||
.appendingPathComponent(UUID().uuidString + ".pdf")
|
||||
|
||||
try await backgroundContext.perform { [weak self] in
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ import QuickLookThumbnailing
|
|||
public enum PDFUtils {
|
||||
public static func copyToLocal(url: URL) throws -> String {
|
||||
let subPath = UUID().uuidString + ".pdf"
|
||||
let dest = FileManager.default
|
||||
.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
let dest = URL.om_documentsDirectory
|
||||
.appendingPathComponent(subPath)
|
||||
|
||||
try FileManager.default.copyItem(at: url, to: dest)
|
||||
|
|
@ -20,8 +19,7 @@ public enum PDFUtils {
|
|||
|
||||
public static func moveToLocal(url: URL) throws -> String {
|
||||
let subPath = UUID().uuidString + ".pdf"
|
||||
let dest = FileManager.default
|
||||
.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
let dest = URL.om_documentsDirectory
|
||||
.appendingPathComponent(subPath)
|
||||
|
||||
try FileManager.default.moveItem(at: url, to: dest)
|
||||
|
|
@ -29,8 +27,7 @@ public enum PDFUtils {
|
|||
}
|
||||
|
||||
public static func localPdfURL(filename: String) -> URL? {
|
||||
let url = FileManager.default
|
||||
.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
let url = URL.om_documentsDirectory
|
||||
.appendingPathComponent(filename)
|
||||
|
||||
return url
|
||||
|
|
|
|||
27
apple/OmnivoreKit/Sources/Utils/URLExtension.swift
Normal file
27
apple/OmnivoreKit/Sources/Utils/URLExtension.swift
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import Foundation
|
||||
|
||||
public extension URL {
|
||||
// swiftlint:disable:next identifier_name
|
||||
static var om_documentsDirectory: URL {
|
||||
if #unavailable(iOS 16, tvOS 16, macOS 13) {
|
||||
guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||
fatalError("Could not determine the user's documents directory")
|
||||
}
|
||||
return url
|
||||
} else {
|
||||
return URL.documentsDirectory
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable:next identifier_name
|
||||
static var om_cachesDirectory: URL {
|
||||
if #unavailable(iOS 16, tvOS 16, macOS 13) {
|
||||
guard let url = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
|
||||
fatalError("Could not determine the user's caches directory")
|
||||
}
|
||||
return url
|
||||
} else {
|
||||
return URL.cachesDirectory
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue