Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File provider extension #2980

Merged
merged 15 commits into from
Jul 13, 2024
2 changes: 1 addition & 1 deletion Brand/Database.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ import Foundation
// Database Realm
//
let databaseName = "nextcloud.realm"
let databaseSchemaVersion: UInt64 = 348
let databaseSchemaVersion: UInt64 = 349
4 changes: 3 additions & 1 deletion Brand/NCBrand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ class NCBrandColor: NSObject {

private func stepCalc(steps: Int, color1: CGColor, color2: CGColor) -> [CGFloat] {
var step = [CGFloat](repeating: 0, count: 3)

step[0] = (color2.components![0] - color1.components![0]) / CGFloat(steps)
step[1] = (color2.components![1] - color1.components![1]) / CGFloat(steps)
step[2] = (color2.components![2] - color1.components![2]) / CGFloat(steps)
Expand All @@ -266,8 +267,8 @@ class NCBrandColor: NSObject {
private func mixPalette(steps: Int, color1: CGColor, color2: CGColor) -> [CGColor] {
var palette = [color1]
let step = stepCalc(steps: steps, color1: color1, color2: color2)

let c1Components = color1.components!

for i in 1 ..< steps {
let r = c1Components[0] + step[0] * CGFloat(i)
let g = c1Components[1] + step[1] * CGFloat(i)
Expand All @@ -292,6 +293,7 @@ class NCBrandColor: NSObject {
let palette1 = mixPalette(steps: steps, color1: red, color2: yellow)
let palette2 = mixPalette(steps: steps, color1: yellow, color2: blue)
let palette3 = mixPalette(steps: steps, color1: blue, color2: red)

return palette1 + palette2 + palette3
}
}
23 changes: 13 additions & 10 deletions File Provider Extension/FileProviderData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,24 @@ class fileProviderData: NSObject {
var accountUrlBase = ""
var homeServerUrl = ""

// Rank favorite
var listFavoriteIdentifierRank: [String: NSNumber] = [:]

// Item for signalEnumerator
var fileProviderSignalDeleteContainerItemIdentifier: [NSFileProviderItemIdentifier: NSFileProviderItemIdentifier] = [:]
var fileProviderSignalUpdateContainerItem: [NSFileProviderItemIdentifier: FileProviderItem] = [:]
var fileProviderSignalDeleteWorkingSetItemIdentifier: [NSFileProviderItemIdentifier: NSFileProviderItemIdentifier] = [:]
var fileProviderSignalUpdateWorkingSetItem: [NSFileProviderItemIdentifier: FileProviderItem] = [:]

// Error
enum FileProviderError: Error {
case downloadError
case uploadError
}

enum TypeSignal: String {
case delete
case update
case workingSet
}

// MARK: -

func setupAccount(domain: NSFileProviderDomain?, providerExtension: NSFileProviderExtension) -> tableAccount? {
Expand Down Expand Up @@ -117,23 +120,23 @@ class fileProviderData: NSObject {
// MARK: -

@discardableResult
func signalEnumerator(ocId: String, delete: Bool = false, update: Bool = false) -> FileProviderItem? {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return nil }
guard let parentItemIdentifier = fileProviderUtility().getParentItemIdentifier(metadata: metadata) else { return nil }
func signalEnumerator(ocId: String, type: TypeSignal) -> FileProviderItem? {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId),
let parentItemIdentifier = fileProviderUtility().getParentItemIdentifier(metadata: metadata) else { return nil }
let item = FileProviderItem(metadata: metadata, parentItemIdentifier: parentItemIdentifier)

if delete {
if type == .delete {
fileProviderData.shared.fileProviderSignalDeleteContainerItemIdentifier[item.itemIdentifier] = item.itemIdentifier
fileProviderData.shared.fileProviderSignalDeleteWorkingSetItemIdentifier[item.itemIdentifier] = item.itemIdentifier
}
if update {
if type == .update {
fileProviderData.shared.fileProviderSignalUpdateContainerItem[item.itemIdentifier] = item
fileProviderData.shared.fileProviderSignalUpdateWorkingSetItem[item.itemIdentifier] = item
}
if !update && !delete {
if type == .workingSet {
fileProviderData.shared.fileProviderSignalUpdateWorkingSetItem[item.itemIdentifier] = item
}
if update || delete {
if type == .delete || type == .update {
fileProviderManager.signalEnumerator(for: parentItemIdentifier) { _ in }
}
fileProviderManager.signalEnumerator(for: .workingSet) { _ in }
Expand Down
6 changes: 3 additions & 3 deletions File Provider Extension/FileProviderEnumerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
return
}
var pageNumber = 1
if let stringPage = String(data: page.rawValue, encoding: .utf8),

Check warning on line 85 in File Provider Extension/FileProviderEnumerator.swift

View workflow job for this annotation

GitHub Actions / Lint

Non-Optional String <-> Data Conversion Violation: Prefer using UTF-8 encoded strings when converting between `String` and `Data` (non_optional_string_data_conversion)
let intPage = Int(stringPage) {
pageNumber = intPage
}
Expand All @@ -105,7 +105,7 @@
if let metadatas,
metadatas.count == self.recordsPerPage {
pageNumber += 1
let providerPage = NSFileProviderPage("\(pageNumber)".data(using: .utf8)!)

Check warning on line 108 in File Provider Extension/FileProviderEnumerator.swift

View workflow job for this annotation

GitHub Actions / Lint

Non-Optional String <-> Data Conversion Violation: Prefer using UTF-8 encoded strings when converting between `String` and `Data` (non_optional_string_data_conversion)
observer.finishEnumerating(upTo: providerPage)
} else {
observer.finishEnumerating(upTo: nil)
Expand Down Expand Up @@ -147,12 +147,12 @@
observer.didDeleteItems(withIdentifiers: itemsDelete)
observer.didUpdate(itemsUpdate)

let data = "\(self.anchor)".data(using: .utf8)

Check warning on line 150 in File Provider Extension/FileProviderEnumerator.swift

View workflow job for this annotation

GitHub Actions / Lint

Non-Optional String <-> Data Conversion Violation: Prefer using UTF-8 encoded strings when converting between `String` and `Data` (non_optional_string_data_conversion)
observer.finishEnumeratingChanges(upTo: NSFileProviderSyncAnchor(data!), moreComing: false)
}

func currentSyncAnchor(completionHandler: @escaping (NSFileProviderSyncAnchor?) -> Void) {
let data = "\(self.anchor)".data(using: .utf8)

Check warning on line 155 in File Provider Extension/FileProviderEnumerator.swift

View workflow job for this annotation

GitHub Actions / Lint

Non-Optional String <-> Data Conversion Violation: Prefer using UTF-8 encoded strings when converting between `String` and `Data` (non_optional_string_data_conversion)
completionHandler(NSFileProviderSyncAnchor(data!))
}

Expand All @@ -160,15 +160,15 @@
let predicate = NSPredicate(format: "account == %@ AND serverUrl == %@", fileProviderData.shared.account, serverUrl)

if pageNumber == 1 {
NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "1", showHiddenFiles: NCKeychain().showHiddenFiles) { account, files, _, error in
NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "1", showHiddenFiles: NCKeychain().showHiddenFiles) { _, files, _, error in
if error == .success {
NCManageDatabase.shared.convertFilesToMetadatas(files, useFirstAsMetadataFolder: true) { metadataFolder, metadatas in
/// FOLDER
NCManageDatabase.shared.addMetadata(metadataFolder)
NCManageDatabase.shared.addDirectory(e2eEncrypted: metadataFolder.e2eEncrypted, favorite: metadataFolder.favorite, ocId: metadataFolder.ocId, fileId: metadataFolder.fileId, etag: metadataFolder.etag, permissions: metadataFolder.permissions, richWorkspace: metadataFolder.richWorkspace, serverUrl: serverUrl, account: metadataFolder.account)
/// FILES
let updatePredicate = NSPredicate(format: "account == %@ AND serverUrl == %@ AND status == %d", account, serverUrl, NCGlobal.shared.metadataStatusNormal)
NCManageDatabase.shared.updateMetadatas(metadatas, predicate: updatePredicate)
NCManageDatabase.shared.deleteMetadata(predicate: predicate)
NCManageDatabase.shared.addMetadatas(metadatas)
}
}
let resultsMetadata = NCManageDatabase.shared.fetchPagedResults(ofType: tableMetadata.self, primaryKey: "ocId", recordsPerPage: self.recordsPerPage, pageNumber: pageNumber, filter: predicate, sortedByKeyPath: "fileName")
Expand Down
22 changes: 8 additions & 14 deletions File Provider Extension/FileProviderExtension+Actions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,9 @@ extension FileProviderExtension {
NCManageDatabase.shared.setDirectory(serverUrl: fileNamePathFrom, serverUrlTo: fileNamePathTo, encrypted: directoryTable.e2eEncrypted, account: account)
} else {
let itemIdentifier = self.providerUtility.getItemIdentifier(metadata: metadata)
// rename file
self.providerUtility.moveFile(self.utilityFileSystem.getDirectoryProviderStorageOcId(itemIdentifier.rawValue, fileNameView: fileNameFrom), toPath: self.utilityFileSystem.getDirectoryProviderStorageOcId(itemIdentifier.rawValue, fileNameView: itemName))

self.providerUtility.moveFile(self.utilityFileSystem.getDirectoryProviderStoragePreviewOcId(itemIdentifier.rawValue, etag: metadata.etag), toPath: self.utilityFileSystem.getDirectoryProviderStoragePreviewOcId(itemIdentifier.rawValue, etag: metadata.etag))

self.providerUtility.moveFile(self.utilityFileSystem.getDirectoryProviderStorageIconOcId(itemIdentifier.rawValue, etag: metadata.etag), toPath: self.utilityFileSystem.getDirectoryProviderStorageIconOcId(itemIdentifier.rawValue, etag: metadata.etag))

NCManageDatabase.shared.setLocalFile(ocId: ocId, fileName: itemName)
}

Expand All @@ -181,11 +177,10 @@ extension FileProviderExtension {
if favoriteRank == nil {
fileProviderData.shared.listFavoriteIdentifierRank.removeValue(forKey: itemIdentifier.rawValue)
} else {
if let rank = fileProviderData.shared.listFavoriteIdentifierRank[itemIdentifier.rawValue] {
favorite = true
} else {
if fileProviderData.shared.listFavoriteIdentifierRank[itemIdentifier.rawValue] == nil {
fileProviderData.shared.listFavoriteIdentifierRank[itemIdentifier.rawValue] = favoriteRank
}
favorite = true
}

if (favorite == true && metadata.favorite == false) || (favorite == false && metadata.favorite == true) {
Expand All @@ -198,17 +193,17 @@ extension FileProviderExtension {
// Change DB
metadata.favorite = favorite
NCManageDatabase.shared.addMetadata(metadata)

let item = fileProviderData.shared.signalEnumerator(ocId: metadata.ocId)
/// SIGNAL
let item = fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, type: .workingSet)
completionHandler(item, nil)
} else {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else {
return completionHandler(nil, NSFileProviderError(.noSuchItem))
}
// Errore, remove from listFavoriteIdentifierRank
fileProviderData.shared.listFavoriteIdentifierRank.removeValue(forKey: itemIdentifier.rawValue)

let item = fileProviderData.shared.signalEnumerator(ocId: metadata.ocId)
/// SIGNAL
let item = fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, type: .workingSet)
completionHandler(item, NSFileProviderError(.serverUnreachable))
}
}
Expand All @@ -222,10 +217,9 @@ extension FileProviderExtension {
let ocId = metadataForTag.ocId
let account = metadataForTag.account

// Add, Remove (nil)
NCManageDatabase.shared.addTag(ocId, tagIOS: tagData, account: account)

let item = fileProviderData.shared.signalEnumerator(ocId: ocId)
/// SIGNAL WORKINGSET
let item = fileProviderData.shared.signalEnumerator(ocId: ocId, type: .workingSet)
completionHandler(item, nil)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,15 @@ extension FileProviderExtension: NCNetworkingDelegate {
func uploadComplete(fileName: String, serverUrl: String, ocId: String?, etag: String?, date: Date?, size: Int64, task: URLSessionTask, error: NKError) {
guard let url = task.currentRequest?.url,
let metadata = NCManageDatabase.shared.getMetadata(from: url, sessionTaskIdentifier: task.taskIdentifier) else { return }
let ocIdTemp = metadata.ocId

if error == .success, let ocId, size == metadata.size {
/// SIGNAL DELETE
fileProviderData.shared.signalEnumerator(ocId: ocIdTemp, delete: true)
if error == .success, let ocId {
/// SIGNAL
fileProviderData.shared.signalEnumerator(ocId: metadata.ocIdTemp, type: .delete)
metadata.fileName = fileName
metadata.serverUrl = serverUrl
metadata.uploadDate = (date as? NSDate) ?? NSDate()
metadata.etag = etag ?? ""
metadata.ocId = ocId
metadata.size = size
if let fileId = NCUtility().ocIdToFileId(ocId: ocId) {
metadata.fileId = fileId
}
Expand All @@ -55,17 +54,19 @@ extension FileProviderExtension: NCNetworkingDelegate {

NCManageDatabase.shared.addMetadata(metadata)
NCManageDatabase.shared.addLocalFile(metadata: metadata)
NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp))

// File system
let atPath = utilityFileSystem.getDirectoryProviderStorageOcId(ocIdTemp)
let toPath = utilityFileSystem.getDirectoryProviderStorageOcId(ocId)
utilityFileSystem.copyFile(atPath: atPath, toPath: toPath)
/// SIGNAL UPDATE
fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, update: true)
/// NEW File
if ocId != metadata.ocIdTemp {
let atPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocIdTemp)
let toPath = utilityFileSystem.getDirectoryProviderStorageOcId(ocId)
utilityFileSystem.copyFile(atPath: atPath, toPath: toPath)
NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocIdTemp))
}
/// SIGNAL
fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, type: .update)
} else {
NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp))
fileProviderData.shared.signalEnumerator(ocId: ocIdTemp, delete: true)
NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocIdTemp))
/// SIGNAL
fileProviderData.shared.signalEnumerator(ocId: metadata.ocIdTemp, type: .delete)
}
}
}
77 changes: 34 additions & 43 deletions File Provider Extension/FileProviderExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -166,22 +166,28 @@ class FileProviderExtension: NSFileProviderExtension {
override func startProvidingItem(at url: URL, completionHandler: @escaping ((_ error: Error?) -> Void)) {
let pathComponents = url.pathComponents
let itemIdentifier = NSFileProviderItemIdentifier(pathComponents[pathComponents.count - 2])
guard let metadata = providerUtility.getTableMetadataFromItemIdentifier(itemIdentifier),
metadata.status == NCGlobal.shared.metadataStatusNormal else {
guard let metadata = providerUtility.getTableMetadataFromItemIdentifier(itemIdentifier) else {
return completionHandler(NSFileProviderError(.noSuchItem))
}
if metadata.session == NCNetworking.shared.sessionUploadBackgroundExtension {
return completionHandler(nil)
}
let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName
let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileName)
// Exists ? return
if let tableLocalFile = NCManageDatabase.shared.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)),
utilityFileSystem.fileProviderStorageExists(metadata),
tableLocalFile.etag == metadata.etag {
return completionHandler(nil)
} else {
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
session: NextcloudKit.shared.nkCommonInstance.sessionIdentifierDownload,
sessionError: "",
selector: "",
status: NCGlobal.shared.metadataStatusDownloading)
}
// Update status
NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId,
status: NCGlobal.shared.metadataStatusDownloading)
fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, update: true)
/// SIGNAL
fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, type: .update)

