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

Offline rename #3086

Merged
merged 24 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 = 359
let databaseSchemaVersion: UInt64 = 360
3 changes: 2 additions & 1 deletion File Provider Extension/FileProviderExtension+Actions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ extension FileProviderExtension {
NextcloudKit.shared.moveFileOrFolder(serverUrlFileNameSource: fileNamePathFrom, serverUrlFileNameDestination: fileNamePathTo, overwrite: false, account: metadata.account) { account, error in
if error == .success {
// Rename metadata
self.database.renameMetadata(fileNameTo: itemName, ocId: ocId, account: account)
self.database.renameMetadata(fileNameNew: itemName, ocId: ocId)
self.database.setMetadataServeUrlFileNameStatusNormal(ocId: ocId)

guard let metadata = self.database.getMetadataFromOcId(ocId) else {
return completionHandler(nil, NSFileProviderError(.noSuchItem))
Expand Down
111 changes: 103 additions & 8 deletions iOSClient/Data/NCManageDatabase+Metadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
@objc dynamic var richWorkspace: String?
@objc dynamic var sceneIdentifier: String?
@objc dynamic var serverUrl = ""
@objc dynamic var serveUrlFileName = ""
@objc dynamic var session = ""
@objc dynamic var sessionDate: Date?
@objc dynamic var sessionError = ""
Expand Down Expand Up @@ -293,7 +294,7 @@
}

var isAvailableRichDocumentEditorView: Bool {
guard (classFile == NKCommon.TypeClassFile.document.rawValue),

Check warning on line 297 in iOSClient/Data/NCManageDatabase+Metadata.swift

View workflow job for this annotation

GitHub Actions / Lint

Control Statement Violation: `if`, `for`, `guard`, `switch`, `while`, and `catch` statements shouldn't unnecessarily wrap their conditionals or arguments in parentheses (control_statement)
NCCapabilities.shared.getCapabilities(account: account).capabilityRichDocumentsEnabled,
NextcloudKit.shared.isNetworkReachable() else { return false }

Expand Down Expand Up @@ -392,6 +393,7 @@
metadata.richWorkspace = file.richWorkspace
metadata.resourceType = file.resourceType
metadata.serverUrl = file.serverUrl
metadata.serveUrlFileName = file.serverUrl + "/" + file.fileName

Check warning on line 396 in iOSClient/Data/NCManageDatabase+Metadata.swift

View workflow job for this annotation

GitHub Actions / Lint

Operator Usage Whitespace Violation: Operators should be surrounded by a single whitespace when they are being used (operator_usage_whitespace)
metadata.sharePermissionsCollaborationServices = file.sharePermissionsCollaborationServices
for element in file.sharePermissionsCloudMesh {
metadata.sharePermissionsCloudMesh.append(element)
Expand Down Expand Up @@ -514,6 +516,7 @@
metadata.ocIdTransfer = ocId
metadata.permissions = "RGDNVW"
metadata.serverUrl = serverUrl
metadata.serveUrlFileName = serverUrl + "/" + fileName
metadata.subline = subline
metadata.uploadDate = Date() as NSDate
metadata.url = url
Expand Down Expand Up @@ -552,18 +555,16 @@

@discardableResult
func addMetadata(_ metadata: tableMetadata) -> tableMetadata? {
let result = tableMetadata(value: metadata)

do {
let realm = try Realm()
try realm.write {
realm.add(result, update: .all)
realm.add(tableMetadata(value: metadata), update: .all)
}
} catch let error {
NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not write to database: \(error)")
return nil
}
return result
return tableMetadata(value: metadata)
}

func addMetadatas(_ metadatas: [tableMetadata]) {
Expand Down Expand Up @@ -614,17 +615,111 @@
}
}

func renameMetadata(fileNameTo: String, ocId: String, account: String) {
func renameMetadata(fileNameNew: String, ocId: String, status: Int = NCGlobal.shared.metadataStatusNormal) {
do {
let realm = try Realm()
try realm.write {
if let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first {
let resultsType = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: fileNameTo, mimeType: "", directory: result.directory, account: account)
result.fileName = fileNameTo
result.fileNameView = fileNameTo
let fileNameView = result.fileNameView
let fileIdMOV = result.livePhotoFile
let directoryServerUrl = self.utilityFileSystem.stringAppendServerUrl(result.serverUrl, addFileName: fileNameView)
let resultsType = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: fileNameNew, mimeType: "", directory: result.directory, account: result.account)

result.fileName = fileNameNew
result.fileNameView = fileNameNew
result.iconName = resultsType.iconName
result.contentType = resultsType.mimeType
result.classFile = resultsType.classFile
result.status = status

if result.directory,
let resultDirectory = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", result.account, directoryServerUrl).first {
let serverUrlTo = self.utilityFileSystem.stringAppendServerUrl(result.serverUrl, addFileName: fileNameNew)

resultDirectory.serverUrl = serverUrlTo
} else {
let atPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(result.ocId) + "/" + fileNameView
let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(result.ocId) + "/" + fileNameNew

self.utilityFileSystem.moveFile(atPath: atPath, toPath: toPath)
}

if result.isLivePhoto,
let resultMOV = realm.objects(tableMetadata.self).filter("fileId == %@ AND account == %@", fileIdMOV, result.account).first {
let fileNameView = resultMOV.fileNameView
let fileName = (fileNameNew as NSString).deletingPathExtension
let ext = (resultMOV.fileName as NSString).pathExtension
resultMOV.fileName = fileName + "." + ext
resultMOV.fileNameView = fileName + "." + ext

let atPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(resultMOV.ocId) + "/" + fileNameView
let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(resultMOV.ocId) + "/" + fileName + "." + ext

self.utilityFileSystem.moveFile(atPath: atPath, toPath: toPath)
}
}
}
} catch let error {
NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not write to database: \(error)")
}
}

func restoreMetadataFileName(ocId: String) {
do {
let realm = try Realm()
try realm.write {
if let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first,
let encodedURLString = result.serveUrlFileName.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: encodedURLString) {
let fileIdMOV = result.livePhotoFile
let directoryServerUrl = self.utilityFileSystem.stringAppendServerUrl(result.serverUrl, addFileName: result.fileNameView)
let lastPathComponent = url.lastPathComponent
let fileName = lastPathComponent.removingPercentEncoding ?? lastPathComponent
let fileNameView = result.fileNameView

result.fileName = fileName
result.fileNameView = fileName
result.status = NCGlobal.shared.metadataStatusNormal

if result.directory,
let resultDirectory = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", result.account, directoryServerUrl).first {
let serverUrlTo = self.utilityFileSystem.stringAppendServerUrl(result.serverUrl, addFileName: fileName)

resultDirectory.serverUrl = serverUrlTo
} else {
let atPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(result.ocId) + "/" + fileNameView
let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(result.ocId) + "/" + fileName

self.utilityFileSystem.moveFile(atPath: atPath, toPath: toPath)
}

if result.isLivePhoto,
let resultMOV = realm.objects(tableMetadata.self).filter("fileId == %@ AND account == %@", fileIdMOV, result.account).first {
let fileNameView = resultMOV.fileNameView
let fileName = (fileName as NSString).deletingPathExtension
let ext = (resultMOV.fileName as NSString).pathExtension
resultMOV.fileName = fileName + "." + ext
resultMOV.fileNameView = fileName + "." + ext

let atPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(resultMOV.ocId) + "/" + fileNameView
let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(resultMOV.ocId) + "/" + fileName + "." + ext

self.utilityFileSystem.moveFile(atPath: atPath, toPath: toPath)
}
}
}
} catch let error {
NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not write to database: \(error)")
}
}

