application iOS de notes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
notes/Notes/Storage/FileStorage.swift

105 lines
3.5 KiB

//
// CloudFileStorage.swift
// Notes
//
// Created by Laurent Morvillier on 16/09/2022.
//
import Foundation
import UIKit
struct StorageRequest {
var filename: String
var content: String
}
let idleTimeBeforeSaving = 2.0
/// Should we have a way to go from local to iCloud?
/// https://stackoverflow.com/questions/33886846/best-way-to-use-icloud-documents-storage
/// Should we store the files locally whatever the iCloud choice is?
class FileStorage : FileOperator {
static var main: FileStorage = FileStorage()
fileprivate var _containerURL: URL?
fileprivate var _cloudStorageDetermined: Bool = false
fileprivate let containerIdentifier = "notes"
fileprivate var _timer: Timer? = nil
fileprivate var _storageRequests: [String : String] = [:]
init() {
DispatchQueue.global(qos: .userInteractive).async {
self._containerURL = FileManager.default.url(forUbiquityContainerIdentifier: self.containerIdentifier)
self._cloudStorageDetermined = true
print("Cloud container URL is : \(String(describing: self._containerURL?.absoluteString))")
}
}
fileprivate func _directoryURL() throws -> URL {
let documentDirectory = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
return documentDirectory
}
// MARK: - FileOperator
func requestStorage(filename: String, content: String) {
self._storageRequests[filename] = content
self._timer?.invalidate()
self._timer = Timer.scheduledTimer(timeInterval: idleTimeBeforeSaving, target: self, selector: #selector(self._storageRequested), userInfo: nil, repeats: false)
}
@objc fileprivate func _storageRequested() {
for (filename, content) in self._storageRequests {
do {
try self._store(filename: filename, content: content)
} catch {
// TODO show errors to users, possibly by notifications
print("error: \(error.localizedDescription)")
}
}
self._storageRequests.removeAll()
}
fileprivate func _store(filename: String, content: String) throws {
let fileURL = try self._directoryURL().appending(path: filename)
print("Store file to: \(fileURL.absoluteString)")
try content.write(to: fileURL, atomically: true, encoding: .utf8)
try self._copyToCloudContainerIfNecessary(fileURL: fileURL, filename: filename)
}
func getContent(filename: String) throws -> String? {
let fileURL = try self._directoryURL().appending(path: filename)
return try String(contentsOf: fileURL)
}
func lastEditDate(filename: String) throws -> Date? {
let fileURL = try self._directoryURL().appending(path: filename)
let attributes = try FileManager.default.attributesOfItem(atPath: fileURL.absoluteString)
return attributes[FileAttributeKey.modificationDate] as? Date
}
fileprivate func _copyToCloudContainerIfNecessary(fileURL: URL, filename: String) throws {
guard let containerURL = self._containerURL else {
return
}
let cloudURL = containerURL.appending(path: filename)
try FileManager.default.copyItem(at: fileURL, to: cloudURL)
print("cloud copy to: \(cloudURL)")
}
deinit {
self._timer?.invalidate()
}
}