NextcloudKit.shared.download(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, requestHandler: { _ in
}, taskHandler: { task in
Expand Down Expand Up @@ -209,31 +215,26 @@ class FileProviderExtension: NSFileProviderExtension {
NCManageDatabase.shared.addMetadata(metadata)
completionHandler(NSFileProviderError(.noSuchItem))
}
fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, update: true)
/// SIGNAL
fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, type: .update)
}
}

/// Upload the changed file
override func itemChanged(at url: URL) {
let pathComponents = url.pathComponents
assert(pathComponents.count > 2)
let itemIdentifier = NSFileProviderItemIdentifier(pathComponents[pathComponents.count - 2])
let fileName = pathComponents[pathComponents.count - 1]
let ocId = itemIdentifier.rawValue

/*
if outstandingOcIdTemp[ocId] != nil && outstandingOcIdTemp[ocId] != ocId {
ocId = outstandingOcIdTemp[ocId]!
let atPath = utilityFileSystem.getDirectoryProviderStorageOcId(itemIdentifier.rawValue, fileNameView: fileName)
let toPath = utilityFileSystem.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)
utilityFileSystem.copyFile(atPath: atPath, toPath: toPath)
}
*/

guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return }

guard let metadata = NCManageDatabase.shared.getMetadataFromOcIdAndOcIdTemp(itemIdentifier.rawValue) else { return }
let serverUrlFileName = metadata.serverUrl + "/" + fileName
let fileNameLocalPath = url.path