func setMetadataServeUrlFileNameStatusNormal(ocId: String) {
do {
let realm = try Realm()
try realm.write {
if let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first {
result.serveUrlFileName = self.utilityFileSystem.stringAppendServerUrl(result.serverUrl, addFileName: result.fileName)
result.status = NCGlobal.shared.metadataStatusNormal
}
}
} catch let error {
Expand Down
12 changes: 6 additions & 6 deletions iOSClient/Data/NCManageDatabase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class NCManageDatabase: NSObject {

override init() {
func migrationSchema(_ migration: Migration, _ oldSchemaVersion: UInt64) {
if oldSchemaVersion < 359 {
if oldSchemaVersion < 360 {
migration.deleteData(forType: tableMetadata.className())
migration.enumerateObjects(ofType: tableDirectory.className()) { _, newObject in
newObject?["etag"] = ""
Expand All @@ -51,11 +51,11 @@ class NCManageDatabase: NSObject {
}

func compactDB(_ totalBytes: Int, _ usedBytes: Int) -> Bool {
// totalBytes refers to the size of the file on disk in bytes (data + free space)
// usedBytes refers to the number of bytes used by data in the file
// Compact if the file is over 100MB in size and less than 50% 'used'
let oneHundredMB = 100 * 1024 * 1024
return (totalBytes > oneHundredMB) && (Double(usedBytes) / Double(totalBytes)) < 0.5
let usedPercentage = (Double(usedBytes) / Double(totalBytes)) * 100
/// Compact the database if more than 25% of the space is free
let shouldCompact = (usedPercentage < 75.0) && (totalBytes > 100 * 1024 * 1024)

return shouldCompact
}
var realm: Realm?
let dirGroup = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroup)
Expand Down
34 changes: 19 additions & 15 deletions iOSClient/Extensions/UIAlertController+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,14 @@ extension UIAlertController {
static func createFolder(serverUrl: String, account: String, markE2ee: Bool = false, sceneIdentifier: String? = nil, completion: ((_ error: NKError) -> Void)? = nil) -> UIAlertController {
let alertController = UIAlertController(title: NSLocalizedString("_create_folder_", comment: ""), message: nil, preferredStyle: .alert)
let session = NCSession.shared.getSession(account: account)
let isDirectoryEncrypted = NCUtilityFileSystem().isDirectoryE2EE(session: session, serverUrl: serverUrl)

let okAction = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default, handler: { _ in
guard let fileNameFolder = alertController.textFields?.first?.text else { return }
if markE2ee {
if NCNetworking.shared.isOffline {
return NCContentPresenter().showInfo(error: NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_offline_not_allowed_"))
}
Task {
let createFolderResults = await NCNetworking.shared.createFolder(serverUrlFileName: serverUrl + "/" + fileNameFolder, account: session.account)
if createFolderResults.error == .success {
Expand All @@ -50,6 +54,15 @@ extension UIAlertController {
NCContentPresenter().showError(error: createFolderResults.error)
}
}
} else if isDirectoryEncrypted {
if NCNetworking.shared.isOffline {
return NCContentPresenter().showInfo(error: NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_offline_not_allowed_"))
}
#if !EXTENSION
Task {
await NCNetworkingE2EECreateFolder().createFolder(fileName: fileNameFolder, serverUrl: serverUrl, withPush: true, sceneIdentifier: sceneIdentifier, session: session)
}
#endif
} else {
let metadataForCreateFolder = NCManageDatabase.shared.createMetadata(fileName: fileNameFolder,
fileNameView: fileNameFolder,
Expand Down Expand Up @@ -122,9 +135,7 @@ extension UIAlertController {
preferredStyle: .alert)
if canDeleteServer {
alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .destructive) { (_: UIAlertAction) in
for metadata in selectedMetadatas {
NCNetworking.shared.deleteMetadata(metadata)
}
NCNetworking.shared.deleteMetadatas(selectedMetadatas, sceneIdentifier: sceneIdentifier)
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource)
completion(false)
})
Expand Down Expand Up @@ -202,32 +213,25 @@ extension UIAlertController {
let alertController = UIAlertController(title: NSLocalizedString("_rename_", comment: ""), message: nil, preferredStyle: .alert)

let okAction = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default, handler: { _ in
guard let newFileName = alertController.textFields?.first?.text else { return }
guard let fileNameNew = alertController.textFields?.first?.text else { return }

// verify if already exists
if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@", metadata.account, metadata.serverUrl, newFileName)) != nil {
if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@", metadata.account, metadata.serverUrl, fileNameNew)) != nil {
NCContentPresenter().showError(error: NKError(errorCode: 0, errorDescription: "_rename_already_exists_"))
return
}

NCActivityIndicator.shared.start()

NCNetworking.shared.renameMetadata(metadata, fileNameNew: newFileName) { error in

NCActivityIndicator.shared.stop()
NCNetworking.shared.renameMetadata(metadata, fileNameNew: fileNameNew)

if error != .success {
NCContentPresenter().showError(error: error)
}
}
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl": metadata.serverUrl])
})

// text field is initially empty, no action
okAction.isEnabled = false
let cancelAction = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel)

alertController.addTextField { textField in
textField.text = metadata.fileName
textField.text = metadata.fileNameView
textField.autocapitalizationType = .words
}

Expand Down
2 changes: 2 additions & 0 deletions iOSClient/Files/NCFiles.swift
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ class NCFiles: NCCollectionViewCommon {
} else if self.dataSource.isEmpty() {
self.collectionView.reloadData()
}
} else if self.dataSource.isEmpty() {
self.collectionView.reloadData()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,8 @@ extension NCCollectionViewCommon: NCCollectionViewCommonSelectTabBarDelegate {
let canDeleteServer = metadatas.allSatisfy { !$0.lock }

if canDeleteServer {
let copyMetadatas = metadatas
alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .destructive) { _ in
for metadata in copyMetadatas {
NCNetworking.shared.deleteMetadata(metadata)
}
NCNetworking.shared.deleteMetadatas(metadatas, sceneIdentifier: self.controller?.sceneIdentifier)
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource)
self.setEditMode(false)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,9 +415,16 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
@objc func renameFile(_ notification: NSNotification) {
guard let userInfo = notification.userInfo as NSDictionary?,
let account = userInfo["account"] as? String,
account == session.account
let serverUrl = userInfo["serverUrl"] as? String,
let error = userInfo["error"] as? NKError,
account == session.account,
serverUrl == self.serverUrl
else { return }

if error != .success {
NCContentPresenter().showError(error: error)
}

reloadDataSource()
}

Expand Down
5 changes: 4 additions & 1 deletion iOSClient/Media/NCMedia+Command.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ extension NCMedia: NCMediaSelectTabBarDelegate {
let ocIds = self.fileSelect.map { $0 }
var alertStyle = UIAlertController.Style.actionSheet
var indexPaths: [IndexPath] = []
var metadatas: [tableMetadata] = []

if UIDevice.current.userInterfaceIdiom == .pad { alertStyle = .alert }

Expand All @@ -203,10 +204,12 @@ extension NCMedia: NCMediaSelectTabBarDelegate {

for ocId in ocIds {
if let metadata = self.database.getMetadataFromOcId(ocId) {
NCNetworking.shared.deleteMetadata(metadata)
metadatas.append(metadata)
}
}

NCNetworking.shared.deleteMetadatas(metadatas, sceneIdentifier: self.controller?.sceneIdentifier)

for index in indices {
let indexPath = IndexPath(row: index, section: 0)
if let cell = self.collectionView.cellForItem(at: indexPath) as? NCMediaCell,
Expand Down
3 changes: 1 addition & 2 deletions iOSClient/Menu/NCCollectionViewCommon+Menu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,7 @@ extension NCCollectionViewCommon {
//
// RENAME
//
if NCNetworking.shared.isOnline,
metadata.isRenameable {
if metadata.isRenameable {
actions.append(
NCMenuAction(
title: NSLocalizedString("_rename_", comment: ""),
Expand Down
2 changes: 1 addition & 1 deletion iOSClient/Menu/NCContextMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ class NCContextMenu: NSObject {
}
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: alertStyle)
alertController.addAction(UIAlertAction(title: NSLocalizedString("_delete_file_", comment: ""), style: .destructive) { _ in
NCNetworking.shared.deleteMetadata(metadata)
NCNetworking.shared.deleteMetadatas([metadata], sceneIdentifier: sceneIdentifier)
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource)
})
alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { _ in })
Expand Down
Loading
Loading