let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: fileName)
utilityFileSystem.copyFile(atPath: url.path, toPath: fileNameLocalPath)
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
session: NCNetworking.shared.sessionUploadBackgroundExtension,
sessionError: "",
selector: "",
status: NCGlobal.shared.metadataStatusUploading)
if let task = NKBackground(nkCommonInstance: NextcloudKit.shared.nkCommonInstance).upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: nil, dateModificationFile: nil, session: NCNetworking.shared.sessionManagerUploadBackgroundExtension) {
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
status: NCGlobal.shared.metadataStatusUploading,
Expand All @@ -243,29 +244,19 @@ class FileProviderExtension: NSFileProviderExtension {
}

override func stopProvidingItem(at url: URL) {
let fileHasLocalChanges = false

if !fileHasLocalChanges {
// remove the existing file to free up space
do {
try providerUtility.fileManager.removeItem(at: url)
} catch let error {
print("error: \(error)")
let pathComponents = url.pathComponents
assert(pathComponents.count > 2)
let itemIdentifier = NSFileProviderItemIdentifier(pathComponents[pathComponents.count - 2])
guard let metadata = NCManageDatabase.shared.getMetadataFromOcIdAndOcIdTemp(itemIdentifier.rawValue) else { return }
if metadata.session == NextcloudKit.shared.nkCommonInstance.sessionIdentifierDownload {
NextcloudKit.shared.sessionManager.session.getTasksWithCompletionHandler { _, _, downloadTasks in
downloadTasks.forEach { task in
if metadata.sessionTaskIdentifier == task.taskIdentifier {
task.cancel()
}
}
}

// write out a placeholder to facilitate future property lookups
self.providePlaceholder(at: url, completionHandler: { _ in
// handle any error, do any necessary cleanup
})
}

/*
// Download task
if let downloadTask = outstandingSessionTasks[url] {
downloadTask.cancel()
outstandingSessionTasks.removeValue(forKey: url)
}
*/
}

override func importDocument(at fileURL: URL, toParentItemIdentifier parentItemIdentifier: NSFileProviderItemIdentifier, completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) {
Expand Down
Loading
Loading