зеркало из https://github.com/nextcloud/ios.git
Родитель
6244f78a06
Коммит
e51ce11520
|
@ -17,8 +17,8 @@ function_body_length:
|
|||
warning: 400
|
||||
|
||||
type_body_length:
|
||||
warning: 1500
|
||||
error: 2000
|
||||
warning: 2000
|
||||
error: 2500
|
||||
|
||||
file_length:
|
||||
warning: 2000
|
||||
|
|
|
@ -26,4 +26,4 @@ import Foundation
|
|||
// Database Realm
|
||||
//
|
||||
let databaseName = "nextcloud.realm"
|
||||
let databaseSchemaVersion: UInt64 = 333
|
||||
let databaseSchemaVersion: UInt64 = 340
|
||||
|
|
|
@ -80,12 +80,14 @@ let userAgent: String = {
|
|||
@objc public var disable_log: Bool = false
|
||||
@objc public var disable_mobileconfig: Bool = false
|
||||
@objc public var disable_show_more_nextcloud_apps_in_settings: Bool = false
|
||||
@objc public var doNotAskPasscodeAtStartup: Bool = false
|
||||
|
||||
// Internal option behaviour
|
||||
@objc public var cleanUpDay: Int = 0 // Set default "Delete, in the cache, all files older than" possible days value are: 0, 1, 7, 30, 90, 180, 365
|
||||
|
||||
// Max upload concurrent
|
||||
public let maxConcurrentOperationUpload: Int = 10
|
||||
// Max download/upload concurrent
|
||||
public let maxConcurrentOperationDownload: Int = 5
|
||||
public let maxConcurrentOperationUpload: Int = 5
|
||||
|
||||
// Number of failed attempts after reset app
|
||||
@objc public let resetAppPasscodeAttempts: Int = 10
|
||||
|
|
|
@ -28,8 +28,6 @@ import Parchment
|
|||
|
||||
class NCApplicationHandle: NSObject {
|
||||
|
||||
let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
|
||||
|
||||
// class: AppDelegate
|
||||
// func nextcloudPushNotificationAction(data: [String: AnyObject])
|
||||
func nextcloudPushNotificationAction(data: [String: AnyObject]) -> [String: AnyObject]? {
|
||||
|
|
|
@ -174,7 +174,7 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
|
|||
|
||||
for metadata in metadatas! {
|
||||
|
||||
if metadata.e2eEncrypted || (!metadata.session.isEmpty && metadata.session != NCNetworking.shared.sessionIdentifierBackgroundExtension) { continue }
|
||||
if metadata.e2eEncrypted || (!metadata.session.isEmpty && metadata.session != NCNetworking.shared.sessionUploadBackgroundExtension) { continue }
|
||||
|
||||
fpUtility.createocIdentifierOnFileSystem(metadata: metadata)
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate {
|
|||
// Create directory File Provider Storage
|
||||
_ = utilityFileSystem.directoryProviderStorage
|
||||
// Configure URLSession
|
||||
_ = NCNetworking.shared.sessionManagerBackgroundExtension
|
||||
_ = NCNetworking.shared.sessionManagerUploadBackgroundExtension
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
@ -285,7 +285,7 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate {
|
|||
let serverUrlFileName = metadata.serverUrl + "/" + fileName
|
||||
let fileNameLocalPath = url.path
|
||||
|
||||
if let task = NKBackground(nkCommonInstance: NextcloudKit.shared.nkCommonInstance).upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: nil, dateModificationFile: nil, description: metadata.ocId, session: NCNetworking.shared.sessionManagerBackgroundExtension) {
|
||||
if let task = NKBackground(nkCommonInstance: NextcloudKit.shared.nkCommonInstance).upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: nil, dateModificationFile: nil, description: metadata.ocId, session: NCNetworking.shared.sessionManagerUploadBackgroundExtension) {
|
||||
|
||||
fileProviderData.shared.fileProviderManager.register(task, forItemWithIdentifier: NSFileProviderItemIdentifier(metadata.fileId)) { _ in }
|
||||
}
|
||||
|
@ -356,7 +356,7 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate {
|
|||
fileURL.stopAccessingSecurityScopedResource()
|
||||
|
||||
let metadata = NCManageDatabase.shared.createMetadata(account: fileProviderData.shared.account, user: fileProviderData.shared.user, userId: fileProviderData.shared.userId, fileName: fileName, fileNameView: fileName, ocId: ocIdTemp, serverUrl: tableDirectory.serverUrl, urlBase: fileProviderData.shared.accountUrlBase, url: "", contentType: "")
|
||||
metadata.session = NCNetworking.shared.sessionIdentifierBackgroundExtension
|
||||
metadata.session = NCNetworking.shared.sessionUploadBackgroundExtension
|
||||
metadata.size = size
|
||||
metadata.status = NCGlobal.shared.metadataStatusUploading
|
||||
|
||||
|
@ -365,7 +365,7 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate {
|
|||
let serverUrlFileName = tableDirectory.serverUrl + "/" + fileName
|
||||
let fileNameLocalPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(ocIdTemp, fileNameView: fileName)
|
||||
|
||||
if let task = NKBackground(nkCommonInstance: NextcloudKit.shared.nkCommonInstance).upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: nil, dateModificationFile: nil, description: ocIdTemp, session: NCNetworking.shared.sessionManagerBackgroundExtension) {
|
||||
if let task = NKBackground(nkCommonInstance: NextcloudKit.shared.nkCommonInstance).upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: nil, dateModificationFile: nil, description: ocIdTemp, session: NCNetworking.shared.sessionManagerUploadBackgroundExtension) {
|
||||
|
||||
self.outstandingSessionTasks[URL(fileURLWithPath: fileNameLocalPath)] = task as URLSessionTask
|
||||
|
||||
|
|
|
@ -202,6 +202,13 @@
|
|||
F719D9E0288D37A300762E33 /* NCColorPicker.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F719D9DF288D37A300762E33 /* NCColorPicker.storyboard */; };
|
||||
F719D9E2288D396100762E33 /* NCColorPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = F719D9E1288D396100762E33 /* NCColorPicker.swift */; };
|
||||
F71CD6CA2930D7B1006C95C1 /* NCApplicationHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = F71CD6C92930D7B1006C95C1 /* NCApplicationHandle.swift */; };
|
||||
F71F6D072B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = F71F6D062B6A6A5E00F1EB15 /* ThreadSafeArray.swift */; };
|
||||
F71F6D082B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = F71F6D062B6A6A5E00F1EB15 /* ThreadSafeArray.swift */; };
|
||||
F71F6D092B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = F71F6D062B6A6A5E00F1EB15 /* ThreadSafeArray.swift */; };
|
||||
F71F6D0A2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = F71F6D062B6A6A5E00F1EB15 /* ThreadSafeArray.swift */; };
|
||||
F71F6D0B2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = F71F6D062B6A6A5E00F1EB15 /* ThreadSafeArray.swift */; };
|
||||
F71F6D0C2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = F71F6D062B6A6A5E00F1EB15 /* ThreadSafeArray.swift */; };
|
||||
F71F6D0D2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = F71F6D062B6A6A5E00F1EB15 /* ThreadSafeArray.swift */; };
|
||||
F7226EDC1EE4089300EBECB1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7226EDB1EE4089300EBECB1 /* Main.storyboard */; };
|
||||
F723985C253C95CE00257F49 /* NCViewerRichdocument.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F723985B253C95CE00257F49 /* NCViewerRichdocument.storyboard */; };
|
||||
F7239871253D86B600257F49 /* NCEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7239870253D86B600257F49 /* NCEmptyDataSet.swift */; };
|
||||
|
@ -409,7 +416,6 @@
|
|||
F757CC8C29E82D0500F31428 /* NCGroupfolders.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F757CC8A29E82D0500F31428 /* NCGroupfolders.storyboard */; };
|
||||
F757CC8D29E82D0500F31428 /* NCGroupfolders.swift in Sources */ = {isa = PBXBuildFile; fileRef = F757CC8B29E82D0500F31428 /* NCGroupfolders.swift */; };
|
||||
F7581D1A25EFDA61004DC699 /* NCLoginWeb+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7581D1925EFDA60004DC699 /* NCLoginWeb+Menu.swift */; };
|
||||
F7581D2425EFDDDF004DC699 /* NCMedia+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7581D2325EFDDDF004DC699 /* NCMedia+Menu.swift */; };
|
||||
F758A01227A7F03E0069468B /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = F758A01127A7F03E0069468B /* JGProgressHUD */; };
|
||||
F758B45A212C564000515F55 /* NCScan.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F758B457212C564000515F55 /* NCScan.storyboard */; };
|
||||
F758B45E212C569D00515F55 /* NCScanCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F758B45D212C569C00515F55 /* NCScanCell.swift */; };
|
||||
|
@ -588,6 +594,9 @@
|
|||
F78ACD4B21903F850088454D /* NCTrashListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD4921903F850088454D /* NCTrashListCell.xib */; };
|
||||
F78ACD52219046DC0088454D /* NCSectionHeaderMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78ACD51219046DC0088454D /* NCSectionHeaderMenu.swift */; };
|
||||
F78ACD54219047D40088454D /* NCSectionFooter.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD53219047D40088454D /* NCSectionFooter.xib */; };
|
||||
F78B87E72B62527100C65ADC /* NCMediaDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78B87E62B62527100C65ADC /* NCMediaDataSource.swift */; };
|
||||
F78B87E92B62550800C65ADC /* NCMediaDownloadThumbnaill.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78B87E82B62550800C65ADC /* NCMediaDownloadThumbnaill.swift */; };
|
||||
F78B87EB2B627AA100C65ADC /* NCMediaCommandView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78B87EA2B627AA100C65ADC /* NCMediaCommandView.swift */; };
|
||||
F78C6FDE296D677300C952C3 /* NCContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78C6FDD296D677300C952C3 /* NCContextMenu.swift */; };
|
||||
F78E2D6529AF02DB0024D4F3 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78E2D6429AF02DB0024D4F3 /* Database.swift */; };
|
||||
F78E2D6629AF02DB0024D4F3 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78E2D6429AF02DB0024D4F3 /* Database.swift */; };
|
||||
|
@ -670,6 +679,7 @@
|
|||
F7BB7E4727A18C56009B9F29 /* Parchment in Frameworks */ = {isa = PBXBuildFile; productRef = F7BB7E4627A18C56009B9F29 /* Parchment */; };
|
||||
F7BC287E26663F6C004D46C5 /* NCViewCertificateDetails.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7BC287D26663F6C004D46C5 /* NCViewCertificateDetails.storyboard */; };
|
||||
F7BC288026663F85004D46C5 /* NCViewCertificateDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BC287F26663F85004D46C5 /* NCViewCertificateDetails.swift */; };
|
||||
F7BD50312B65216300D5AEF9 /* NCMediaGridLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BD50302B65216300D5AEF9 /* NCMediaGridLayout.swift */; };
|
||||
F7BD71E62636EAFC00643C34 /* NCNetworkingE2EE.swift in Sources */ = {isa = PBXBuildFile; fileRef = F785EE9C246196DF00B3F945 /* NCNetworkingE2EE.swift */; };
|
||||
F7BF9D822934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BF9D812934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift */; };
|
||||
F7BF9D832934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BF9D812934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift */; };
|
||||
|
@ -694,6 +704,13 @@
|
|||
F7C9739228F17131002C43E2 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7C9739128F17131002C43E2 /* Intents.framework */; };
|
||||
F7C9739528F17131002C43E2 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9739428F17131002C43E2 /* IntentHandler.swift */; };
|
||||
F7C9739928F17131002C43E2 /* WidgetDashboardIntentHandler.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = F7C9739028F17131002C43E2 /* WidgetDashboardIntentHandler.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
F7C9B91D2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9B91C2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift */; };
|
||||
F7C9B91E2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9B91C2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift */; };
|
||||
F7C9B91F2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9B91C2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift */; };
|
||||
F7C9B9202B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9B91C2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift */; };
|
||||
F7C9B9212B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9B91C2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift */; };
|
||||
F7C9B9222B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9B91C2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift */; };
|
||||
F7C9B9232B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9B91C2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift */; };
|
||||
F7CA212D25F1333300826ABB /* NCAccountRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CA212B25F1333200826ABB /* NCAccountRequest.swift */; };
|
||||
F7CA212E25F1333300826ABB /* NCAccountRequest.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CA212C25F1333200826ABB /* NCAccountRequest.storyboard */; };
|
||||
F7CB689A2541676B0050EC94 /* NCMore.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CB68992541676B0050EC94 /* NCMore.storyboard */; };
|
||||
|
@ -1038,6 +1055,7 @@
|
|||
F719D9DF288D37A300762E33 /* NCColorPicker.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCColorPicker.storyboard; sourceTree = "<group>"; };
|
||||
F719D9E1288D396100762E33 /* NCColorPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCColorPicker.swift; sourceTree = "<group>"; };
|
||||
F71CD6C92930D7B1006C95C1 /* NCApplicationHandle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCApplicationHandle.swift; sourceTree = "<group>"; };
|
||||
F71F6D062B6A6A5E00F1EB15 /* ThreadSafeArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadSafeArray.swift; sourceTree = "<group>"; };
|
||||
F7226EDB1EE4089300EBECB1 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
|
||||
F723985B253C95CE00257F49 /* NCViewerRichdocument.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCViewerRichdocument.storyboard; sourceTree = "<group>"; };
|
||||
F7239870253D86B600257F49 /* NCEmptyDataSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEmptyDataSet.swift; sourceTree = "<group>"; };
|
||||
|
@ -1116,7 +1134,6 @@
|
|||
F757CC8A29E82D0500F31428 /* NCGroupfolders.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCGroupfolders.storyboard; sourceTree = "<group>"; };
|
||||
F757CC8B29E82D0500F31428 /* NCGroupfolders.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCGroupfolders.swift; sourceTree = "<group>"; };
|
||||
F7581D1925EFDA60004DC699 /* NCLoginWeb+Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCLoginWeb+Menu.swift"; sourceTree = "<group>"; };
|
||||
F7581D2325EFDDDF004DC699 /* NCMedia+Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCMedia+Menu.swift"; sourceTree = "<group>"; };
|
||||
F758B457212C564000515F55 /* NCScan.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCScan.storyboard; sourceTree = "<group>"; };
|
||||
F758B45D212C569C00515F55 /* NCScanCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCScanCell.swift; sourceTree = "<group>"; };
|
||||
F758B45F212C56A400515F55 /* NCScan.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCScan.swift; sourceTree = "<group>"; };
|
||||
|
@ -1233,6 +1250,9 @@
|
|||
F78ACD4921903F850088454D /* NCTrashListCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCTrashListCell.xib; sourceTree = "<group>"; };
|
||||
F78ACD51219046DC0088454D /* NCSectionHeaderMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSectionHeaderMenu.swift; sourceTree = "<group>"; };
|
||||
F78ACD53219047D40088454D /* NCSectionFooter.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCSectionFooter.xib; sourceTree = "<group>"; };
|
||||
F78B87E62B62527100C65ADC /* NCMediaDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMediaDataSource.swift; sourceTree = "<group>"; };
|
||||
F78B87E82B62550800C65ADC /* NCMediaDownloadThumbnaill.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMediaDownloadThumbnaill.swift; sourceTree = "<group>"; };
|
||||
F78B87EA2B627AA100C65ADC /* NCMediaCommandView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMediaCommandView.swift; sourceTree = "<group>"; };
|
||||
F78C6FDD296D677300C952C3 /* NCContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCContextMenu.swift; sourceTree = "<group>"; };
|
||||
F78D6F461F0B7CB9002F9619 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
F78D6F4D1F0B7CE4002F9619 /* nb-NO */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "nb-NO"; path = "nb-NO.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
|
@ -1331,6 +1351,7 @@
|
|||
F7BB04851FD58ACB00BBFD2A /* cs-CZ */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "cs-CZ"; path = "cs-CZ.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
F7BC287D26663F6C004D46C5 /* NCViewCertificateDetails.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCViewCertificateDetails.storyboard; sourceTree = "<group>"; };
|
||||
F7BC287F26663F85004D46C5 /* NCViewCertificateDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCViewCertificateDetails.swift; sourceTree = "<group>"; };
|
||||
F7BD50302B65216300D5AEF9 /* NCMediaGridLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMediaGridLayout.swift; sourceTree = "<group>"; };
|
||||
F7BE7C25290AC8C9002ABB61 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Intent.strings; sourceTree = "<group>"; };
|
||||
F7BE7C27290ADEFD002ABB61 /* eu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = eu; path = eu.lproj/Intent.strings; sourceTree = "<group>"; };
|
||||
F7BE7C29290ADEFD002ABB61 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Intent.strings; sourceTree = "<group>"; };
|
||||
|
@ -1398,6 +1419,7 @@
|
|||
F7C9739028F17131002C43E2 /* WidgetDashboardIntentHandler.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetDashboardIntentHandler.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F7C9739128F17131002C43E2 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
|
||||
F7C9739428F17131002C43E2 /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = "<group>"; };
|
||||
F7C9B91C2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+SecurityGuard.swift"; sourceTree = "<group>"; };
|
||||
F7CA212B25F1333200826ABB /* NCAccountRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCAccountRequest.swift; sourceTree = "<group>"; };
|
||||
F7CA212C25F1333200826ABB /* NCAccountRequest.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCAccountRequest.storyboard; sourceTree = "<group>"; };
|
||||
F7CB68992541676B0050EC94 /* NCMore.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCMore.storyboard; sourceTree = "<group>"; };
|
||||
|
@ -1627,7 +1649,6 @@
|
|||
8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */,
|
||||
F77A697C250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift */,
|
||||
F7581D1925EFDA60004DC699 /* NCLoginWeb+Menu.swift */,
|
||||
F7581D2325EFDDDF004DC699 /* NCMedia+Menu.swift */,
|
||||
F7CBC31B24F78E79004D3812 /* NCSortMenu.swift */,
|
||||
F75D19E225EFE09000D74598 /* NCTrash+Menu.swift */,
|
||||
AF93471127E2341B002537EE /* NCShare+Menu.swift */,
|
||||
|
@ -2295,6 +2316,7 @@
|
|||
F7864ACB2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift */,
|
||||
AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */,
|
||||
F73EF7C62B0225610087E6E9 /* NCManageDatabase+PhotoLibrary.swift */,
|
||||
F7C9B91C2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift */,
|
||||
F749B649297B0CBB00087535 /* NCManageDatabase+Share.swift */,
|
||||
F73EF7CE2B0225BA0087E6E9 /* NCManageDatabase+Tag.swift */,
|
||||
F73EF7D62B0226080087E6E9 /* NCManageDatabase+Tip.swift */,
|
||||
|
@ -2339,6 +2361,7 @@
|
|||
F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */,
|
||||
F702F2FC25EE5D2C008F8E80 /* NYMnemonic */,
|
||||
AF36077027BFA4E8001A243D /* ParallelWorker.swift */,
|
||||
F71F6D062B6A6A5E00F1EB15 /* ThreadSafeArray.swift */,
|
||||
F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */,
|
||||
);
|
||||
path = Utility;
|
||||
|
@ -2471,7 +2494,11 @@
|
|||
F720B5B72507B9A5008C94E5 /* Cell */,
|
||||
F7501C302212E57400FB1415 /* NCMedia.storyboard */,
|
||||
F7501C312212E57400FB1415 /* NCMedia.swift */,
|
||||
F78B87EA2B627AA100C65ADC /* NCMediaCommandView.swift */,
|
||||
F7F1E54B2492369A00E42386 /* NCMediaCommandView.xib */,
|
||||
F78B87E62B62527100C65ADC /* NCMediaDataSource.swift */,
|
||||
F78B87E82B62550800C65ADC /* NCMediaDownloadThumbnaill.swift */,
|
||||
F7BD50302B65216300D5AEF9 /* NCMediaGridLayout.swift */,
|
||||
);
|
||||
path = Media;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3439,6 +3466,7 @@
|
|||
F749B64F297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
|
||||
F359D86D2A7D03420023F405 /* NCUtility+Exif.swift in Sources */,
|
||||
F73EF7AD2B0223900087E6E9 /* NCManageDatabase+Comments.swift in Sources */,
|
||||
F7C9B9232B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */,
|
||||
F73EF7CD2B0225610087E6E9 /* NCManageDatabase+PhotoLibrary.swift in Sources */,
|
||||
D575039F27146F93008DC9DC /* String+Extension.swift in Sources */,
|
||||
F769CA1A2966EA3C00039397 /* ComponentView.swift in Sources */,
|
||||
|
@ -3456,6 +3484,7 @@
|
|||
F343A4B92A1E084400DDA874 /* PHAsset+Extension.swift in Sources */,
|
||||
F73EF7E52B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */,
|
||||
F73EF7D52B0225BA0087E6E9 /* NCManageDatabase+Tag.swift in Sources */,
|
||||
F71F6D0D2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */,
|
||||
F763D2A32A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
|
||||
F749B656297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
|
||||
F782FDC424E6933900666099 /* NCUtility.swift in Sources */,
|
||||
|
@ -3518,11 +3547,13 @@
|
|||
F7183BD82AEBDCD8000CD020 /* NCKeychain.swift in Sources */,
|
||||
F7490E8129882C79009DCE94 /* NCManageDatabase+DashboardWidget.swift in Sources */,
|
||||
F73EF7D42B0225BA0087E6E9 /* NCManageDatabase+Tag.swift in Sources */,
|
||||
F71F6D0C2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */,
|
||||
F7490E8629882C99009DCE94 /* NCUtilityFileSystem.swift in Sources */,
|
||||
F763D2A22A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
|
||||
F73EF7E42B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */,
|
||||
F343A4C02A1E734600DDA874 /* Optional+Extension.swift in Sources */,
|
||||
F711A4E12AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */,
|
||||
F7C9B9222B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */,
|
||||
F7490E8529882C8C009DCE94 /* NCManageDatabase+Video.swift in Sources */,
|
||||
F7490E8C29882D02009DCE94 /* CCUtility.m in Sources */,
|
||||
F7490E7729882C10009DCE94 /* UIColor+Extension.swift in Sources */,
|
||||
|
@ -3555,6 +3586,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F7864ACF2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */,
|
||||
F71F6D0A2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */,
|
||||
F7245925289BB59100474787 /* ThreadSafeDictionary.swift in Sources */,
|
||||
F7EDE4E5262D7BBE00414FE6 /* NCSectionHeaderMenu.swift in Sources */,
|
||||
F7BF9D852934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
|
||||
|
@ -3585,6 +3617,7 @@
|
|||
AF4BF615275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */,
|
||||
F798F0E225880608000DAFFD /* UIColor+Extension.swift in Sources */,
|
||||
AF3FDCC32796F3FB00710F60 /* NCTrashListCell+NCTrashCellProtocol.swift in Sources */,
|
||||
F7C9B9202B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */,
|
||||
AF817EF2274BC781009ED85B /* NCUserBaseUrl.swift in Sources */,
|
||||
F78E2D6829AF02DB0024D4F3 /* Database.swift in Sources */,
|
||||
F711A4DF2AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */,
|
||||
|
@ -3662,6 +3695,7 @@
|
|||
F711D63128F44801003F43C8 /* IntentHandler.swift in Sources */,
|
||||
F76DEE9728F808AF0041B1C9 /* LockscreenData.swift in Sources */,
|
||||
F72EA95A28B7BD0D00C88F0C /* FilesWidgetView.swift in Sources */,
|
||||
F71F6D082B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */,
|
||||
F78302FE28B4C44700B84583 /* NCBrand.swift in Sources */,
|
||||
F749B64B297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
|
||||
F7075B682AE15F8100512300 /* NCCellProtocol.swift in Sources */,
|
||||
|
@ -3705,6 +3739,7 @@
|
|||
F73EF7E02B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */,
|
||||
F73EF7E82B0226B90087E6E9 /* NCManageDatabase+UserStatus.swift in Sources */,
|
||||
F73EF7D82B0226080087E6E9 /* NCManageDatabase+Tip.swift in Sources */,
|
||||
F7C9B91E2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */,
|
||||
F72FD3B6297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */,
|
||||
F783030128B4C49700B84583 /* UIImage+Extension.swift in Sources */,
|
||||
F72EA95428B7BABA00C88F0C /* FilesWidgetProvider.swift in Sources */,
|
||||
|
@ -3738,6 +3773,7 @@
|
|||
F7D68FCF28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */,
|
||||
F73EF7CB2B0225610087E6E9 /* NCManageDatabase+PhotoLibrary.swift in Sources */,
|
||||
F73EF7C32B02250B0087E6E9 /* NCManageDatabase+GPS.swift in Sources */,
|
||||
F7C9B9212B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */,
|
||||
F359D86B2A7D03420023F405 /* NCUtility+Exif.swift in Sources */,
|
||||
F7864AD02A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */,
|
||||
F7183BD72AEBDCD8000CD020 /* NCKeychain.swift in Sources */,
|
||||
|
@ -3763,6 +3799,7 @@
|
|||
F72429372AFE39980040AEF3 /* NCLivePhoto.swift in Sources */,
|
||||
F7A76DCD256A71CE00119AB3 /* UIImage+Extension.swift in Sources */,
|
||||
F73EF7DB2B0226080087E6E9 /* NCManageDatabase+Tip.swift in Sources */,
|
||||
F71F6D0B2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */,
|
||||
F73EF7EB2B0226B90087E6E9 /* NCManageDatabase+UserStatus.swift in Sources */,
|
||||
F771E3F820E239B500AFB62D /* FileProviderExtension+Thumbnail.swift in Sources */,
|
||||
F343A4BF2A1E734600DDA874 /* Optional+Extension.swift in Sources */,
|
||||
|
@ -3819,6 +3856,7 @@
|
|||
F78A18B823CDE2B300F681F3 /* NCViewerRichWorkspace.swift in Sources */,
|
||||
F7A60F86292D215000FCE1F2 /* NCShareAccounts.swift in Sources */,
|
||||
F77910AB25DD53C700CEDB9E /* NCSettingsBundleHelper.swift in Sources */,
|
||||
F78B87EB2B627AA100C65ADC /* NCMediaCommandView.swift in Sources */,
|
||||
F73EF7B72B0224AB0087E6E9 /* NCManageDatabase+ExternalSites.swift in Sources */,
|
||||
AF4BF61927562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */,
|
||||
F73EF7E72B0226B90087E6E9 /* NCManageDatabase+UserStatus.swift in Sources */,
|
||||
|
@ -3872,6 +3910,7 @@
|
|||
AFCE353327E4ED1900FEA6C2 /* UIToolbar+Extension.swift in Sources */,
|
||||
8491B1CD273BBA82001C8C5B /* UIViewController+Menu.swift in Sources */,
|
||||
F73EF7BF2B02250B0087E6E9 /* NCManageDatabase+GPS.swift in Sources */,
|
||||
F71F6D072B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */,
|
||||
F761856C29E98543006EB3B0 /* NCIntroCollectionViewCell.swift in Sources */,
|
||||
F75DD765290ABB25002EB562 /* Intent.intentdefinition in Sources */,
|
||||
F74B6D952A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */,
|
||||
|
@ -3888,6 +3927,7 @@
|
|||
F72944F22A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */,
|
||||
F70BFC7420E0FA7D00C67599 /* NCUtility.swift in Sources */,
|
||||
F79EDAA526B004980007D134 /* NCPlayer.swift in Sources */,
|
||||
F7BD50312B65216300D5AEF9 /* NCMediaGridLayout.swift in Sources */,
|
||||
F7C1EEA525053A9C00866ACC /* NCDataSource.swift in Sources */,
|
||||
F713FF002472764100214AF6 /* UIImage+animatedGIF.m in Sources */,
|
||||
AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */,
|
||||
|
@ -3902,10 +3942,10 @@
|
|||
F765F73125237E3F00391DBE /* NCRecent.swift in Sources */,
|
||||
F76B3CCE1EAE01BD00921AC9 /* NCBrand.swift in Sources */,
|
||||
F359D8672A7D03420023F405 /* NCUtility+Exif.swift in Sources */,
|
||||
F7581D2425EFDDDF004DC699 /* NCMedia+Menu.swift in Sources */,
|
||||
F738D4902756740100CD1D38 /* NCLoginNavigationController.swift in Sources */,
|
||||
F77B0E981D118A16002130FE /* CCManageAccount.m in Sources */,
|
||||
F769CA192966EA3C00039397 /* ComponentView.swift in Sources */,
|
||||
F7C9B91D2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */,
|
||||
AF93474C27E34120002537EE /* NCUtility+Image.swift in Sources */,
|
||||
F702F30125EE5D2C008F8E80 /* NYMnemonic.m in Sources */,
|
||||
AF93474E27E3F212002537EE /* NCShareNewUserAddComment.swift in Sources */,
|
||||
|
@ -3947,6 +3987,7 @@
|
|||
F70968A424212C4E00ED60E5 /* NCLivePhoto.swift in Sources */,
|
||||
F7C30DFA291BCF790017149B /* NCNetworkingE2EECreateFolder.swift in Sources */,
|
||||
F7BC288026663F85004D46C5 /* NCViewCertificateDetails.swift in Sources */,
|
||||
F78B87E92B62550800C65ADC /* NCMediaDownloadThumbnaill.swift in Sources */,
|
||||
F73EF7AF2B0224350087E6E9 /* NCManageDatabase+DirectEditing.swift in Sources */,
|
||||
F702F2E625EE5C86008F8E80 /* NCAudioRecorderViewController.swift in Sources */,
|
||||
D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */,
|
||||
|
@ -3972,6 +4013,7 @@
|
|||
F7A7FA6329265CF4000603EF /* NCManageE2EE.swift in Sources */,
|
||||
F7C7B489245EBA4100D93E60 /* NCViewerQuickLook.swift in Sources */,
|
||||
F758B45E212C569D00515F55 /* NCScanCell.swift in Sources */,
|
||||
F78B87E72B62527100C65ADC /* NCMediaDataSource.swift in Sources */,
|
||||
F7581D1A25EFDA61004DC699 /* NCLoginWeb+Menu.swift in Sources */,
|
||||
F7864ACC2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */,
|
||||
F7F4F11027ECDC4A008676F9 /* UIDevice+Extension.swift in Sources */,
|
||||
|
@ -4002,6 +4044,7 @@
|
|||
F7C9739528F17131002C43E2 /* IntentHandler.swift in Sources */,
|
||||
F7A8D73D28F181D3008BBE1C /* NCUtilityFileSystem.swift in Sources */,
|
||||
F73EF7E12B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */,
|
||||
F7C9B91F2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */,
|
||||
F7A8D74528F1828E008BBE1C /* CCUtility.m in Sources */,
|
||||
F75DD767290ABB25002EB562 /* Intent.intentdefinition in Sources */,
|
||||
F749B64C297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
|
||||
|
@ -4034,6 +4077,7 @@
|
|||
F73EF7D12B0225BA0087E6E9 /* NCManageDatabase+Tag.swift in Sources */,
|
||||
F73EF7C92B0225610087E6E9 /* NCManageDatabase+PhotoLibrary.swift in Sources */,
|
||||
F73EF7B92B0224AB0087E6E9 /* NCManageDatabase+ExternalSites.swift in Sources */,
|
||||
F71F6D092B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */,
|
||||
F757CC8429E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
|
||||
F78E2D6729AF02DB0024D4F3 /* Database.swift in Sources */,
|
||||
F7A8D73628F17E1A008BBE1C /* NCManageDatabase+Activity.swift in Sources */,
|
||||
|
@ -4308,7 +4352,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = it.twsweb.NextcloudTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -4325,7 +4369,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = it.twsweb.NextcloudTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -4360,7 +4404,7 @@
|
|||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
|
@ -4398,7 +4442,7 @@
|
|||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
|
@ -4441,7 +4485,7 @@
|
|||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
|
@ -4480,7 +4524,7 @@
|
|||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
|
@ -4522,7 +4566,7 @@
|
|||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
|
@ -4561,7 +4605,7 @@
|
|||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
|
@ -4873,7 +4917,7 @@
|
|||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = NKUJUXUJ3B;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
|
@ -4899,7 +4943,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 4.9.6;
|
||||
MARKETING_VERSION = 5.0.0;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "";
|
||||
SDKROOT = iphoneos;
|
||||
|
@ -4938,7 +4982,7 @@
|
|||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
DEVELOPMENT_TEAM = NKUJUXUJ3B;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
|
@ -4961,7 +5005,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 4.9.6;
|
||||
MARKETING_VERSION = 5.0.0;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "";
|
||||
SDKROOT = iphoneos;
|
||||
|
@ -5253,7 +5297,7 @@
|
|||
repositoryURL = "https://github.com/nextcloud/NextcloudKit";
|
||||
requirement = {
|
||||
kind = exactVersion;
|
||||
version = 2.9.4;
|
||||
version = 2.9.5;
|
||||
};
|
||||
};
|
||||
F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = {
|
||||
|
|
|
@ -213,6 +213,7 @@ func getFilesDataEntry(configuration: AccountIntent?, isPreview: Bool, displaySi
|
|||
var datas: [FilesData] = []
|
||||
var imageRecent = UIImage(named: "file")!
|
||||
let title = getTitleFilesWidget(account: account)
|
||||
let files = files.sorted(by: { ($0.date as Date) > ($1.date as Date) })
|
||||
|
||||
for file in files {
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ class NCActivity: UIViewController, NCSharePagingContent {
|
|||
|
||||
appDelegate.activeViewController = self
|
||||
|
||||
navigationController?.setFileAppreance()
|
||||
navigationController?.setNavigationBarAppearance()
|
||||
|
||||
fetchAll(isInitial: true)
|
||||
}
|
||||
|
|
|
@ -156,13 +156,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
self.handleProcessingTask(task)
|
||||
}
|
||||
|
||||
// Intro
|
||||
if NCBrandOptions.shared.disable_intro {
|
||||
if account.isEmpty {
|
||||
if account.isEmpty {
|
||||
if NCBrandOptions.shared.disable_intro {
|
||||
openLogin(viewController: nil, selector: NCGlobal.shared.introLogin, openLoginWeb: false)
|
||||
}
|
||||
} else {
|
||||
if !NCKeychain().intro {
|
||||
} else {
|
||||
if let viewController = UIStoryboard(name: "NCIntro", bundle: nil).instantiateInitialViewController() {
|
||||
let navigationController = NCLoginNavigationController(rootViewController: viewController)
|
||||
window?.rootViewController = navigationController
|
||||
|
@ -272,6 +269,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
|
||||
scheduleAppRefresh()
|
||||
scheduleAppProcessing()
|
||||
NCNetworking.shared.cancelAllQueue()
|
||||
NCNetworking.shared.cancelDataTask()
|
||||
NCNetworking.shared.cancelDownloadTasks()
|
||||
presentPasscode { }
|
||||
|
@ -579,6 +577,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
|
||||
@objc func changeAccount(_ account: String, userProfile: NKUserProfile?) {
|
||||
|
||||
NCNetworking.shared.cancelAllQueue()
|
||||
NCNetworking.shared.cancelDataTask()
|
||||
NCNetworking.shared.cancelDownloadTasks()
|
||||
NCNetworking.shared.cancelUploadTasks()
|
||||
|
@ -882,10 +881,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
|
||||
let utilityFileSystem = NCUtilityFileSystem()
|
||||
|
||||
NCNetworking.shared.cancelAllQueue()
|
||||
NCNetworking.shared.cancelDataTask()
|
||||
NCNetworking.shared.cancelDownloadTasks()
|
||||
NCNetworking.shared.cancelUploadTasks()
|
||||
NCNetworking.shared.cancelUploadBackgroundTask()
|
||||
NCNetworking.shared.cancelUploadBackgroundTask(withNotification: false)
|
||||
|
||||
URLCache.shared.memoryCapacity = 0
|
||||
URLCache.shared.diskCapacity = 0
|
||||
|
@ -928,18 +928,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Queue
|
||||
|
||||
@objc func cancelAllQueue() {
|
||||
NCNetworking.shared.downloadQueue.cancelAll()
|
||||
NCNetworking.shared.downloadThumbnailQueue.cancelAll()
|
||||
NCNetworking.shared.downloadThumbnailActivityQueue.cancelAll()
|
||||
NCNetworking.shared.downloadAvatarQueue.cancelAll()
|
||||
NCNetworking.shared.unifiedSearchQueue.cancelAll()
|
||||
NCNetworking.shared.saveLivePhotoQueue.cancelAll()
|
||||
NCNetworking.shared.convertLivePhotoQueue.cancelAll()
|
||||
}
|
||||
|
||||
// MARK: - Universal Links
|
||||
|
||||
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
||||
|
|
|
@ -137,7 +137,7 @@ class NCDataSource: NSObject {
|
|||
|
||||
} else {
|
||||
|
||||
// normal
|
||||
// normal
|
||||
let directory = NSLocalizedString("directory", comment: "").lowercased().firstUppercased
|
||||
self.sectionsValue = self.sectionsValue.sorted {
|
||||
if directoryOnTop && $0 == directory {
|
||||
|
@ -191,10 +191,9 @@ class NCDataSource: NSObject {
|
|||
|
||||
// MARK: -
|
||||
|
||||
@discardableResult
|
||||
func appendMetadatasToSection(_ metadatas: [tableMetadata], metadataForSection: NCMetadataForSection, lastSearchResult: NKSearchResult) -> [IndexPath] {
|
||||
func appendMetadatasToSection(_ metadatas: [tableMetadata], metadataForSection: NCMetadataForSection, lastSearchResult: NKSearchResult) {
|
||||
|
||||
guard let sectionIndex = getSectionIndex(metadataForSection.sectionValue) else { return [] }
|
||||
guard let sectionIndex = getSectionIndex(metadataForSection.sectionValue) else { return }
|
||||
var indexPaths: [IndexPath] = []
|
||||
|
||||
self.metadatas.append(contentsOf: metadatas)
|
||||
|
@ -207,36 +206,6 @@ class NCDataSource: NSObject {
|
|||
indexPaths.append(IndexPath(row: rowIndex, section: sectionIndex))
|
||||
}
|
||||
}
|
||||
|
||||
return indexPaths
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func reloadMetadata(ocId: String, ocIdTemp: String? = nil) -> (indexPath: IndexPath?, sameSections: Bool) {
|
||||
|
||||
let numberOfSections = self.numberOfSections()
|
||||
var ocIdSearch = ocId
|
||||
|
||||
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return (nil, self.isSameNumbersOfSections(numberOfSections: numberOfSections)) }
|
||||
|
||||
if let ocIdTemp = ocIdTemp {
|
||||
ocIdSearch = ocIdTemp
|
||||
}
|
||||
|
||||
// UPDATE metadataForSection (IMPORTANT FIRST)
|
||||
let (indexPath, metadataForSection) = self.getIndexPathMetadata(ocId: ocIdSearch)
|
||||
if let indexPath = indexPath, let metadataForSection = metadataForSection {
|
||||
metadataForSection.metadatas[indexPath.row] = metadata
|
||||
metadataForSection.createMetadatas()
|
||||
}
|
||||
|
||||
// UPDATE metadatasSource (IMPORTANT LAST)
|
||||
if let rowIndex = self.metadatas.firstIndex(where: {$0.ocId == ocIdSearch}) {
|
||||
self.metadatas[rowIndex] = metadata
|
||||
}
|
||||
|
||||
let result = self.getIndexPathMetadata(ocId: ocId)
|
||||
return (result.indexPath, self.isSameNumbersOfSections(numberOfSections: numberOfSections))
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
|
|
@ -102,6 +102,7 @@ extension NCManageDatabase {
|
|||
let userstatus: UserStatus?
|
||||
let external: External?
|
||||
let groupfolders: GroupFolders?
|
||||
let securityguard: SecurityGuard?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case filessharing = "files_sharing"
|
||||
|
@ -110,6 +111,7 @@ extension NCManageDatabase {
|
|||
case richdocuments, activity, notifications, files
|
||||
case userstatus = "user_status"
|
||||
case external, groupfolders
|
||||
case securityguard = "security_guard"
|
||||
}
|
||||
|
||||
struct FilesSharing: Codable {
|
||||
|
@ -263,6 +265,10 @@ extension NCManageDatabase {
|
|||
struct GroupFolders: Codable {
|
||||
let hasGroupFolders: Bool?
|
||||
}
|
||||
|
||||
struct SecurityGuard: Codable {
|
||||
let diagnostics: Bool?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -288,65 +294,69 @@ extension NCManageDatabase {
|
|||
guard let jsonData = jsonData else { return }
|
||||
|
||||
do {
|
||||
var global = NCGlobal.shared
|
||||
let json = try JSONDecoder().decode(CapabilityNextcloud.self, from: jsonData)
|
||||
NCGlobal.shared.capabilityServerVersion = json.ocs.data.version.string
|
||||
NCGlobal.shared.capabilityServerVersionMajor = json.ocs.data.version.major
|
||||
var data = json.ocs.data
|
||||
|
||||
if NCGlobal.shared.capabilityServerVersionMajor > 0 {
|
||||
NextcloudKit.shared.setup(nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor)
|
||||
global.capabilityServerVersion = data.version.string
|
||||
global.capabilityServerVersionMajor = data.version.major
|
||||
|
||||
if global.capabilityServerVersionMajor > 0 {
|
||||
NextcloudKit.shared.setup(nextcloudVersion: global.capabilityServerVersionMajor)
|
||||
}
|
||||
|
||||
NCGlobal.shared.capabilityFileSharingApiEnabled = json.ocs.data.capabilities.filessharing?.apienabled ?? false
|
||||
NCGlobal.shared.capabilityFileSharingDefaultPermission = json.ocs.data.capabilities.filessharing?.defaultpermissions ?? 0
|
||||
NCGlobal.shared.capabilityFileSharingPubPasswdEnforced = json.ocs.data.capabilities.filessharing?.ncpublic?.password?.enforced ?? false
|
||||
NCGlobal.shared.capabilityFileSharingPubExpireDateEnforced = json.ocs.data.capabilities.filessharing?.ncpublic?.expiredate?.enforced ?? false
|
||||
NCGlobal.shared.capabilityFileSharingPubExpireDateDays = json.ocs.data.capabilities.filessharing?.ncpublic?.expiredate?.days ?? 0
|
||||
NCGlobal.shared.capabilityFileSharingInternalExpireDateEnforced = json.ocs.data.capabilities.filessharing?.ncpublic?.expiredateinternal?.enforced ?? false
|
||||
NCGlobal.shared.capabilityFileSharingInternalExpireDateDays = json.ocs.data.capabilities.filessharing?.ncpublic?.expiredateinternal?.days ?? 0
|
||||
NCGlobal.shared.capabilityFileSharingRemoteExpireDateEnforced = json.ocs.data.capabilities.filessharing?.ncpublic?.expiredateremote?.enforced ?? false
|
||||
NCGlobal.shared.capabilityFileSharingRemoteExpireDateDays = json.ocs.data.capabilities.filessharing?.ncpublic?.expiredateremote?.days ?? 0
|
||||
global.capabilityFileSharingApiEnabled = data.capabilities.filessharing?.apienabled ?? false
|
||||
global.capabilityFileSharingDefaultPermission = data.capabilities.filessharing?.defaultpermissions ?? 0
|
||||
global.capabilityFileSharingPubPasswdEnforced = data.capabilities.filessharing?.ncpublic?.password?.enforced ?? false
|
||||
global.capabilityFileSharingPubExpireDateEnforced = data.capabilities.filessharing?.ncpublic?.expiredate?.enforced ?? false
|
||||
global.capabilityFileSharingPubExpireDateDays = data.capabilities.filessharing?.ncpublic?.expiredate?.days ?? 0
|
||||
global.capabilityFileSharingInternalExpireDateEnforced = data.capabilities.filessharing?.ncpublic?.expiredateinternal?.enforced ?? false
|
||||
global.capabilityFileSharingInternalExpireDateDays = data.capabilities.filessharing?.ncpublic?.expiredateinternal?.days ?? 0
|
||||
global.capabilityFileSharingRemoteExpireDateEnforced = data.capabilities.filessharing?.ncpublic?.expiredateremote?.enforced ?? false
|
||||
global.capabilityFileSharingRemoteExpireDateDays = data.capabilities.filessharing?.ncpublic?.expiredateremote?.days ?? 0
|
||||
|
||||
NCGlobal.shared.capabilityThemingColor = json.ocs.data.capabilities.theming?.color ?? ""
|
||||
NCGlobal.shared.capabilityThemingColorElement = json.ocs.data.capabilities.theming?.colorelement ?? ""
|
||||
NCGlobal.shared.capabilityThemingColorText = json.ocs.data.capabilities.theming?.colortext ?? ""
|
||||
NCGlobal.shared.capabilityThemingName = json.ocs.data.capabilities.theming?.name ?? ""
|
||||
NCGlobal.shared.capabilityThemingSlogan = json.ocs.data.capabilities.theming?.slogan ?? ""
|
||||
global.capabilityThemingColor = data.capabilities.theming?.color ?? ""
|
||||
global.capabilityThemingColorElement = data.capabilities.theming?.colorelement ?? ""
|
||||
global.capabilityThemingColorText = data.capabilities.theming?.colortext ?? ""
|
||||
global.capabilityThemingName = data.capabilities.theming?.name ?? ""
|
||||
global.capabilityThemingSlogan = data.capabilities.theming?.slogan ?? ""
|
||||
|
||||
NCGlobal.shared.capabilityE2EEEnabled = json.ocs.data.capabilities.endtoendencryption?.enabled ?? false
|
||||
NCGlobal.shared.capabilityE2EEApiVersion = json.ocs.data.capabilities.endtoendencryption?.apiversion ?? ""
|
||||
global.capabilityE2EEEnabled = data.capabilities.endtoendencryption?.enabled ?? false
|
||||
global.capabilityE2EEApiVersion = data.capabilities.endtoendencryption?.apiversion ?? ""
|
||||
|
||||
NCGlobal.shared.capabilityRichdocumentsEnabled = json.ocs.data.capabilities.richdocuments?.directediting ?? false
|
||||
NCGlobal.shared.capabilityRichdocumentsMimetypes.removeAll()
|
||||
if let mimetypes = json.ocs.data.capabilities.richdocuments?.mimetypes {
|
||||
global.capabilityRichdocumentsEnabled = json.ocs.data.capabilities.richdocuments?.directediting ?? false
|
||||
global.capabilityRichdocumentsMimetypes.removeAll()
|
||||
if let mimetypes = data.capabilities.richdocuments?.mimetypes {
|
||||
for mimetype in mimetypes {
|
||||
NCGlobal.shared.capabilityRichdocumentsMimetypes.append(mimetype)
|
||||
global.capabilityRichdocumentsMimetypes.append(mimetype)
|
||||
}
|
||||
}
|
||||
|
||||
NCGlobal.shared.capabilityActivity.removeAll()
|
||||
if let activities = json.ocs.data.capabilities.activity?.apiv2 {
|
||||
global.capabilityActivity.removeAll()
|
||||
if let activities = data.capabilities.activity?.apiv2 {
|
||||
for activity in activities {
|
||||
NCGlobal.shared.capabilityActivity.append(activity)
|
||||
global.capabilityActivity.append(activity)
|
||||
}
|
||||
}
|
||||
|
||||
NCGlobal.shared.capabilityNotification.removeAll()
|
||||
if let notifications = json.ocs.data.capabilities.notifications?.ocsendpoints {
|
||||
global.capabilityNotification.removeAll()
|
||||
if let notifications = data.capabilities.notifications?.ocsendpoints {
|
||||
for notification in notifications {
|
||||
NCGlobal.shared.capabilityNotification.append(notification)
|
||||
global.capabilityNotification.append(notification)
|
||||
}
|
||||
}
|
||||
|
||||
NCGlobal.shared.capabilityFilesUndelete = json.ocs.data.capabilities.files?.undelete ?? false
|
||||
NCGlobal.shared.capabilityFilesLockVersion = json.ocs.data.capabilities.files?.locking ?? ""
|
||||
NCGlobal.shared.capabilityFilesComments = json.ocs.data.capabilities.files?.comments ?? false
|
||||
NCGlobal.shared.capabilityFilesBigfilechunking = json.ocs.data.capabilities.files?.bigfilechunking ?? false
|
||||
global.capabilityFilesUndelete = data.capabilities.files?.undelete ?? false
|
||||
global.capabilityFilesLockVersion = data.capabilities.files?.locking ?? ""
|
||||
global.capabilityFilesComments = data.capabilities.files?.comments ?? false
|
||||
global.capabilityFilesBigfilechunking = data.capabilities.files?.bigfilechunking ?? false
|
||||
|
||||
NCGlobal.shared.capabilityUserStatusEnabled = json.ocs.data.capabilities.files?.undelete ?? false
|
||||
if json.ocs.data.capabilities.external != nil {
|
||||
NCGlobal.shared.capabilityExternalSites = true
|
||||
global.capabilityUserStatusEnabled = data.capabilities.files?.undelete ?? false
|
||||
if data.capabilities.external != nil {
|
||||
global.capabilityExternalSites = true
|
||||
}
|
||||
NCGlobal.shared.capabilityGroupfoldersEnabled = json.ocs.data.capabilities.groupfolders?.hasGroupFolders ?? false
|
||||
global.capabilityGroupfoldersEnabled = data.capabilities.groupfolders?.hasGroupFolders ?? false
|
||||
global.capabilitySecurityGuardDiagnostics = data.capabilities.securityguard?.diagnostics ?? false
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
return
|
||||
|
|
|
@ -77,6 +77,14 @@ extension NCManageDatabase {
|
|||
|
||||
func deleteDirectoryAndSubDirectory(serverUrl: String, account: String) {
|
||||
|
||||
#if !EXTENSION
|
||||
DispatchQueue.main.async {
|
||||
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
|
||||
appDelegate.listFilesVC[serverUrl] = nil
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
let results = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl BEGINSWITH %@", account, serverUrl)
|
||||
|
@ -123,6 +131,20 @@ extension NCManageDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
func cleanEtagDirectory(account: String, serverUrl: String) {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
try realm.write {
|
||||
if let result = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first {
|
||||
result.etag = ""
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func getTableDirectory(predicate: NSPredicate) -> tableDirectory? {
|
||||
|
||||
do {
|
||||
|
@ -141,7 +163,6 @@ extension NCManageDatabase {
|
|||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
realm.refresh()
|
||||
return realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
|
|
|
@ -46,7 +46,6 @@ class tableE2eEncryptionV3: Object {
|
|||
@Persisted var key = ""
|
||||
@Persisted var initializationVector = ""
|
||||
@Persisted var metadataKey = ""
|
||||
@Persisted var metadataKeyFiledrop = ""
|
||||
@Persisted var metadataKeyIndex: Int = 0
|
||||
@Persisted var metadataVersion: Double = 0
|
||||
@Persisted var mimeType = ""
|
||||
|
@ -132,25 +131,6 @@ class tableE2eUsers: Object {
|
|||
}
|
||||
}
|
||||
|
||||
class tableE2eUsersFiledrop: Object {
|
||||
|
||||
@Persisted(primaryKey: true) var primaryKey = ""
|
||||
@Persisted var account = ""
|
||||
@Persisted var certificate = ""
|
||||
@Persisted var encryptedFiledropKey: String?
|
||||
@Persisted var ocIdServerUrl: String = ""
|
||||
@Persisted var serverUrl: String = ""
|
||||
@Persisted var userId = ""
|
||||
|
||||
convenience init(account: String, ocIdServerUrl: String, userId: String) {
|
||||
self.init()
|
||||
self.primaryKey = account + ocIdServerUrl + userId
|
||||
self.account = account
|
||||
self.ocIdServerUrl = ocIdServerUrl
|
||||
self.userId = userId
|
||||
}
|
||||
}
|
||||
|
||||
extension NCManageDatabase {
|
||||
|
||||
// MARK: -
|
||||
|
@ -371,7 +351,7 @@ extension NCManageDatabase {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getE2EUsers(account: String, ocIdServerUrl: String, userId: String) -> tableE2eUsers? {
|
||||
func getE2EUser(account: String, ocIdServerUrl: String, userId: String) -> tableE2eUsers? {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
|
@ -383,18 +363,6 @@ extension NCManageDatabase {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getE2EUsersFiledrop(account: String, ocIdServerUrl: String, userId: String) -> tableE2eUsersFiledrop? {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
return realm.objects(tableE2eUsersFiledrop.self).filter("account == %@ && ocIdServerUrl == %@ AND userId == %@", account, ocIdServerUrl, userId).first
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getE2eMetadata(account: String, ocIdServerUrl: String) -> tableE2eMetadata? {
|
||||
|
||||
do {
|
||||
|
|
|
@ -52,7 +52,6 @@ extension NCManageDatabase {
|
|||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
realm.refresh()
|
||||
return realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
|
@ -170,7 +169,6 @@ extension NCManageDatabase {
|
|||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
realm.refresh()
|
||||
let results = realm.objects(tableLocalFile.self).filter("account == %@", account)
|
||||
return Array(results.map { tableLocalFile.init(value: $0) })
|
||||
} catch let error as NSError {
|
||||
|
@ -184,7 +182,6 @@ extension NCManageDatabase {
|
|||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
realm.refresh()
|
||||
guard let result = realm.objects(tableLocalFile.self).filter(predicate).first else { return nil }
|
||||
return tableLocalFile.init(value: result)
|
||||
} catch let error as NSError {
|
||||
|
@ -198,7 +195,6 @@ extension NCManageDatabase {
|
|||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
realm.refresh()
|
||||
return realm.objects(tableLocalFile.self).filter(predicate)
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
|
@ -211,7 +207,6 @@ extension NCManageDatabase {
|
|||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
realm.refresh()
|
||||
let results = realm.objects(tableLocalFile.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
|
||||
return Array(results.map { tableLocalFile.init(value: $0) })
|
||||
} catch let error as NSError {
|
||||
|
@ -225,7 +220,6 @@ extension NCManageDatabase {
|
|||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
realm.refresh()
|
||||
return realm.objects(tableLocalFile.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
|
|
|
@ -27,9 +27,25 @@ import NextcloudKit
|
|||
|
||||
class tableMetadata: Object, NCUserBaseUrl {
|
||||
override func isEqual(_ object: Any?) -> Bool {
|
||||
if let object = object as? tableMetadata {
|
||||
return self.fileId == object.fileId && self.account == object.account
|
||||
&& self.path == object.path && self.fileName == object.fileName
|
||||
if let object = object as? tableMetadata,
|
||||
self.account == object.account,
|
||||
self.etag == object.etag,
|
||||
self.fileId == object.fileId,
|
||||
self.path == object.path,
|
||||
self.fileName == object.fileName,
|
||||
self.fileNameView == object.fileNameView,
|
||||
self.date == object.date,
|
||||
self.permissions == object.permissions,
|
||||
self.hasPreview == object.hasPreview,
|
||||
self.note == object.note,
|
||||
self.lock == object.lock,
|
||||
self.favorite == object.favorite,
|
||||
self.livePhotoFile == object.livePhotoFile,
|
||||
self.sharePermissionsCollaborationServices == object.sharePermissionsCollaborationServices,
|
||||
Array(self.tags).elementsEqual(Array(object.tags)),
|
||||
Array(self.shareType).elementsEqual(Array(object.shareType)),
|
||||
Array(self.sharePermissionsCloudMesh).elementsEqual(Array(object.sharePermissionsCloudMesh)) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
@ -60,11 +76,11 @@ class tableMetadata: Object, NCUserBaseUrl {
|
|||
@objc dynamic var hidden: Bool = false
|
||||
@objc dynamic var iconName = ""
|
||||
@objc dynamic var iconUrl = ""
|
||||
@objc dynamic var isFlaggedAsLivePhotoByServer: Bool = false
|
||||
@objc dynamic var isFlaggedAsLivePhotoByServer: Bool = false // Indicating if the file is sent as a live photo from the server, or if we should detect it as such and convert it client-side
|
||||
@objc dynamic var isExtractFile: Bool = false
|
||||
@objc dynamic var livePhotoFile = ""
|
||||
@objc dynamic var livePhotoFile = "" // If this is not empty, the media is a live photo. New media gets this straight from server, but old media needs to be detected as live photo (look isFlaggedAsLivePhotoByServer)
|
||||
@objc dynamic var mountType = ""
|
||||
@objc dynamic var name = "" // for unifiedSearch is the provider.id
|
||||
@objc dynamic var name = "" // for unifiedSearch is the provider.id
|
||||
@objc dynamic var note = ""
|
||||
@objc dynamic var ocId = ""
|
||||
@objc dynamic var ownerId = ""
|
||||
|
@ -107,8 +123,6 @@ class tableMetadata: Object, NCUserBaseUrl {
|
|||
@objc dynamic var height: Int = 0
|
||||
@objc dynamic var width: Int = 0
|
||||
@objc dynamic var errorCode: Int = 0
|
||||
@objc dynamic var errorCodeCounter: Int = 0
|
||||
@objc dynamic var errorCodeDate: Date?
|
||||
|
||||
override static func primaryKey() -> String {
|
||||
return "ocId"
|
||||
|
@ -226,7 +240,7 @@ extension tableMetadata {
|
|||
}
|
||||
|
||||
var isInTransfer: Bool {
|
||||
status == NCGlobal.shared.metadataStatusInDownload || status == NCGlobal.shared.metadataStatusDownloading || status == NCGlobal.shared.metadataStatusInUpload || status == NCGlobal.shared.metadataStatusUploading
|
||||
status == NCGlobal.shared.metadataStatusDownloading || status == NCGlobal.shared.metadataStatusUploading
|
||||
}
|
||||
|
||||
var isTransferInForeground: Bool {
|
||||
|
@ -234,11 +248,11 @@ extension tableMetadata {
|
|||
}
|
||||
|
||||
var isDownload: Bool {
|
||||
status == NCGlobal.shared.metadataStatusInDownload || status == NCGlobal.shared.metadataStatusDownloading
|
||||
status == NCGlobal.shared.metadataStatusDownloading
|
||||
}
|
||||
|
||||
var isUpload: Bool {
|
||||
status == NCGlobal.shared.metadataStatusInUpload || status == NCGlobal.shared.metadataStatusUploading
|
||||
status == NCGlobal.shared.metadataStatusUploading
|
||||
}
|
||||
|
||||
@objc var isDirectoryE2EE: Bool {
|
||||
|
@ -257,6 +271,14 @@ extension tableMetadata {
|
|||
!isFlaggedAsLivePhotoByServer
|
||||
}
|
||||
|
||||
var isSynchronizable: Bool {
|
||||
let localFile = NCManageDatabase.shared.getResultsTableLocalFile(predicate: NSPredicate(format: "ocId == %@", ocId))?.first
|
||||
if localFile?.etag != etag || NCUtilityFileSystem().fileProviderStorageSize(ocId, fileNameView: fileNameView) == 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/// Returns false if the user is lokced out of the file. I.e. The file is locked but by somone else
|
||||
func canUnlock(as user: String) -> Bool {
|
||||
return !lock || (lockOwner == user && lockOwnerType == 0)
|
||||
|
@ -264,10 +286,8 @@ extension tableMetadata {
|
|||
|
||||
// Return if is sharable
|
||||
func isSharable() -> Bool {
|
||||
guard NCGlobal.shared.capabilityFileSharingApiEnabled else { return false }
|
||||
if isDirectoryE2EE || e2eEncrypted {
|
||||
guard directory, NCGlobal.shared.capabilityE2EEEnabled else { return false }
|
||||
return true
|
||||
if !NCGlobal.shared.capabilityFileSharingApiEnabled || (NCGlobal.shared.capabilityE2EEEnabled && isDirectoryE2EE) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -402,6 +422,15 @@ extension NCManageDatabase {
|
|||
completion(metadataFolder, metadataFolders, metadatas)
|
||||
}
|
||||
|
||||
func convertFilesToMetadatas(_ files: [NKFile], useMetadataFolder: Bool) async -> (metadataFolder: tableMetadata, metadatasFolder: [tableMetadata], metadatas: [tableMetadata]) {
|
||||
|
||||
await withUnsafeContinuation({ continuation in
|
||||
convertFilesToMetadatas(files, useMetadataFolder: useMetadataFolder) { metadataFolder, metadatasFolder, metadatas in
|
||||
continuation.resume(returning: (metadataFolder, metadatasFolder, metadatas))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func createMetadata(account: String, user: String, userId: String, fileName: String, fileNameView: String, ocId: String, serverUrl: String, urlBase: String, url: String, contentType: String, isUrl: Bool = false, name: String = NCGlobal.shared.appName, subline: String? = nil, iconName: String? = nil, iconUrl: String? = nil) -> tableMetadata {
|
||||
|
||||
let metadata = tableMetadata()
|
||||
|
@ -497,6 +526,18 @@ extension NCManageDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
func deleteMetadata(results: Results<tableMetadata>) {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
try realm.write {
|
||||
realm.delete(results)
|
||||
}
|
||||
} catch let error {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func moveMetadata(ocId: String, serverUrlTo: String) {
|
||||
|
||||
do {
|
||||
|
@ -530,7 +571,14 @@ extension NCManageDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
func setMetadataSession(ocId: String, newFileName: String? = nil, session: String?, sessionError: String?, sessionSelector: String?, sessionTaskIdentifier: Int?, status: Int?, etag: String? = nil, errorCode: Int?) {
|
||||
func setMetadataSession(ocId: String,
|
||||
newFileName: String? = nil,
|
||||
session: String? = nil,
|
||||
sessionError: String? = nil,
|
||||
selector: String? = nil,
|
||||
status: Int? = nil,
|
||||
etag: String? = nil,
|
||||
errorCode: Int? = nil) {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
|
@ -546,11 +594,8 @@ extension NCManageDatabase {
|
|||
if let sessionError {
|
||||
result.sessionError = sessionError
|
||||
}
|
||||
if let sessionSelector {
|
||||
result.sessionSelector = sessionSelector
|
||||
}
|
||||
if let sessionTaskIdentifier {
|
||||
result.sessionTaskIdentifier = sessionTaskIdentifier
|
||||
if let selector {
|
||||
result.sessionSelector = selector
|
||||
}
|
||||
if let status {
|
||||
result.status = status
|
||||
|
@ -560,12 +605,6 @@ extension NCManageDatabase {
|
|||
}
|
||||
if let errorCode {
|
||||
result.errorCode = errorCode
|
||||
if errorCode == 0 {
|
||||
result.errorCodeCounter = 0
|
||||
} else {
|
||||
result.errorCodeCounter += 1
|
||||
result.errorCodeDate = Date()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -574,6 +613,49 @@ extension NCManageDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
func setMetadataSession(ocId: String,
|
||||
status: Int? = nil,
|
||||
taskIdentifier: Int? = nil) {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
try realm.write {
|
||||
if let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first {
|
||||
if let status {
|
||||
result.status = status
|
||||
}
|
||||
if let taskIdentifier {
|
||||
result.sessionTaskIdentifier = taskIdentifier
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func setMetadataSessionInWaitDownload(ocId: String, selector: String) -> tableMetadata? {
|
||||
|
||||
var metadata: tableMetadata?
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
try realm.write {
|
||||
if let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first {
|
||||
result.session = NextcloudKit.shared.nkCommonInstance.sessionIdentifierDownload
|
||||
result.sessionError = ""
|
||||
result.sessionSelector = selector
|
||||
result.status = NCGlobal.shared.metadataStatusWaitDownload
|
||||
metadata = tableMetadata(value: result)
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
|
||||
}
|
||||
|
||||
return metadata
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func setMetadataStatus(ocId: String, status: Int) -> tableMetadata? {
|
||||
|
||||
|
@ -629,9 +711,10 @@ extension NCManageDatabase {
|
|||
do {
|
||||
let realm = try Realm()
|
||||
try realm.write {
|
||||
let result = realm.objects(tableMetadata.self).filter("account == %@ AND ocId == %@", account, ocId).first
|
||||
result?.isFlaggedAsLivePhotoByServer = true
|
||||
result?.livePhotoFile = livePhotoFile
|
||||
if let result = realm.objects(tableMetadata.self).filter("account == %@ AND ocId == %@", account, ocId).first {
|
||||
result.isFlaggedAsLivePhotoByServer = true
|
||||
result.livePhotoFile = livePhotoFile
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
|
||||
|
@ -724,6 +807,19 @@ extension NCManageDatabase {
|
|||
return []
|
||||
}
|
||||
|
||||
func getMetadatas(predicate: NSPredicate, sorted: String, ascending: Bool = false) -> [tableMetadata]? {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
let results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
|
||||
return Array(results.map { tableMetadata.init(value: $0) })
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getResultsMetadatas(predicate: NSPredicate, sorted: String? = nil, ascending: Bool = false) -> Results<tableMetadata>? {
|
||||
|
||||
do {
|
||||
|
@ -740,6 +836,18 @@ extension NCManageDatabase {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getResultsMetadatas(predicate: NSPredicate, sorted: [RealmSwift.SortDescriptor]) -> Results<tableMetadata>? {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
return realm.objects(tableMetadata.self).filter(predicate).sorted(by: sorted)
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getResultMetadata(predicate: NSPredicate) -> tableMetadata? {
|
||||
|
||||
do {
|
||||
|
@ -1007,7 +1115,7 @@ extension NCManageDatabase {
|
|||
do {
|
||||
let realm = try Realm()
|
||||
realm.refresh()
|
||||
return realm.objects(tableMetadata.self).filter(NSPredicate(format: "status == %i || status == %i", NCGlobal.shared.metadataStatusInUpload, NCGlobal.shared.metadataStatusUploading)).count
|
||||
return realm.objects(tableMetadata.self).filter(NSPredicate(format: "status == %i", NCGlobal.shared.metadataStatusUploading)).count
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
}
|
||||
|
@ -1067,24 +1175,6 @@ extension NCManageDatabase {
|
|||
return nil
|
||||
}
|
||||
|
||||
func clearErrorCodeMetadatas(metadatas: Results<tableMetadata>?) {
|
||||
|
||||
guard let metadatas else { return }
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
try realm.write {
|
||||
for metadata in metadatas {
|
||||
metadata.errorCode = 0
|
||||
metadata.errorCodeCounter = 0
|
||||
metadata.errorCodeDate = nil
|
||||
}
|
||||
}
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func updateMetadatas(_ metadatas: [tableMetadata], predicate: NSPredicate) -> (metadatasChangedCount: Int, metadatasChanged: Bool) {
|
||||
|
||||
|
@ -1097,7 +1187,7 @@ extension NCManageDatabase {
|
|||
let results = realm.objects(tableMetadata.self).filter(predicate)
|
||||
metadatasChangedCount = metadatas.count - results.count
|
||||
for metadata in metadatas {
|
||||
if let result = results.filter({ $0.ocId == metadata.ocId }).first,
|
||||
if let result = results.first(where: { $0.ocId == metadata.ocId }),
|
||||
metadata.isEqual(result) { } else {
|
||||
metadatasChanged = true
|
||||
break
|
||||
|
@ -1116,4 +1206,37 @@ extension NCManageDatabase {
|
|||
|
||||
return (metadatasChangedCount, metadatasChanged)
|
||||
}
|
||||
|
||||
func replaceMetadata(_ metadatas: [tableMetadata], predicate: NSPredicate) {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
try realm.write {
|
||||
let results = realm.objects(tableMetadata.self).filter(predicate)
|
||||
realm.delete(results)
|
||||
for metadata in metadatas {
|
||||
if results.where({ $0.ocId == metadata.ocId }).isEmpty {
|
||||
realm.add(tableMetadata(value: metadata), update: .modified)
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func getMediaMetadatas(predicate: NSPredicate) -> ThreadSafeArray<tableMetadata>? {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
let results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: "date", ascending: false)
|
||||
return ThreadSafeArray(results.map { tableMetadata.init(value: $0) })
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
//
|
||||
// NCManageDatabase+SecurityGuard.swift
|
||||
// Nextcloud
|
||||
//
|
||||
// Created by Marino Faggiana on 17/01/24.
|
||||
// Copyright © 2024 Marino Faggiana. All rights reserved.
|
||||
//
|
||||
// Author Marino Faggiana <marino.faggiana@nextcloud.com>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RealmSwift
|
||||
import NextcloudKit
|
||||
|
||||
class TableSecurityGuardDiagnostics: Object {
|
||||
|
||||
@Persisted var account = ""
|
||||
@Persisted(primaryKey: true) var primaryKey = ""
|
||||
@Persisted var issue: String = ""
|
||||
@Persisted var error: String?
|
||||
@Persisted var counter: Int = 0
|
||||
@Persisted var oldest: TimeInterval
|
||||
@Persisted var id: ObjectId
|
||||
|
||||
convenience init(account: String, issue: String, error: String?, date: Date) {
|
||||
self.init()
|
||||
|
||||
self.account = account
|
||||
self.primaryKey = account + issue + (error ?? "")
|
||||
self.issue = issue
|
||||
self.error = error
|
||||
self.counter = 1
|
||||
self.oldest = date.timeIntervalSince1970
|
||||
}
|
||||
}
|
||||
|
||||
extension NCManageDatabase {
|
||||
|
||||
func addDiagnostic(account: String, issue: String, error: String? = nil) {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
try realm.write {
|
||||
let primaryKey = account + issue + (error ?? "")
|
||||
if let result = realm.object(ofType: TableSecurityGuardDiagnostics.self, forPrimaryKey: primaryKey) {
|
||||
result.counter += 1
|
||||
result.oldest = Date().timeIntervalSince1970
|
||||
} else {
|
||||
let table = TableSecurityGuardDiagnostics(account: account, issue: issue, error: error, date: Date())
|
||||
realm.add(table)
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func existsDiagnostics(account: String) -> Bool {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
let results = realm.objects(TableSecurityGuardDiagnostics.self).where({
|
||||
$0.account == account
|
||||
})
|
||||
if !results.isEmpty { return true }
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func getDiagnostics(account: String, issue: String) -> Results<TableSecurityGuardDiagnostics>? {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
let results = realm.objects(TableSecurityGuardDiagnostics.self).where({
|
||||
$0.account == account && $0.issue == issue
|
||||
})
|
||||
return results
|
||||
} catch let error as NSError {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteDiagnostics(account: String, ids: [ObjectId]) {
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
try realm.write {
|
||||
let results = realm.objects(TableSecurityGuardDiagnostics.self).where({
|
||||
$0.account == account
|
||||
})
|
||||
for result in results where ids.contains(result.id) {
|
||||
realm.delete(result)
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -155,8 +155,9 @@ extension NCManageDatabase {
|
|||
do {
|
||||
let realm = try Realm()
|
||||
try realm.write {
|
||||
let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId)
|
||||
realm.delete(result)
|
||||
if let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first {
|
||||
realm.delete(result)
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
|
||||
|
|
|
@ -86,13 +86,13 @@ class NCManageDatabase: NSObject {
|
|||
tableE2eMetadata.self,
|
||||
tableE2eUsers.self,
|
||||
tableE2eCounter.self,
|
||||
tableE2eUsersFiledrop.self,
|
||||
tableShare.self,
|
||||
tableChunk.self,
|
||||
tableAvatar.self,
|
||||
tableDashboardWidget.self,
|
||||
tableDashboardWidgetButton.self,
|
||||
NCDBLayoutForView.self]
|
||||
NCDBLayoutForView.self,
|
||||
TableSecurityGuardDiagnostics.self]
|
||||
)
|
||||
|
||||
} else {
|
||||
|
@ -235,6 +235,7 @@ class NCManageDatabase: NSObject {
|
|||
self.clearTable(tableMetadata.self, account: account)
|
||||
self.clearTable(tablePhotoLibrary.self, account: account)
|
||||
self.clearTable(tableShare.self, account: account)
|
||||
self.clearTable(TableSecurityGuardDiagnostics.self, account: account)
|
||||
self.clearTable(tableTag.self, account: account)
|
||||
self.clearTable(tableTip.self)
|
||||
self.clearTable(tableTrash.self, account: account)
|
||||
|
@ -250,7 +251,6 @@ class NCManageDatabase: NSObject {
|
|||
self.clearTable(tableE2eMetadata.self, account: account)
|
||||
self.clearTable(tableE2eUsers.self, account: account)
|
||||
self.clearTable(tableE2eCounter.self, account: account)
|
||||
self.clearTable(tableE2eUsersFiledrop.self, account: account)
|
||||
}
|
||||
|
||||
@objc func removeDB() {
|
||||
|
|
|
@ -115,6 +115,9 @@ class NCCapabilitiesViewOO: ObservableObject {
|
|||
if let image = UIImage(systemName: "person.2") {
|
||||
capabililies.append(Capability(text: "Group folders", image: image, resize: false, available: NCGlobal.shared.capabilityGroupfoldersEnabled))
|
||||
}
|
||||
if let image = UIImage(systemName: "shield") {
|
||||
capabililies.append(Capability(text: "Security Guard Diagnostics", image: image, resize: false, available: NCGlobal.shared.capabilitySecurityGuardDiagnostics))
|
||||
}
|
||||
|
||||
homeServer = utilityFileSystem.getHomeServer(urlBase: activeAccount.urlBase, userId: activeAccount.userId) + "/"
|
||||
}
|
||||
|
|
|
@ -31,6 +31,12 @@ extension String {
|
|||
return self.components(separatedBy: CharacterSet.alphanumerics.inverted).joined().lowercased()
|
||||
}
|
||||
|
||||
var isNumber: Bool {
|
||||
return self.allSatisfy { character in
|
||||
character.isNumber
|
||||
}
|
||||
}
|
||||
|
||||
public var uppercaseInitials: String? {
|
||||
let initials = self.components(separatedBy: .whitespaces)
|
||||
.reduce("", {
|
||||
|
|
|
@ -38,7 +38,6 @@ extension UIAlertController {
|
|||
guard let fileNameFolder = alertController.textFields?.first?.text else { return }
|
||||
if markE2ee {
|
||||
Task {
|
||||
|
||||
let createFolderResults = await NextcloudKit.shared.createFolder(serverUrlFileName: serverUrl + "/" + fileNameFolder)
|
||||
if createFolderResults.error == .success {
|
||||
let error = await NCNetworkingE2EEMarkFolder().markFolderE2ee(account: urlBase.account, fileName: fileNameFolder, serverUrl: serverUrl, userId: urlBase.userId)
|
||||
|
|
|
@ -30,7 +30,7 @@ extension UINavigationController {
|
|||
return self.visibleViewController!.topMostViewController()
|
||||
}
|
||||
|
||||
func setFileAppreance() {
|
||||
func setNavigationBarAppearance() {
|
||||
|
||||
navigationBar.tintColor = .systemBlue
|
||||
|
||||
|
@ -39,7 +39,6 @@ extension UINavigationController {
|
|||
|
||||
standardAppearance.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.label]
|
||||
standardAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.label]
|
||||
standardAppearance.backgroundColor = .systemGray6
|
||||
navigationBar.standardAppearance = standardAppearance
|
||||
|
||||
let scrollEdgeAppearance = UINavigationBarAppearance()
|
||||
|
|
|
@ -44,12 +44,16 @@ class NCFavorite: NCCollectionViewCommon {
|
|||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
navigationController?.setFileAppreance()
|
||||
if dataSource.metadatas.isEmpty {
|
||||
reloadDataSource()
|
||||
}
|
||||
reloadDataSourceNetwork()
|
||||
}
|
||||
|
||||
// MARK: - DataSource + NC Endpoint
|
||||
|
||||
override func queryDB(isForced: Bool) {
|
||||
override func queryDB() {
|
||||
super.queryDB()
|
||||
|
||||
var metadatas: [tableMetadata] = []
|
||||
|
||||
|
@ -70,37 +74,20 @@ class NCFavorite: NCCollectionViewCommon {
|
|||
searchResults: self.searchResults)
|
||||
}
|
||||
|
||||
override func reloadDataSource(isForced: Bool = true) {
|
||||
super.reloadDataSource()
|
||||
|
||||
DispatchQueue.global().async {
|
||||
self.queryDB(isForced: isForced)
|
||||
DispatchQueue.main.async {
|
||||
self.refreshControl.endRefreshing()
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func reloadDataSourceNetwork(isForced: Bool = false) {
|
||||
super.reloadDataSourceNetwork(isForced: isForced)
|
||||
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Reload data source network favorite forced \(isForced)")
|
||||
|
||||
isReloadDataSourceNetworkInProgress = true
|
||||
collectionView?.reloadData()
|
||||
override func reloadDataSourceNetwork() {
|
||||
super.reloadDataSourceNetwork()
|
||||
|
||||
NextcloudKit.shared.listingFavorites(showHiddenFiles: NCKeychain().showHiddenFiles,
|
||||
options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { account, files, _, error in
|
||||
|
||||
self.isReloadDataSourceNetworkInProgress = false
|
||||
if error == .success {
|
||||
NCManageDatabase.shared.convertFilesToMetadatas(files, useMetadataFolder: false) { _, _, metadatas in
|
||||
NCManageDatabase.shared.updateMetadatasFavorite(account: account, metadatas: metadatas)
|
||||
self.reloadDataSource()
|
||||
}
|
||||
} else {
|
||||
self.reloadDataSource(withQueryDB: false)
|
||||
}
|
||||
self.reloadDataSource()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EFX-fO-Oip">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EFX-fO-Oip">
|
||||
<device id="retina5_9" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
@ -17,7 +17,7 @@
|
|||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="Zaz-Cl-qpZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="862"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="fF1-wd-0xN">
|
||||
<size key="itemSize" width="0.0" height="0.0"/>
|
||||
|
@ -37,7 +37,7 @@
|
|||
<constraints>
|
||||
<constraint firstItem="Zaz-Cl-qpZ" firstAttribute="leading" secondItem="Meh-VD-wWh" secondAttribute="leading" id="1bp-sm-u0X"/>
|
||||
<constraint firstItem="Meh-VD-wWh" firstAttribute="trailing" secondItem="Zaz-Cl-qpZ" secondAttribute="trailing" id="aNd-UL-hmu"/>
|
||||
<constraint firstItem="Meh-VD-wWh" firstAttribute="bottom" secondItem="Zaz-Cl-qpZ" secondAttribute="bottom" constant="-34" id="aNr-tf-2AH"/>
|
||||
<constraint firstItem="Meh-VD-wWh" firstAttribute="bottom" secondItem="Zaz-Cl-qpZ" secondAttribute="bottom" constant="-84" id="aNr-tf-2AH"/>
|
||||
<constraint firstItem="Zaz-Cl-qpZ" firstAttribute="top" secondItem="QEs-gO-Cmp" secondAttribute="top" id="tji-wt-R7s"/>
|
||||
</constraints>
|
||||
</view>
|
||||
|
|
|
@ -71,9 +71,9 @@ class NCFiles: NCCollectionViewCommon {
|
|||
}
|
||||
|
||||
self.titleCurrentFolder = self.getNavigationTitle()
|
||||
self.setNavigationItem()
|
||||
self.setNavigationItems()
|
||||
|
||||
self.reloadDataSource(isForced: false)
|
||||
self.reloadDataSource()
|
||||
self.reloadDataSourceNetwork()
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,11 @@ class NCFiles: NCCollectionViewCommon {
|
|||
titleCurrentFolder = getNavigationTitle()
|
||||
}
|
||||
super.viewWillAppear(animated)
|
||||
navigationController?.setFileAppreance()
|
||||
|
||||
if dataSource.metadatas.isEmpty {
|
||||
reloadDataSource()
|
||||
}
|
||||
reloadDataSourceNetwork()
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
|
@ -97,23 +101,16 @@ class NCFiles: NCCollectionViewCommon {
|
|||
}
|
||||
|
||||
// MARK: - DataSource + NC Endpoint
|
||||
//
|
||||
// forced: do no make the etag of directory test (default)
|
||||
//
|
||||
|
||||
override func queryDB(isForced: Bool) {
|
||||
override func queryDB() {
|
||||
super.queryDB()
|
||||
|
||||
let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl))
|
||||
let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl))
|
||||
let metadataTransfer = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "status != %i AND serverUrl == %@", NCGlobal.shared.metadataStatusNormal, self.serverUrl))
|
||||
if self.metadataFolder == nil {
|
||||
self.metadataFolder = NCManageDatabase.shared.getMetadataFolder(account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId, serverUrl: self.serverUrl)
|
||||
}
|
||||
|
||||
if !isForced, let directory, directory.etag == self.dataSource.directory?.etag, metadataTransfer == nil, self.fileNameBlink == nil, self.fileNameOpen == nil {
|
||||
return
|
||||
}
|
||||
|
||||
self.richWorkspaceText = directory?.richWorkspace
|
||||
self.dataSource = NCDataSource(
|
||||
metadatas: metadatas,
|
||||
|
@ -128,32 +125,20 @@ class NCFiles: NCCollectionViewCommon {
|
|||
searchResults: self.searchResults)
|
||||
}
|
||||
|
||||
override func reloadDataSource(isForced: Bool = true) {
|
||||
super.reloadDataSource()
|
||||
override func reloadDataSource(withQueryDB: Bool = true) {
|
||||
super.reloadDataSource(withQueryDB: withQueryDB)
|
||||
|
||||
DispatchQueue.main.async { self.refreshControl.endRefreshing() }
|
||||
DispatchQueue.global().async {
|
||||
guard !self.isSearchingMode, !self.appDelegate.account.isEmpty, !self.appDelegate.urlBase.isEmpty, !self.serverUrl.isEmpty else { return }
|
||||
|
||||
self.queryDB(isForced: isForced)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.collectionView.reloadData()
|
||||
if !self.dataSource.metadatas.isEmpty {
|
||||
self.blinkCell(fileName: self.fileNameBlink)
|
||||
self.openFile(fileName: self.fileNameOpen)
|
||||
self.fileNameBlink = nil
|
||||
self.fileNameOpen = nil
|
||||
}
|
||||
}
|
||||
if !self.dataSource.metadatas.isEmpty {
|
||||
self.blinkCell(fileName: self.fileNameBlink)
|
||||
self.openFile(fileName: self.fileNameOpen)
|
||||
self.fileNameBlink = nil
|
||||
self.fileNameOpen = nil
|
||||
}
|
||||
}
|
||||
|
||||
override func reloadDataSourceNetwork(isForced: Bool = false) {
|
||||
super.reloadDataSourceNetwork(isForced: isForced)
|
||||
override func reloadDataSourceNetwork() {
|
||||
guard !isSearchingMode else {
|
||||
networkSearch()
|
||||
return
|
||||
return networkSearch()
|
||||
}
|
||||
|
||||
func downloadMetadata(_ metadata: tableMetadata) -> Bool {
|
||||
|
@ -170,29 +155,86 @@ class NCFiles: NCCollectionViewCommon {
|
|||
return false
|
||||
}
|
||||
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Reload data source network files forced \(isForced)")
|
||||
super.reloadDataSourceNetwork()
|
||||
|
||||
isReloadDataSourceNetworkInProgress = true
|
||||
collectionView?.reloadData()
|
||||
|
||||
networkReadFolder(isForced: isForced) { tableDirectory, metadatas, metadatasChangedCount, metadatasChanged, error in
|
||||
networkReadFolder { tableDirectory, metadatas, metadatasChangedCount, metadatasChanged, error in
|
||||
if error == .success {
|
||||
for metadata in metadatas ?? [] where !metadata.directory && downloadMetadata(metadata) {
|
||||
if NCNetworking.shared.downloadQueue.operations.filter({ ($0 as? NCOperationDownload)?.metadata.ocId == metadata.ocId }).isEmpty {
|
||||
NCNetworking.shared.downloadQueue.addOperation(NCOperationDownload(metadata: metadata, selector: NCGlobal.shared.selectorDownloadFile))
|
||||
}
|
||||
}
|
||||
}
|
||||
self.richWorkspaceText = tableDirectory?.richWorkspace
|
||||
|
||||
self.isReloadDataSourceNetworkInProgress = false
|
||||
self.richWorkspaceText = tableDirectory?.richWorkspace
|
||||
|
||||
if metadatasChangedCount != 0 || metadatasChanged || isForced {
|
||||
self.reloadDataSource()
|
||||
} else if self.dataSource.getMetadataSourceForAllSections().isEmpty {
|
||||
DispatchQueue.main.async {
|
||||
self.collectionView.reloadData()
|
||||
if metadatasChangedCount != 0 || metadatasChanged {
|
||||
self.reloadDataSource()
|
||||
} else {
|
||||
self.reloadDataSource(withQueryDB: false)
|
||||
}
|
||||
} else {
|
||||
self.reloadDataSource(withQueryDB: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func networkReadFolder(completion: @escaping(_ tableDirectory: tableDirectory?, _ metadatas: [tableMetadata]?, _ metadatasChangedCount: Int, _ metadatasChanged: Bool, _ error: NKError) -> Void) {
|
||||
|
||||
var tableDirectory: tableDirectory?
|
||||
|
||||
NCNetworking.shared.readFile(serverUrlFileName: serverUrl) { account, metadataFolder, error in
|
||||
|
||||
guard error == .success, let metadataFolder else {
|
||||
return completion(nil, nil, 0, false, error)
|
||||
}
|
||||
tableDirectory = NCManageDatabase.shared.setDirectory(serverUrl: self.serverUrl, richWorkspace: metadataFolder.richWorkspace, account: account)
|
||||
// swiftlint:disable empty_string
|
||||
let forceReplaceMetadatas = tableDirectory?.etag == ""
|
||||
// swiftlint:enable empty_string
|
||||
|
||||
if tableDirectory?.etag != metadataFolder.etag || metadataFolder.e2eEncrypted {
|
||||
NCNetworking.shared.readFolder(serverUrl: self.serverUrl,
|
||||
account: self.appDelegate.account,
|
||||
forceReplaceMetadatas: forceReplaceMetadatas) { _, metadataFolder, metadatas, metadatasChangedCount, metadatasChanged, error in
|
||||
guard error == .success else {
|
||||
return completion(tableDirectory, nil, 0, false, error)
|
||||
}
|
||||
self.metadataFolder = metadataFolder
|
||||
// E2EE
|
||||
if let metadataFolder = metadataFolder,
|
||||
metadataFolder.e2eEncrypted,
|
||||
NCKeychain().isEndToEndEnabled(account: self.appDelegate.account),
|
||||
!NCNetworkingE2EE().isInUpload(account: self.appDelegate.account, serverUrl: self.serverUrl) {
|
||||
let lock = NCManageDatabase.shared.getE2ETokenLock(account: self.appDelegate.account, serverUrl: self.serverUrl)
|
||||
NextcloudKit.shared.getE2EEMetadata(fileId: metadataFolder.ocId, e2eToken: lock?.e2eToken, options: NCNetworkingE2EE().getOptions()) { account, e2eMetadata, signature, _, error in
|
||||
if error == .success, let e2eMetadata = e2eMetadata {
|
||||
let error = NCEndToEndMetadata().decodeMetadata(e2eMetadata, signature: signature, serverUrl: self.serverUrl, account: account, urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId)
|
||||
if error == .success {
|
||||
self.reloadDataSource()
|
||||
} else {
|
||||
// Client Diagnostic
|
||||
NCManageDatabase.shared.addDiagnostic(account: account, issue: NCGlobal.shared.diagnosticIssueE2eeErrors)
|
||||
NCContentPresenter().showError(error: error)
|
||||
}
|
||||
} else if error.errorCode == NCGlobal.shared.errorResourceNotFound {
|
||||
// no metadata found, send a new metadata
|
||||
Task {
|
||||
let serverUrl = metadataFolder.serverUrl + "/" + metadataFolder.fileName
|
||||
let error = await NCNetworkingE2EE().uploadMetadata(account: metadataFolder.account, serverUrl: serverUrl, userId: metadataFolder.userId)
|
||||
if error != .success {
|
||||
NCContentPresenter().showError(error: error)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NCContentPresenter().showError(error: NKError(errorCode: NCGlobal.shared.errorE2EEKeyDecodeMetadata, errorDescription: "_e2e_error_"))
|
||||
}
|
||||
completion(tableDirectory, metadatas, metadatasChangedCount, metadatasChanged, error)
|
||||
}
|
||||
} else {
|
||||
completion(tableDirectory, metadatas, metadatasChangedCount, metadatasChanged, error)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
completion(tableDirectory, nil, 0, false, NKError())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,12 +44,16 @@ class NCGroupfolders: NCCollectionViewCommon {
|
|||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
navigationController?.setFileAppreance()
|
||||
if dataSource.metadatas.isEmpty {
|
||||
reloadDataSource()
|
||||
}
|
||||
reloadDataSourceNetwork()
|
||||
}
|
||||
|
||||
// MARK: - DataSource + NC Endpoint
|
||||
|
||||
override func queryDB(isForced: Bool) {
|
||||
override func queryDB() {
|
||||
super.queryDB()
|
||||
|
||||
var metadatas: [tableMetadata] = []
|
||||
|
||||
|
@ -71,24 +75,8 @@ class NCGroupfolders: NCCollectionViewCommon {
|
|||
searchResults: self.searchResults)
|
||||
}
|
||||
|
||||
override func reloadDataSource(isForced: Bool = true) {
|
||||
super.reloadDataSource()
|
||||
|
||||
self.queryDB(isForced: isForced)
|
||||
DispatchQueue.main.async {
|
||||
self.isReloadDataSourceNetworkInProgress = false
|
||||
self.refreshControl.endRefreshing()
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
override func reloadDataSourceNetwork(isForced: Bool = false) {
|
||||
super.reloadDataSourceNetwork(isForced: isForced)
|
||||
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Reload data source network groupfolders forced \(isForced)")
|
||||
|
||||
isReloadDataSourceNetworkInProgress = true
|
||||
collectionView?.reloadData()
|
||||
override func reloadDataSourceNetwork() {
|
||||
super.reloadDataSourceNetwork()
|
||||
|
||||
let homeServerUrl = utilityFileSystem.getHomeServer(urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId)
|
||||
|
||||
|
@ -112,8 +100,8 @@ class NCGroupfolders: NCCollectionViewCommon {
|
|||
}
|
||||
self.reloadDataSource()
|
||||
}
|
||||
} else if error != .success {
|
||||
self.reloadDataSource()
|
||||
} else {
|
||||
self.reloadDataSource(withQueryDB: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -400,19 +400,20 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
|
|||
|
||||
self.appDelegate.changeAccount(account, userProfile: userProfile)
|
||||
|
||||
if NCKeychain().intro {
|
||||
self.dismiss(animated: true)
|
||||
} else {
|
||||
NCKeychain().intro = true
|
||||
if self.presentingViewController == nil {
|
||||
let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
|
||||
viewController?.modalPresentationStyle = .fullScreen
|
||||
if self.presentingViewController == nil {
|
||||
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() {
|
||||
viewController.modalPresentationStyle = .fullScreen
|
||||
viewController.view.alpha = 0
|
||||
self.appDelegate.window?.rootViewController = viewController
|
||||
self.appDelegate.window?.makeKey()
|
||||
} else {
|
||||
self.dismiss(animated: true)
|
||||
self.appDelegate.window?.makeKeyAndVisible()
|
||||
UIView.animate(withDuration: 0.5) {
|
||||
viewController.view.alpha = 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.dismiss(animated: true)
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert)
|
||||
|
|
|
@ -298,23 +298,18 @@ extension NCLoginWeb: WKNavigationDelegate {
|
|||
|
||||
self.appDelegate.changeAccount(account, userProfile: userProfile)
|
||||
|
||||
if NCKeychain().intro {
|
||||
self.dismiss(animated: true)
|
||||
} else {
|
||||
NCKeychain().intro = true
|
||||
if self.presentingViewController == nil {
|
||||
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() {
|
||||
viewController.modalPresentationStyle = .fullScreen
|
||||
viewController.view.alpha = 0
|
||||
self.appDelegate.window?.rootViewController = viewController
|
||||
self.appDelegate.window?.makeKeyAndVisible()
|
||||
UIView.animate(withDuration: 0.5) {
|
||||
viewController.view.alpha = 1
|
||||
}
|
||||
if self.presentingViewController == nil {
|
||||
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() {
|
||||
viewController.modalPresentationStyle = .fullScreen
|
||||
viewController.view.alpha = 0
|
||||
self.appDelegate.window?.rootViewController = viewController
|
||||
self.appDelegate.window?.makeKeyAndVisible()
|
||||
UIView.animate(withDuration: 0.5) {
|
||||
viewController.view.alpha = 1
|
||||
}
|
||||
} else {
|
||||
self.dismiss(animated: true)
|
||||
}
|
||||
} else {
|
||||
self.dismiss(animated: true)
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
|
@ -48,25 +48,23 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
internal var richWorkspaceText: String?
|
||||
internal var headerMenu: NCSectionHeaderMenu?
|
||||
internal var isSearchingMode: Bool = false
|
||||
|
||||
internal var layoutForView: NCDBLayoutForView?
|
||||
internal var selectableDataSource: [RealmSwiftObject] { dataSource.getMetadataSourceForAllSections() }
|
||||
|
||||
private var autoUploadFileName = ""
|
||||
private var autoUploadDirectory = ""
|
||||
internal var groupByField = "name"
|
||||
internal var providers: [NKSearchProvider]?
|
||||
internal var searchResults: [NKSearchResult]?
|
||||
|
||||
internal var listLayout: NCListLayout!
|
||||
internal var gridLayout: NCGridLayout!
|
||||
|
||||
internal var literalSearch: String?
|
||||
|
||||
internal var isReloadDataSourceNetworkInProgress: Bool = false
|
||||
|
||||
private var pushed: Bool = false
|
||||
internal var timerNotificationCenter: Timer?
|
||||
internal var notificationReloadDataSource: Int = 0
|
||||
internal var notificationReloadDataSourceNetwork: Int = 0
|
||||
|
||||
private var pushed: Bool = false
|
||||
private var tipView: EasyTipView?
|
||||
private var isTransitioning: Bool = false
|
||||
// DECLARE
|
||||
|
@ -129,7 +127,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
collectionView.refreshControl = refreshControl
|
||||
refreshControl.action(for: .valueChanged) { _ in
|
||||
self.dataSource.clearDirectory()
|
||||
self.reloadDataSourceNetwork(isForced: true)
|
||||
NCManageDatabase.shared.cleanEtagDirectory(account: self.appDelegate.account, serverUrl: self.serverUrl)
|
||||
self.reloadDataSourceNetwork()
|
||||
}
|
||||
|
||||
// Empty
|
||||
|
@ -174,14 +173,15 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
collectionView?.collectionViewLayout = gridLayout
|
||||
}
|
||||
|
||||
timerNotificationCenter = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(notificationCenterEvents), userInfo: nil, repeats: true)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(applicationWillResignActive(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationWillResignActive), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(closeRichWorkspaceWebView), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterCloseRichWorkspaceWebView), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(changeStatusFolderE2EE(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(reloadAvatar(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadAvatar), object: nil)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSource(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSource), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSourceNetwork), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSourceNetwork), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSourceNetworkForced(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSourceNetwork(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSourceNetwork), object: nil)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(deleteFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDeleteFile), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(moveFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMoveFile), object: nil)
|
||||
|
@ -196,6 +196,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(uploadStartFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadStartFile), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(uploadedFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(uploadedLivePhoto(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedLivePhoto), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(uploadCancelFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadCancelFile), object: nil)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(triggerProgressTask(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask), object: nil)
|
||||
|
@ -208,12 +209,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
|
||||
navigationController?.navigationBar.prefersLargeTitles = true
|
||||
navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
setNavigationItem()
|
||||
|
||||
reloadDataSource(isForced: false)
|
||||
if !isSearchingMode {
|
||||
reloadDataSourceNetwork()
|
||||
}
|
||||
navigationController?.setNavigationBarAppearance()
|
||||
setNavigationItems()
|
||||
|
||||
// FIXME: iPAD PDF landscape mode iOS 16
|
||||
DispatchQueue.main.async {
|
||||
|
@ -231,16 +228,26 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSource), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSourceNetwork), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced), object: nil)
|
||||
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDeleteFile), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMoveFile), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterCopyFile), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterRenameFile), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterCreateFolder), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterFavoriteFile), object: nil)
|
||||
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadStartFile), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadCancelFile), object: nil)
|
||||
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadStartFile), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedLivePhoto), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadCancelFile), object: nil)
|
||||
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask), object: nil)
|
||||
|
||||
timerNotificationCenter?.invalidate()
|
||||
pushed = false
|
||||
|
||||
// REQUEST
|
||||
|
@ -276,6 +283,14 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
|
||||
// MARK: - NotificationCenter
|
||||
|
||||
@objc func notificationCenterEvents() {
|
||||
if notificationReloadDataSource > 0 {
|
||||
print("notificationReloadDataSource: \(notificationReloadDataSource)")
|
||||
reloadDataSource()
|
||||
notificationReloadDataSource = 0
|
||||
}
|
||||
}
|
||||
|
||||
@objc func applicationWillResignActive(_ notification: NSNotification) {
|
||||
self.refreshControl.endRefreshing()
|
||||
}
|
||||
|
@ -290,7 +305,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
let error = userInfo["error"] as? NKError,
|
||||
error.errorCode != NCGlobal.shared.errorNotModified else { return }
|
||||
|
||||
setNavigationItem()
|
||||
setNavigationItems()
|
||||
}
|
||||
|
||||
@objc func changeTheming() {
|
||||
|
@ -298,18 +313,17 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
}
|
||||
|
||||
@objc func reloadDataSource(_ notification: NSNotification) {
|
||||
reloadDataSource()
|
||||
notificationReloadDataSource += 1
|
||||
}
|
||||
|
||||
@objc func reloadDataSourceNetworkForced(_ notification: NSNotification) {
|
||||
|
||||
@objc func reloadDataSourceNetwork(_ notification: NSNotification) {
|
||||
if !isSearchingMode {
|
||||
reloadDataSourceNetwork(isForced: true)
|
||||
reloadDataSourceNetwork()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func changeStatusFolderE2EE(_ notification: NSNotification) {
|
||||
reloadDataSource()
|
||||
notificationReloadDataSource += 1
|
||||
}
|
||||
|
||||
@objc func closeRichWorkspaceWebView() {
|
||||
|
@ -321,8 +335,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
guard let userInfo = notification.userInfo as NSDictionary?,
|
||||
let error = userInfo["error"] as? NKError else { return }
|
||||
|
||||
self.queryDB(isForced: true)
|
||||
self.collectionView?.reloadData()
|
||||
notificationReloadDataSource += 1
|
||||
|
||||
if error != .success {
|
||||
NCContentPresenter().showError(error: error)
|
||||
|
@ -350,7 +363,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
account == appDelegate.account
|
||||
else { return }
|
||||
|
||||
reloadDataSourceNetwork(isForced: true)
|
||||
reloadDataSourceNetwork()
|
||||
}
|
||||
|
||||
@objc func createFolder(_ notification: NSNotification) {
|
||||
|
@ -364,29 +377,25 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
let withPush = userInfo["withPush"] as? Bool
|
||||
else { return }
|
||||
|
||||
if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
|
||||
reloadDataSource()
|
||||
if withPush {
|
||||
pushMetadata(metadata)
|
||||
}
|
||||
notificationReloadDataSource += 1
|
||||
|
||||
if withPush, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
|
||||
pushMetadata(metadata)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func favoriteFile(_ notification: NSNotification) {
|
||||
|
||||
guard let userInfo = notification.userInfo as NSDictionary?,
|
||||
let ocId = userInfo["ocId"] as? String,
|
||||
let serverUrl = userInfo["serverUrl"] as? String,
|
||||
serverUrl == self.serverUrl
|
||||
else {
|
||||
if self is NCFavorite {
|
||||
reloadDataSource()
|
||||
}
|
||||
return
|
||||
if self is NCFavorite {
|
||||
return notificationReloadDataSource += 1
|
||||
}
|
||||
|
||||
dataSource.reloadMetadata(ocId: ocId)
|
||||
collectionView?.reloadData()
|
||||
guard let userInfo = notification.userInfo as NSDictionary?,
|
||||
let serverUrl = userInfo["serverUrl"] as? String,
|
||||
serverUrl == self.serverUrl
|
||||
else { return }
|
||||
|
||||
notificationReloadDataSource += 1
|
||||
}
|
||||
|
||||
@objc func downloadStartFile(_ notification: NSNotification) {
|
||||
|
@ -398,7 +407,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
account == appDelegate.account
|
||||
else { return }
|
||||
|
||||
reloadDataSource()
|
||||
self.notificationReloadDataSource += 1
|
||||
}
|
||||
|
||||
@objc func downloadedFile(_ notification: NSNotification) {
|
||||
|
@ -407,32 +416,27 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
let serverUrl = userInfo["serverUrl"] as? String,
|
||||
serverUrl == self.serverUrl,
|
||||
let account = userInfo["account"] as? String,
|
||||
account == appDelegate.account
|
||||
account == appDelegate.account,
|
||||
let error = userInfo["error"] as? NKError
|
||||
else { return }
|
||||
|
||||
reloadDataSource()
|
||||
if error != .success {
|
||||
NCContentPresenter().showError(error: error)
|
||||
}
|
||||
|
||||
notificationReloadDataSource += 1
|
||||
}
|
||||
|
||||
@objc func downloadCancelFile(_ notification: NSNotification) {
|
||||
|
||||
guard let userInfo = notification.userInfo as NSDictionary?,
|
||||
let ocId = userInfo["ocId"] as? String,
|
||||
let serverUrl = userInfo["serverUrl"] as? String,
|
||||
serverUrl == self.serverUrl,
|
||||
let account = userInfo["account"] as? String,
|
||||
account == appDelegate.account
|
||||
else { return }
|
||||
|
||||
let (indexPath, sameSections) = dataSource.reloadMetadata(ocId: ocId)
|
||||
if let indexPath = indexPath {
|
||||
if sameSections && (indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section)) {
|
||||
collectionView?.reloadItems(at: [indexPath])
|
||||
} else {
|
||||
self.collectionView?.reloadData()
|
||||
}
|
||||
} else {
|
||||
reloadDataSource()
|
||||
}
|
||||
notificationReloadDataSource += 1
|
||||
}
|
||||
|
||||
@objc func uploadStartFile(_ notification: NSNotification) {
|
||||
|
@ -440,19 +444,19 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
guard let userInfo = notification.userInfo as NSDictionary?,
|
||||
let ocId = userInfo["ocId"] as? String,
|
||||
let serverUrl = userInfo["serverUrl"] as? String,
|
||||
let account = userInfo["account"] as? String
|
||||
let account = userInfo["account"] as? String,
|
||||
!isSearchingMode,
|
||||
let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId)
|
||||
else { return }
|
||||
|
||||
guard !isSearchingMode, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return }
|
||||
|
||||
// Header view trasfer
|
||||
if metadata.isTransferInForeground {
|
||||
NCNetworking.shared.transferInForegorund = NCNetworking.TransferInForegorund(ocId: ocId, progress: 0)
|
||||
self.collectionView?.reloadData()
|
||||
DispatchQueue.main.async { self.collectionView?.reloadData() }
|
||||
}
|
||||
|
||||
if serverUrl == self.serverUrl, account == appDelegate.account {
|
||||
reloadDataSource()
|
||||
notificationReloadDataSource += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -466,14 +470,26 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
|
||||
if ocIdTemp == NCNetworking.shared.transferInForegorund?.ocId {
|
||||
NCNetworking.shared.transferInForegorund = nil
|
||||
self.collectionView?.reloadData()
|
||||
DispatchQueue.main.async { self.collectionView?.reloadData() }
|
||||
}
|
||||
|
||||
if account == appDelegate.account, serverUrl == self.serverUrl {
|
||||
reloadDataSource()
|
||||
notificationReloadDataSource += 1
|
||||
}
|
||||
}
|
||||
|
||||
@objc func uploadedLivePhoto(_ notification: NSNotification) {
|
||||
|
||||
guard let userInfo = notification.userInfo as NSDictionary?,
|
||||
let serverUrl = userInfo["serverUrl"] as? String,
|
||||
serverUrl == self.serverUrl,
|
||||
let account = userInfo["account"] as? String,
|
||||
account == appDelegate.account
|
||||
else { return }
|
||||
|
||||
notificationReloadDataSource += 1
|
||||
}
|
||||
|
||||
@objc func uploadCancelFile(_ notification: NSNotification) {
|
||||
|
||||
guard let userInfo = notification.userInfo as NSDictionary?,
|
||||
|
@ -484,11 +500,11 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
|
||||
if ocId == NCNetworking.shared.transferInForegorund?.ocId {
|
||||
NCNetworking.shared.transferInForegorund = nil
|
||||
self.collectionView?.reloadData()
|
||||
DispatchQueue.main.async { self.collectionView?.reloadData() }
|
||||
}
|
||||
|
||||
if account == appDelegate.account, serverUrl == self.serverUrl {
|
||||
reloadDataSource()
|
||||
notificationReloadDataSource += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -504,22 +520,22 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
let chunk: Int = userInfo["chunk"] as? Int ?? 0
|
||||
let e2eEncrypted: Bool = userInfo["e2eEncrypted"] as? Bool ?? false
|
||||
|
||||
// Header Transfer
|
||||
if headerMenuTransferView && (chunk > 0 || e2eEncrypted) {
|
||||
if NCNetworking.shared.transferInForegorund?.ocId == ocId {
|
||||
NCNetworking.shared.transferInForegorund?.progress = progressNumber.floatValue
|
||||
} else {
|
||||
NCNetworking.shared.transferInForegorund = NCNetworking.TransferInForegorund(ocId: ocId, progress: progressNumber.floatValue)
|
||||
collectionView.reloadData()
|
||||
if self.headerMenuTransferView && (chunk > 0 || e2eEncrypted) {
|
||||
DispatchQueue.main.async {
|
||||
if NCNetworking.shared.transferInForegorund?.ocId == ocId {
|
||||
NCNetworking.shared.transferInForegorund?.progress = progressNumber.floatValue
|
||||
} else {
|
||||
NCNetworking.shared.transferInForegorund = NCNetworking.TransferInForegorund(ocId: ocId, progress: progressNumber.floatValue)
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
self.headerMenu?.progressTransfer.progress = progressNumber.floatValue
|
||||
}
|
||||
self.headerMenu?.progressTransfer.progress = progressNumber.floatValue
|
||||
}
|
||||
|
||||
let status = userInfo["status"] as? Int ?? NCGlobal.shared.metadataStatusNormal
|
||||
|
||||
if let (indexPath, _) = self.dataSource.getIndexPathMetadata(ocId: ocId) as? (IndexPath, NCMetadataForSection?),
|
||||
let cell = collectionView?.cellForItem(at: indexPath) {
|
||||
if let cell = cell as? NCCellProtocol {
|
||||
} else {
|
||||
guard let indexPath = self.dataSource.getIndexPathMetadata(ocId: ocId).indexPath else { return }
|
||||
let status = userInfo["status"] as? Int ?? NCGlobal.shared.metadataStatusNormal
|
||||
DispatchQueue.main.async {
|
||||
guard let cell = self.collectionView?.cellForItem(at: indexPath),
|
||||
let cell = cell as? NCCellProtocol else { return }
|
||||
if progressNumber.floatValue == 1 && !(cell is NCTransferCell) {
|
||||
cell.fileProgressView?.isHidden = true
|
||||
cell.fileProgressView?.progress = .zero
|
||||
|
@ -533,13 +549,13 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
cell.fileProgressView?.isHidden = false
|
||||
cell.fileProgressView?.progress = progressNumber.floatValue
|
||||
cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCImageCache.images.buttonStop)
|
||||
if status == NCGlobal.shared.metadataStatusInDownload {
|
||||
cell.fileInfoLabel?.text = utilityFileSystem.transformedSize(totalBytesExpected) + " - ↓ " + utilityFileSystem.transformedSize(totalBytes)
|
||||
} else if status == NCGlobal.shared.metadataStatusInUpload {
|
||||
if status == NCGlobal.shared.metadataStatusDownloading {
|
||||
cell.fileInfoLabel?.text = self.utilityFileSystem.transformedSize(totalBytesExpected) + " - ↓ " + self.utilityFileSystem.transformedSize(totalBytes)
|
||||
} else if status == NCGlobal.shared.metadataStatusUploading {
|
||||
if totalBytes > 0 {
|
||||
cell.fileInfoLabel?.text = utilityFileSystem.transformedSize(totalBytesExpected) + " - ↑ " + utilityFileSystem.transformedSize(totalBytes)
|
||||
cell.fileInfoLabel?.text = self.utilityFileSystem.transformedSize(totalBytesExpected) + " - ↑ " + self.utilityFileSystem.transformedSize(totalBytes)
|
||||
} else {
|
||||
cell.fileInfoLabel?.text = utilityFileSystem.transformedSize(totalBytesExpected) + " - ↑ …"
|
||||
cell.fileInfoLabel?.text = self.utilityFileSystem.transformedSize(totalBytesExpected) + " - ↑ …"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -550,7 +566,6 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
// MARK: - Tip
|
||||
|
||||
func showTip() {
|
||||
|
||||
if self is NCFiles, self.view.window != nil, !NCBrandOptions.shared.disable_multiaccount, !NCBrandOptions.shared.disable_manage_account, self.serverUrl == utilityFileSystem.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId), let view = self.navigationItem.leftBarButtonItem?.customView {
|
||||
if !NCManageDatabase.shared.tipExists(NCGlobal.shared.tipNCCollectionViewCommonAccountRequest), !NCManageDatabase.shared.getAllAccountOrderAlias().isEmpty {
|
||||
self.tipView?.show(forView: view)
|
||||
|
@ -560,7 +575,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
|
||||
// MARK: - Layout
|
||||
|
||||
func setNavigationItem() {
|
||||
func setNavigationItems() {
|
||||
|
||||
self.setNavigationRightItems()
|
||||
navigationItem.title = titleCurrentFolder
|
||||
|
@ -579,20 +594,6 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
let button = UIButton(type: .custom)
|
||||
button.setImage(image, for: .normal)
|
||||
|
||||
if serverUrl == utilityFileSystem.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) {
|
||||
|
||||
var titleButton = " "
|
||||
|
||||
if getNavigationTitle() == activeAccount?.alias {
|
||||
titleButton = ""
|
||||
} else {
|
||||
titleButton += activeAccount?.displayName ?? ""
|
||||
}
|
||||
|
||||
button.setTitle(titleButton, for: .normal)
|
||||
button.setTitleColor(.systemBlue, for: .normal)
|
||||
}
|
||||
|
||||
button.semanticContentAttribute = .forceLeftToRight
|
||||
button.sizeToFit()
|
||||
button.action(for: .touchUpInside) { _ in
|
||||
|
@ -622,13 +623,14 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
self.dismissTip()
|
||||
}
|
||||
}
|
||||
|
||||
navigationItem.setLeftBarButton(UIBarButtonItem(customView: button), animated: true)
|
||||
navigationItem.leftItemsSupplementBackButton = true
|
||||
if titlePreviusFolder == nil {
|
||||
navigationController?.navigationBar.topItem?.title = getNavigationTitle()
|
||||
} else {
|
||||
|
||||
if titlePreviusFolder != nil {
|
||||
navigationController?.navigationBar.topItem?.title = titlePreviusFolder
|
||||
}
|
||||
|
||||
navigationItem.title = titleCurrentFolder
|
||||
}
|
||||
|
||||
|
@ -699,12 +701,10 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
|
||||
DispatchQueue.global().async {
|
||||
NCNetworking.shared.cancelUnifiedSearchFiles()
|
||||
|
||||
self.isSearchingMode = false
|
||||
self.literalSearch = ""
|
||||
self.providers?.removeAll()
|
||||
self.dataSource.clearDataSource()
|
||||
|
||||
self.reloadDataSource()
|
||||
}
|
||||
}
|
||||
|
@ -883,10 +883,10 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
|
||||
// MARK: - DataSource + NC Endpoint
|
||||
|
||||
func queryDB(isForced: Bool) { }
|
||||
func queryDB() { }
|
||||
|
||||
@objc func reloadDataSource(isForced: Bool = true) {
|
||||
guard !appDelegate.account.isEmpty else { return }
|
||||
@objc func reloadDataSource(withQueryDB: Bool = true) {
|
||||
guard !appDelegate.account.isEmpty, !self.isSearchingMode else { return }
|
||||
|
||||
// get auto upload folder
|
||||
autoUploadFileName = NCManageDatabase.shared.getAccountAutoUploadFileName()
|
||||
|
@ -901,16 +901,26 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
} else {
|
||||
groupByField = "name"
|
||||
}
|
||||
|
||||
DispatchQueue.global().async {
|
||||
if withQueryDB { self.queryDB() }
|
||||
DispatchQueue.main.async {
|
||||
self.isReloadDataSourceNetworkInProgress = false
|
||||
self.refreshControl.endRefreshing()
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func reloadDataSourceNetwork(isForced: Bool = false) { }
|
||||
@objc func reloadDataSourceNetwork() {
|
||||
|
||||
isReloadDataSourceNetworkInProgress = true
|
||||
collectionView?.reloadData()
|
||||
}
|
||||
|
||||
@objc func networkSearch() {
|
||||
guard !appDelegate.account.isEmpty, let literalSearch = literalSearch, !literalSearch.isEmpty
|
||||
else {
|
||||
self.refreshControl.endRefreshing()
|
||||
return
|
||||
}
|
||||
else { return self.refreshControl.endRefreshing() }
|
||||
|
||||
isReloadDataSourceNetworkInProgress = true
|
||||
self.dataSource.clearDataSource()
|
||||
|
@ -982,65 +992,6 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
|
|||
}
|
||||
}
|
||||
|
||||
@objc func networkReadFolder(isForced: Bool, completion: @escaping(_ tableDirectory: tableDirectory?, _ metadatas: [tableMetadata]?, _ metadatasChangedCount: Int, _ metadatasChanged: Bool, _ error: NKError) -> Void) {
|
||||
|
||||
var tableDirectory: tableDirectory?
|
||||
|
||||
NCNetworking.shared.readFile(serverUrlFileName: serverUrl) { account, metadataFolder, error in
|
||||
guard error == .success else {
|
||||
completion(nil, nil, 0, false, error)
|
||||
return
|
||||
}
|
||||
|
||||
if let metadataFolder = metadataFolder {
|
||||
tableDirectory = NCManageDatabase.shared.setDirectory(serverUrl: self.serverUrl, richWorkspace: metadataFolder.richWorkspace, account: account)
|
||||
}
|
||||
|
||||
if isForced || tableDirectory?.etag != metadataFolder?.etag || metadataFolder?.e2eEncrypted ?? true {
|
||||
NCNetworking.shared.readFolder(serverUrl: self.serverUrl, account: self.appDelegate.account) { _, metadataFolder, metadatas, metadatasChangedCount, metadatasChanged, error in
|
||||
guard error == .success else {
|
||||
completion(tableDirectory, nil, 0, false, error)
|
||||
return
|
||||
}
|
||||
self.metadataFolder = metadataFolder
|
||||
// E2EE
|
||||
if let metadataFolder = metadataFolder,
|
||||
metadataFolder.e2eEncrypted,
|
||||
NCKeychain().isEndToEndEnabled(account: self.appDelegate.account),
|
||||
!NCNetworkingE2EE().isInUpload(account: self.appDelegate.account, serverUrl: self.serverUrl) {
|
||||
let lock = NCManageDatabase.shared.getE2ETokenLock(account: self.appDelegate.account, serverUrl: self.serverUrl)
|
||||
NextcloudKit.shared.getE2EEMetadata(fileId: metadataFolder.ocId, e2eToken: lock?.e2eToken) { _, e2eMetadata, signature, _, error in
|
||||
if error == .success, let e2eMetadata = e2eMetadata {
|
||||
let error = NCEndToEndMetadata().decodeMetadata(e2eMetadata, signature: signature, serverUrl: self.serverUrl, account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId)
|
||||
if error == .success {
|
||||
self.reloadDataSource()
|
||||
} else {
|
||||
NCContentPresenter().showError(error: error)
|
||||
}
|
||||
} else if error.errorCode == NCGlobal.shared.errorResourceNotFound {
|
||||
// no metadata found, send a new metadata
|
||||
Task {
|
||||
let serverUrl = metadataFolder.serverUrl + "/" + metadataFolder.fileName
|
||||
let error = await NCNetworkingE2EE().uploadMetadata(account: metadataFolder.account, serverUrl: serverUrl, userId: metadataFolder.userId)
|
||||
if error != .success {
|
||||
NCContentPresenter().showError(error: error)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NCContentPresenter().showError(error: NKError(errorCode: NCGlobal.shared.errorE2EEKeyDecodeMetadata, errorDescription: "_e2e_error_"))
|
||||
}
|
||||
completion(tableDirectory, metadatas, metadatasChangedCount, metadatasChanged, error)
|
||||
}
|
||||
} else {
|
||||
completion(tableDirectory, metadatas, metadatasChangedCount, metadatasChanged, error)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
completion(tableDirectory, nil, 0, false, NKError())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Push metadata
|
||||
|
||||
func pushMetadata(_ metadata: tableMetadata) {
|
||||
|
@ -1131,8 +1082,8 @@ extension NCCollectionViewCommon: UICollectionViewDelegate {
|
|||
|
||||
if utilityFileSystem.fileProviderStorageExists(metadata) {
|
||||
NCViewer().view(viewController: self, metadata: metadata, metadatas: [metadata], imageIcon: imageIcon)
|
||||
} else if NextcloudKit.shared.isNetworkReachable() {
|
||||
NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadFileView) { _, _ in }
|
||||
} else if NextcloudKit.shared.isNetworkReachable(), let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: NCGlobal.shared.selectorLoadFileView) {
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: true)
|
||||
} else {
|
||||
let error = NKError(errorCode: NCGlobal.shared.errorOffline, errorDescription: "_go_online_")
|
||||
NCContentPresenter().showInfo(error: error)
|
||||
|
@ -1416,16 +1367,11 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
|
|||
switch metadata.status {
|
||||
case NCGlobal.shared.metadataStatusWaitDownload:
|
||||
cell.fileInfoLabel?.text = utilityFileSystem.transformedSize(metadata.size) + " - " + NSLocalizedString("_status_wait_download_", comment: "")
|
||||
case NCGlobal.shared.metadataStatusInDownload:
|
||||
cell.fileInfoLabel?.text = utilityFileSystem.transformedSize(metadata.size) + " - " + NSLocalizedString("_status_in_download_", comment: "")
|
||||
case NCGlobal.shared.metadataStatusDownloading:
|
||||
cell.fileInfoLabel?.text = utilityFileSystem.transformedSize(metadata.size) + " - ↓ …"
|
||||
case NCGlobal.shared.metadataStatusWaitUpload:
|
||||
cell.fileInfoLabel?.text = utilityFileSystem.transformedSize(metadata.size) + " - " + NSLocalizedString("_status_wait_upload_", comment: "")
|
||||
cell.fileLocalImage?.image = nil
|
||||
case NCGlobal.shared.metadataStatusInUpload:
|
||||
cell.fileInfoLabel?.text = utilityFileSystem.transformedSize(metadata.size) + " - " + NSLocalizedString("_status_in_upload_", comment: "")
|
||||
cell.fileLocalImage?.image = nil
|
||||
case NCGlobal.shared.metadataStatusUploading:
|
||||
cell.fileInfoLabel?.text = utilityFileSystem.transformedSize(metadata.size) + " - ↑ …"
|
||||
cell.fileLocalImage?.image = nil
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22154" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_0" orientation="landscape" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22130"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
|
@ -19,35 +19,35 @@
|
|||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="w2m-Vw-hpd" userLabel="ImageItem">
|
||||
<rect key="frame" x="57" y="43.666666666666664" width="40" height="39.999999999999993"/>
|
||||
<rect key="frame" x="57" y="54" width="40" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="Dpd-Xj-z4U"/>
|
||||
<constraint firstAttribute="width" constant="40" id="v0e-MW-EeE"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="7Q9-Tv-9yo" userLabel="imageStatus">
|
||||
<rect key="frame" x="52" y="73.666666666666671" width="15" height="15"/>
|
||||
<rect key="frame" x="52" y="84" width="15" height="15"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="15" id="f8p-9B-Rgw"/>
|
||||
<constraint firstAttribute="height" constant="15" id="ndy-wW-xdL"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="C4K-Nv-phA" userLabel="imageFavorite">
|
||||
<rect key="frame" x="87" y="38.666666666666664" width="15" height="15"/>
|
||||
<rect key="frame" x="87" y="49" width="15" height="15"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="15" id="hXC-b9-Q2V"/>
|
||||
<constraint firstAttribute="height" constant="15" id="mPH-zc-eH5"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="AyA-hP-r6w" userLabel="imageSelect">
|
||||
<rect key="frame" x="57" y="51" width="25" height="25"/>
|
||||
<rect key="frame" x="10" y="61.666666666666657" width="25" height="25"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="25" id="bIF-gu-6Jj"/>
|
||||
<constraint firstAttribute="height" constant="25" id="nJa-oj-gcQ"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="H4E-G2-C1H" userLabel="imageLocal">
|
||||
<rect key="frame" x="87" y="73.666666666666671" width="15" height="15"/>
|
||||
<rect key="frame" x="87" y="84" width="15" height="15"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="15" id="BEs-Rd-5Ov"/>
|
||||
<constraint firstAttribute="height" constant="15" id="N8h-3R-JpE"/>
|
||||
|
@ -66,7 +66,7 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" alpha="0.29999999999999999" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="o4u-0K-Qpt" userLabel="buttonShare">
|
||||
<rect key="frame" x="537" y="34.666666666666664" width="40" height="57.999999999999993"/>
|
||||
<rect key="frame" x="584" y="45" width="40" height="58"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="58" id="WOg-y5-5UA"/>
|
||||
|
@ -77,14 +77,14 @@
|
|||
</connections>
|
||||
</button>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="jc6-Vg-TaS" userLabel="imageShared">
|
||||
<rect key="frame" x="542" y="48.666666666666664" width="30" height="29.999999999999993"/>
|
||||
<rect key="frame" x="589" y="59" width="30" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="Cvy-nZ-zyD"/>
|
||||
<constraint firstAttribute="width" constant="30" id="jfe-Fg-vA8"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yhy-xd-w5C" userLabel="buttonMore">
|
||||
<rect key="frame" x="582" y="33.666666666666664" width="40" height="59.999999999999993"/>
|
||||
<rect key="frame" x="629" y="44" width="40" height="60"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="40" id="ZgH-mI-l2k"/>
|
||||
<constraint firstAttribute="height" constant="60" id="woC-64-Tyc"/>
|
||||
|
@ -94,17 +94,17 @@
|
|||
</connections>
|
||||
</button>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="dgL-g5-Nkc" userLabel="imageMore">
|
||||
<rect key="frame" x="589.66666666666663" y="51" width="25" height="25"/>
|
||||
<rect key="frame" x="636.66666666666663" y="61.666666666666657" width="25" height="25"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="25" id="05P-NL-pd8"/>
|
||||
<constraint firstAttribute="height" constant="25" id="Jet-eo-x1M"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<progressView hidden="YES" opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="m2p-oJ-j15">
|
||||
<rect key="frame" x="107" y="116" width="425" height="4"/>
|
||||
<rect key="frame" x="107" y="137" width="472" height="4"/>
|
||||
</progressView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Egg-cb-EhZ" userLabel="separator">
|
||||
<rect key="frame" x="97" y="126" width="525" height="1"/>
|
||||
<rect key="frame" x="97" y="147" width="572" height="1"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
|
@ -112,7 +112,7 @@
|
|||
</constraints>
|
||||
</view>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="tag0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qnc-hI-Z9r" customClass="PaddedAndBorderedLabel" customModule="Nextcloud" customModuleProvider="target">
|
||||
<rect key="frame" x="107" y="103.66666666666667" width="26" height="14.333333333333329"/>
|
||||
<rect key="frame" x="107" y="122.66666666666667" width="36" height="16.333333333333329"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" systemColor="systemGrayColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
|
@ -141,7 +141,7 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="tag1" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jUe-8q-VJd" customClass="PaddedAndBorderedLabel" customModule="Nextcloud" customModuleProvider="target">
|
||||
<rect key="frame" x="138" y="103.66666666666667" width="24" height="14.333333333333329"/>
|
||||
<rect key="frame" x="148" y="122.66666666666667" width="34" height="16.333333333333329"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" systemColor="systemGrayColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
|
@ -174,38 +174,38 @@
|
|||
<viewLayoutGuide key="safeArea" id="Gu8-oz-zWa"/>
|
||||
<constraints>
|
||||
<constraint firstItem="jUe-8q-VJd" firstAttribute="centerY" secondItem="qnc-hI-Z9r" secondAttribute="centerY" id="2Z4-Yh-1lR"/>
|
||||
<constraint firstItem="Gu8-oz-zWa" firstAttribute="trailing" secondItem="m2p-oJ-j15" secondAttribute="trailing" constant="90" id="2zI-li-v77"/>
|
||||
<constraint firstAttribute="trailing" secondItem="m2p-oJ-j15" secondAttribute="trailing" constant="90" id="2zI-li-v77"/>
|
||||
<constraint firstItem="H4E-G2-C1H" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="-10" id="6fN-Jc-WID"/>
|
||||
<constraint firstItem="Gu8-oz-zWa" firstAttribute="bottom" secondItem="Egg-cb-EhZ" secondAttribute="bottom" id="81D-sw-EaX"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Egg-cb-EhZ" secondAttribute="bottom" id="81D-sw-EaX"/>
|
||||
<constraint firstItem="AXX-71-9Q6" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="10" id="Bxx-kv-KT3"/>
|
||||
<constraint firstItem="w2m-Vw-hpd" firstAttribute="top" secondItem="C4K-Nv-phA" secondAttribute="bottom" constant="-10" id="DB1-jf-rpE"/>
|
||||
<constraint firstItem="o4u-0K-Qpt" firstAttribute="centerY" secondItem="Gu8-oz-zWa" secondAttribute="centerY" id="HFM-sM-wJr"/>
|
||||
<constraint firstItem="o4u-0K-Qpt" firstAttribute="centerY" secondItem="jxV-Pk-fPt" secondAttribute="centerY" id="HFM-sM-wJr"/>
|
||||
<constraint firstItem="Egg-cb-EhZ" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" id="JCm-UU-Pxu"/>
|
||||
<constraint firstItem="dgL-g5-Nkc" firstAttribute="centerY" secondItem="yhy-xd-w5C" secondAttribute="centerY" id="OMy-Cu-HAx"/>
|
||||
<constraint firstItem="UtT-L6-mgW" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="10" id="PQ8-0b-fLa"/>
|
||||
<constraint firstItem="AyA-hP-r6w" firstAttribute="leading" secondItem="Gu8-oz-zWa" secondAttribute="leading" constant="10" id="RYl-cO-cCN"/>
|
||||
<constraint firstItem="Gu8-oz-zWa" firstAttribute="bottom" secondItem="m2p-oJ-j15" secondAttribute="bottom" constant="7" id="SYv-gc-ahx"/>
|
||||
<constraint firstItem="AyA-hP-r6w" firstAttribute="leading" secondItem="jxV-Pk-fPt" secondAttribute="leading" constant="10" id="RYl-cO-cCN"/>
|
||||
<constraint firstAttribute="bottom" secondItem="m2p-oJ-j15" secondAttribute="bottom" constant="7" id="SYv-gc-ahx"/>
|
||||
<constraint firstItem="C4K-Nv-phA" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="-10" id="Sof-wy-toF"/>
|
||||
<constraint firstItem="Gu8-oz-zWa" firstAttribute="trailing" secondItem="UtT-L6-mgW" secondAttribute="trailing" constant="90" id="Tq4-bB-YMV"/>
|
||||
<constraint firstAttribute="trailing" secondItem="UtT-L6-mgW" secondAttribute="trailing" constant="137" id="Tq4-bB-YMV"/>
|
||||
<constraint firstItem="H4E-G2-C1H" firstAttribute="top" secondItem="w2m-Vw-hpd" secondAttribute="bottom" constant="-10" id="UWI-r9-vcA"/>
|
||||
<constraint firstItem="dgL-g5-Nkc" firstAttribute="centerX" secondItem="yhy-xd-w5C" secondAttribute="centerX" id="VSJ-7R-Srk"/>
|
||||
<constraint firstItem="Gu8-oz-zWa" firstAttribute="bottom" secondItem="qnc-hI-Z9r" secondAttribute="bottom" constant="9" id="XTs-Qg-kiX"/>
|
||||
<constraint firstAttribute="bottom" secondItem="qnc-hI-Z9r" secondAttribute="bottom" constant="9" id="XTs-Qg-kiX"/>
|
||||
<constraint firstItem="7Q9-Tv-9yo" firstAttribute="top" secondItem="w2m-Vw-hpd" secondAttribute="bottom" constant="-10" id="XbB-4a-WpA"/>
|
||||
<constraint firstItem="yhy-xd-w5C" firstAttribute="centerY" secondItem="Gu8-oz-zWa" secondAttribute="centerY" id="ZO7-Ny-L3I"/>
|
||||
<constraint firstItem="yhy-xd-w5C" firstAttribute="centerY" secondItem="jxV-Pk-fPt" secondAttribute="centerY" id="ZO7-Ny-L3I"/>
|
||||
<constraint firstItem="m2p-oJ-j15" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="10" id="Zyr-qM-9qP"/>
|
||||
<constraint firstAttribute="bottom" secondItem="AXX-71-9Q6" secondAttribute="bottom" constant="13" id="d06-sn-I3Y"/>
|
||||
<constraint firstItem="jc6-Vg-TaS" firstAttribute="centerX" secondItem="o4u-0K-Qpt" secondAttribute="centerX" id="fAq-0d-u57"/>
|
||||
<constraint firstItem="jUe-8q-VJd" firstAttribute="leading" secondItem="qnc-hI-Z9r" secondAttribute="trailing" constant="5" id="jMG-V1-hgF"/>
|
||||
<constraint firstItem="Gu8-oz-zWa" firstAttribute="trailing" secondItem="Egg-cb-EhZ" secondAttribute="trailing" id="k8f-bU-D6I"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Egg-cb-EhZ" secondAttribute="trailing" id="k8f-bU-D6I"/>
|
||||
<constraint firstItem="qnc-hI-Z9r" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="10" id="l6K-6H-QIr"/>
|
||||
<constraint firstItem="w2m-Vw-hpd" firstAttribute="leading" secondItem="Gu8-oz-zWa" secondAttribute="leading" constant="10" id="mBb-ff-7HD"/>
|
||||
<constraint firstItem="w2m-Vw-hpd" firstAttribute="leading" secondItem="jxV-Pk-fPt" secondAttribute="leading" constant="57" id="mBb-ff-7HD"/>
|
||||
<constraint firstItem="w2m-Vw-hpd" firstAttribute="leading" secondItem="7Q9-Tv-9yo" secondAttribute="trailing" constant="-10" id="mon-aq-gcP"/>
|
||||
<constraint firstItem="UtT-L6-mgW" firstAttribute="top" secondItem="Gu8-oz-zWa" secondAttribute="top" constant="13" id="nrY-2F-QZ2"/>
|
||||
<constraint firstItem="Gu8-oz-zWa" firstAttribute="trailing" secondItem="AXX-71-9Q6" secondAttribute="trailing" constant="90" id="p0M-zU-aDG"/>
|
||||
<constraint firstItem="w2m-Vw-hpd" firstAttribute="centerY" secondItem="Gu8-oz-zWa" secondAttribute="centerY" id="qKl-4Y-m5t"/>
|
||||
<constraint firstItem="Gu8-oz-zWa" firstAttribute="trailing" secondItem="yhy-xd-w5C" secondAttribute="trailing" id="s2S-RP-cw5"/>
|
||||
<constraint firstItem="AyA-hP-r6w" firstAttribute="centerY" secondItem="Gu8-oz-zWa" secondAttribute="centerY" id="sJp-0x-bdC"/>
|
||||
<constraint firstItem="Gu8-oz-zWa" firstAttribute="trailing" secondItem="o4u-0K-Qpt" secondAttribute="trailing" constant="45" id="tOD-Sd-Uhy"/>
|
||||
<constraint firstItem="UtT-L6-mgW" firstAttribute="top" secondItem="jxV-Pk-fPt" secondAttribute="top" constant="13" id="nrY-2F-QZ2"/>
|
||||
<constraint firstAttribute="trailing" secondItem="AXX-71-9Q6" secondAttribute="trailing" constant="137" id="p0M-zU-aDG"/>
|
||||
<constraint firstItem="w2m-Vw-hpd" firstAttribute="centerY" secondItem="jxV-Pk-fPt" secondAttribute="centerY" id="qKl-4Y-m5t"/>
|
||||
<constraint firstAttribute="trailing" secondItem="yhy-xd-w5C" secondAttribute="trailing" id="s2S-RP-cw5"/>
|
||||
<constraint firstItem="AyA-hP-r6w" firstAttribute="centerY" secondItem="jxV-Pk-fPt" secondAttribute="centerY" id="sJp-0x-bdC"/>
|
||||
<constraint firstAttribute="trailing" secondItem="o4u-0K-Qpt" secondAttribute="trailing" constant="45" id="tOD-Sd-Uhy"/>
|
||||
<constraint firstItem="jc6-Vg-TaS" firstAttribute="centerY" secondItem="o4u-0K-Qpt" secondAttribute="centerY" id="xnq-6u-TXH"/>
|
||||
</constraints>
|
||||
<size key="customSize" width="719" height="146"/>
|
||||
|
@ -235,10 +235,10 @@
|
|||
</objects>
|
||||
<designables>
|
||||
<designable name="jUe-8q-VJd">
|
||||
<size key="intrinsicContentSize" width="24" height="14.333333333333334"/>
|
||||
<size key="intrinsicContentSize" width="34" height="16.333333333333336"/>
|
||||
</designable>
|
||||
<designable name="qnc-hI-Z9r">
|
||||
<size key="intrinsicContentSize" width="26" height="14.333333333333334"/>
|
||||
<size key="intrinsicContentSize" width="36" height="16.333333333333336"/>
|
||||
</designable>
|
||||
</designables>
|
||||
<resources>
|
||||
|
|
|
@ -47,8 +47,8 @@ protocol NCSelectableNavigationView: AnyObject {
|
|||
var layoutKey: String { get }
|
||||
var selectActions: [NCMenuAction] { get }
|
||||
|
||||
func reloadDataSource(isForced: Bool)
|
||||
func setNavigationItem()
|
||||
func reloadDataSource(withQueryDB: Bool)
|
||||
func setNavigationItems()
|
||||
|
||||
func tapSelectMenu()
|
||||
func tapSelect()
|
||||
|
@ -56,7 +56,7 @@ protocol NCSelectableNavigationView: AnyObject {
|
|||
|
||||
extension NCSelectableNavigationView {
|
||||
|
||||
func setNavigationItem() {
|
||||
func setNavigationItems() {
|
||||
setNavigationRightItems()
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ extension NCSelectableNavigationView {
|
|||
isEditMode = !isEditMode
|
||||
selectOcId.removeAll()
|
||||
selectIndexPath.removeAll()
|
||||
self.setNavigationItem()
|
||||
self.setNavigationItems()
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ extension NCSelectableNavigationView where Self: UIViewController {
|
|||
actions.append(.saveMediaAction(selectedMediaMetadatas: selectedMediaMetadatas, completion: tapSelect))
|
||||
}
|
||||
actions.append(.setAvailableOfflineAction(selectedMetadatas: selectedMetadatas, isAnyOffline: isAnyOffline, viewController: self, completion: {
|
||||
self.reloadDataSource(isForced: true)
|
||||
self.reloadDataSource(withQueryDB: true)
|
||||
self.tapSelect()
|
||||
}))
|
||||
|
||||
|
|
|
@ -212,9 +212,7 @@ import XLForm
|
|||
|
||||
func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], indexPath: [IndexPath], overwrite: Bool, copy: Bool, move: Bool) {
|
||||
|
||||
guard let serverUrl = serverUrl else {
|
||||
return
|
||||
}
|
||||
guard let serverUrl = serverUrl else { return }
|
||||
|
||||
self.serverUrl = serverUrl
|
||||
if serverUrl == utilityFileSystem.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) {
|
||||
|
@ -246,9 +244,7 @@ import XLForm
|
|||
|
||||
@objc func save() {
|
||||
|
||||
guard let selectTemplate = self.selectTemplate else {
|
||||
return
|
||||
}
|
||||
guard let selectTemplate = self.selectTemplate else { return }
|
||||
templateIdentifier = selectTemplate.identifier
|
||||
|
||||
let rowFileName: XLFormRowDescriptor = self.form.formRow(withTag: "fileName")!
|
||||
|
|
|
@ -225,7 +225,7 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud
|
|||
|
||||
let metadataForUpload = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: fileNameSave, fileNameView: fileNameSave, ocId: UUID().uuidString, serverUrl: self.serverUrl, urlBase: self.appDelegate.urlBase, url: "", contentType: "")
|
||||
|
||||
metadataForUpload.session = NCNetworking.shared.sessionIdentifierBackground
|
||||
metadataForUpload.session = NCNetworking.shared.sessionUploadBackground
|
||||
metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile
|
||||
metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload
|
||||
metadataForUpload.size = utilityFileSystem.getFileSize(filePath: fileNamePath)
|
||||
|
|
|
@ -263,7 +263,7 @@ struct UploadAssetsView: View {
|
|||
metadata.livePhotoFile = (metadata.fileName as NSString).deletingPathExtension + ".mov"
|
||||
}
|
||||
metadata.assetLocalIdentifier = asset.localIdentifier
|
||||
metadata.session = NCNetworking.shared.sessionIdentifierBackground
|
||||
metadata.session = NCNetworking.shared.sessionUploadBackground
|
||||
metadata.sessionSelector = NCGlobal.shared.selectorUploadFile
|
||||
metadata.status = NCGlobal.shared.metadataStatusWaitUpload
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="FkP-Lh-8zt">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="FkP-Lh-8zt">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
|
|
|
@ -41,18 +41,18 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
|
|||
var documentController: UIDocumentInteractionController?
|
||||
let utilityFileSystem = NCUtilityFileSystem()
|
||||
let utility = NCUtility()
|
||||
let appDelegate = UIApplication.shared.delegate as? AppDelegate
|
||||
|
||||
// MARK: - Download
|
||||
|
||||
@objc func downloadedFile(_ notification: NSNotification) {
|
||||
|
||||
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
|
||||
guard let userInfo = notification.userInfo as NSDictionary?,
|
||||
let ocId = userInfo["ocId"] as? String,
|
||||
let selector = userInfo["selector"] as? String,
|
||||
let error = userInfo["error"] as? NKError,
|
||||
let account = userInfo["account"] as? String,
|
||||
account == appDelegate.account
|
||||
account == appDelegate?.account
|
||||
else { return }
|
||||
|
||||
guard error == .success else {
|
||||
|
@ -72,42 +72,47 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
|
|||
|
||||
switch selector {
|
||||
case NCGlobal.shared.selectorLoadFileQuickLook:
|
||||
let fileNamePath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
|
||||
let fileNameTemp = NSTemporaryDirectory() + metadata.fileNameView
|
||||
let viewerQuickLook = NCViewerQuickLook(with: URL(fileURLWithPath: fileNameTemp), isEditingEnabled: true, metadata: metadata)
|
||||
if let image = UIImage(contentsOfFile: fileNamePath) {
|
||||
if let data = image.jpegData(compressionQuality: 1) {
|
||||
do {
|
||||
try data.write(to: URL(fileURLWithPath: fileNameTemp))
|
||||
} catch {
|
||||
return
|
||||
DispatchQueue.main.async {
|
||||
let fileNamePath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
|
||||
let fileNameTemp = NSTemporaryDirectory() + metadata.fileNameView
|
||||
let viewerQuickLook = NCViewerQuickLook(with: URL(fileURLWithPath: fileNameTemp), isEditingEnabled: true, metadata: metadata)
|
||||
if let image = UIImage(contentsOfFile: fileNamePath) {
|
||||
if let data = image.jpegData(compressionQuality: 1) {
|
||||
do {
|
||||
try data.write(to: URL(fileURLWithPath: fileNameTemp))
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
}
|
||||
let navigationController = UINavigationController(rootViewController: viewerQuickLook)
|
||||
navigationController.modalPresentationStyle = .fullScreen
|
||||
self.appDelegate?.window?.rootViewController?.present(navigationController, animated: true)
|
||||
} else {
|
||||
self.utilityFileSystem.copyFile(atPath: fileNamePath, toPath: fileNameTemp)
|
||||
self.appDelegate?.window?.rootViewController?.present(viewerQuickLook, animated: true)
|
||||
}
|
||||
let navigationController = UINavigationController(rootViewController: viewerQuickLook)
|
||||
navigationController.modalPresentationStyle = .fullScreen
|
||||
appDelegate.window?.rootViewController?.present(navigationController, animated: true)
|
||||
} else {
|
||||
utilityFileSystem.copyFile(atPath: fileNamePath, toPath: fileNameTemp)
|
||||
appDelegate.window?.rootViewController?.present(viewerQuickLook, animated: true)
|
||||
}
|
||||
|
||||
case NCGlobal.shared.selectorLoadFileView:
|
||||
guard UIApplication.shared.applicationState == .active else { break }
|
||||
|
||||
if metadata.contentType.contains("opendocument") && !utility.isRichDocument(metadata) {
|
||||
self.openDocumentController(metadata: metadata)
|
||||
} else if metadata.classFile == NKCommon.TypeClassFile.compress.rawValue || metadata.classFile == NKCommon.TypeClassFile.unknow.rawValue {
|
||||
self.openDocumentController(metadata: metadata)
|
||||
} else {
|
||||
if let viewController = appDelegate.activeViewController {
|
||||
let imageIcon = UIImage(contentsOfFile: utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag))
|
||||
NCViewer().view(viewController: viewController, metadata: metadata, metadatas: [metadata], imageIcon: imageIcon)
|
||||
DispatchQueue.main.async {
|
||||
guard UIApplication.shared.applicationState == .active else { return }
|
||||
if metadata.contentType.contains("opendocument") && !self.utility.isRichDocument(metadata) {
|
||||
self.openDocumentController(metadata: metadata)
|
||||
} else if metadata.classFile == NKCommon.TypeClassFile.compress.rawValue || metadata.classFile == NKCommon.TypeClassFile.unknow.rawValue {
|
||||
self.openDocumentController(metadata: metadata)
|
||||
} else {
|
||||
if let viewController = self.appDelegate?.activeViewController {
|
||||
let imageIcon = UIImage(contentsOfFile: self.utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag))
|
||||
NCViewer().view(viewController: viewController, metadata: metadata, metadatas: [metadata], imageIcon: imageIcon)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case NCGlobal.shared.selectorOpenIn:
|
||||
if UIApplication.shared.applicationState == .active {
|
||||
self.openDocumentController(metadata: metadata)
|
||||
DispatchQueue.main.async {
|
||||
if UIApplication.shared.applicationState == .active {
|
||||
self.openDocumentController(metadata: metadata)
|
||||
}
|
||||
}
|
||||
|
||||
case NCGlobal.shared.selectorLoadOffline:
|
||||
|
@ -121,10 +126,14 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
|
|||
}
|
||||
|
||||
case NCGlobal.shared.selectorSaveAlbum:
|
||||
saveAlbum(metadata: metadata)
|
||||
DispatchQueue.main.async {
|
||||
self.saveAlbum(metadata: metadata)
|
||||
}
|
||||
|
||||
case NCGlobal.shared.selectorSaveAsScan:
|
||||
saveAsScan(metadata: metadata)
|
||||
DispatchQueue.main.async {
|
||||
self.saveAsScan(metadata: metadata)
|
||||
}
|
||||
|
||||
case NCGlobal.shared.selectorOpenDetail:
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterOpenMediaDetail, userInfo: ["ocId": metadata.ocId])
|
||||
|
@ -146,11 +155,12 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
|
|||
}
|
||||
} else if metadata.directory {
|
||||
NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, offline: true, account: appDelegate.account)
|
||||
NCNetworking.shared.synchronizationServerUrl(serverUrl, account: metadata.account, selector: NCGlobal.shared.selectorSynchronizationOffline)
|
||||
NCNetworking.shared.synchronization(account: metadata.account, serverUrl: serverUrl, selector: NCGlobal.shared.selectorSynchronizationOffline)
|
||||
} else {
|
||||
NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadOffline) { _, _ in }
|
||||
if let metadataLivePhoto = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) {
|
||||
NCNetworking.shared.download(metadata: metadataLivePhoto, selector: NCGlobal.shared.selectorLoadOffline) { _, _ in }
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: NCGlobal.shared.selectorLoadOffline) else { return }
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: true)
|
||||
if let metadata = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata), let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: NCGlobal.shared.selectorLoadOffline) {
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -321,7 +331,8 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
|
|||
let processor = ParallelWorker(n: 5, titleKey: "_downloading_", totalTasks: downloadMetadata.count, hudView: appDelegate.window?.rootViewController?.view)
|
||||
for (metadata, url) in downloadMetadata {
|
||||
processor.execute { completion in
|
||||
NCNetworking.shared.download(metadata: metadata, selector: "", notificationCenterProgressTask: false) { _ in
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: "") else { return completion() }
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: false) {
|
||||
} progressHandler: { progress in
|
||||
processor.hud?.progress = Float(progress.fractionCompleted)
|
||||
} completion: { _, _ in
|
||||
|
@ -467,7 +478,9 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
|
|||
|
||||
for metadata in downloadMetadatas {
|
||||
processor.execute { completion in
|
||||
NCNetworking.shared.download(metadata: metadata, selector: "", notificationCenterProgressTask: false) { _ in
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: "") else { return completion() }
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: false) {
|
||||
} requestHandler: { _ in
|
||||
} progressHandler: { progress in
|
||||
if Float(progress.fractionCompleted) > fractionCompleted || fractionCompleted == 0 {
|
||||
processor.hud?.progress = Float(progress.fractionCompleted)
|
||||
|
@ -506,7 +519,7 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
|
|||
let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(ocId!, fileNameView: fileName)
|
||||
self.utilityFileSystem.moveFile(atPath: fileNameLocalPath, toPath: toPath)
|
||||
NCManageDatabase.shared.addLocalFile(account: account, etag: etag!, ocId: ocId!, fileName: fileName)
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced)
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetwork)
|
||||
} else if afError?.isExplicitlyCancelledError ?? false {
|
||||
print("cancel")
|
||||
} else {
|
||||
|
|
|
@ -45,10 +45,7 @@ class NCMainTabBar: UITabBar {
|
|||
appDelegate.mainTabBar = self
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(updateBadgeNumber(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUpdateBadgeNumber), object: nil)
|
||||
|
||||
barTintColor = .secondarySystemBackground
|
||||
backgroundColor = .secondarySystemBackground
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(updateBadgeNumber), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUpdateBadgeNumber), object: nil)
|
||||
|
||||
changeTheming()
|
||||
}
|
||||
|
@ -79,34 +76,31 @@ class NCMainTabBar: UITabBar {
|
|||
}
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
layer.shadowPath = createPath()
|
||||
layer.shadowRadius = 5
|
||||
layer.shadowOffset = .zero
|
||||
layer.shadowOpacity = 0.25
|
||||
}
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
self.subviews.forEach({ $0.removeFromSuperview() })
|
||||
|
||||
addShape()
|
||||
createButtons()
|
||||
}
|
||||
|
||||
private func addShape() {
|
||||
let blurEffect = UIBlurEffect(style: .systemThinMaterial)
|
||||
|
||||
let shapeLayer = CAShapeLayer()
|
||||
shapeLayer.path = createPath()
|
||||
shapeLayer.fillColor = backgroundColor?.cgColor
|
||||
shapeLayer.strokeColor = UIColor.clear.cgColor
|
||||
let blurView = UIVisualEffectView(effect: blurEffect)
|
||||
blurView.frame = self.bounds
|
||||
|
||||
if let oldShapeLayer = self.shapeLayer {
|
||||
self.layer.replaceSublayer(oldShapeLayer, with: shapeLayer)
|
||||
} else {
|
||||
self.layer.insertSublayer(shapeLayer, at: 0)
|
||||
}
|
||||
let maskLayer = CAShapeLayer()
|
||||
maskLayer.path = createPath()
|
||||
|
||||
self.shapeLayer = shapeLayer
|
||||
blurView.layer.mask = maskLayer
|
||||
|
||||
var border = CALayer()
|
||||
border.backgroundColor = UIColor.separator.cgColor
|
||||
border.frame = CGRect(x: 0, y: 0, width: blurView.frame.width, height: 0.5)
|
||||
|
||||
blurView.layer.addSublayer(border)
|
||||
|
||||
self.addSubview(blurView)
|
||||
}
|
||||
|
||||
private func createPath() -> CGPath {
|
||||
|
@ -205,31 +199,55 @@ class NCMainTabBar: UITabBar {
|
|||
self.addSubview(centerButton)
|
||||
}
|
||||
|
||||
@objc func updateBadgeNumber(_ notification: NSNotification) {
|
||||
@objc func updateBadgeNumber() {
|
||||
|
||||
guard let userInfo = notification.userInfo as NSDictionary?,
|
||||
let counterDownload = userInfo["counterDownload"] as? Int,
|
||||
let counterUpload = userInfo["counterUpload"] as? Int
|
||||
else { return }
|
||||
DispatchQueue.global().async {
|
||||
|
||||
var counterDownload = 0
|
||||
var counterUpload = 0
|
||||
|
||||
if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "status < 0")) {
|
||||
counterDownload = results.count
|
||||
}
|
||||
if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "status > 0")) {
|
||||
counterUpload = results.count
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.updateBadgeNumberUI(counterDownload: counterDownload, counterUpload: counterUpload)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateBadgeNumberUI(counterDownload: Int, counterUpload: Int) {
|
||||
|
||||
UIApplication.shared.applicationIconBadgeNumber = counterUpload
|
||||
|
||||
if let item = self.items?[0] {
|
||||
if counterDownload == 0, counterUpload == 0 {
|
||||
item.badgeValue = nil
|
||||
} else if counterDownload > 0, counterUpload == 0 {
|
||||
var badgeValue = String("↓ \(counterDownload)")
|
||||
if counterDownload >= NCGlobal.shared.maxConcurrentOperationCountDownload {
|
||||
badgeValue = String("↓ 10+")
|
||||
if counterDownload >= NCBrandOptions.shared.maxConcurrentOperationDownload {
|
||||
badgeValue = String("↓ \(NCBrandOptions.shared.maxConcurrentOperationDownload)+")
|
||||
}
|
||||
item.badgeValue = badgeValue
|
||||
} else if counterDownload == 0, counterUpload > 0 {
|
||||
item.badgeValue = String("↑ \(counterUpload)")
|
||||
} else {
|
||||
var badgeValue = String("↓ \(counterDownload) ↑ \(counterUpload)")
|
||||
if counterDownload >= NCGlobal.shared.maxConcurrentOperationCountDownload {
|
||||
badgeValue = String("↓ 10+ ↑ \(counterUpload)")
|
||||
var badgeValue = String("↑ \(counterUpload)")
|
||||
if counterUpload >= NCBrandOptions.shared.maxConcurrentOperationUpload {
|
||||
badgeValue = String("↑ \(NCBrandOptions.shared.maxConcurrentOperationUpload)+")
|
||||
}
|
||||
item.badgeValue = badgeValue
|
||||
} else {
|
||||
var badgeValueDownload = String("↓ \(counterDownload)")
|
||||
if counterDownload >= NCBrandOptions.shared.maxConcurrentOperationDownload {
|
||||
badgeValueDownload = String("↓ \(NCBrandOptions.shared.maxConcurrentOperationDownload)+")
|
||||
}
|
||||
var badgeValueUpload = String("↑ \(counterUpload)")
|
||||
if counterUpload >= NCBrandOptions.shared.maxConcurrentOperationUpload {
|
||||
badgeValueUpload = String("↑ \(NCBrandOptions.shared.maxConcurrentOperationUpload)+")
|
||||
}
|
||||
item.badgeValue = badgeValueDownload + " " + badgeValueUpload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ class NCDocumentPickerViewController: NSObject, UIDocumentPickerDelegate {
|
|||
|
||||
let metadataForUpload = NCManageDatabase.shared.createMetadata(account: appDelegate.account, user: appDelegate.user, userId: appDelegate.userId, fileName: fileName, fileNameView: fileName, ocId: ocId, serverUrl: serverUrl, urlBase: appDelegate.urlBase, url: "", contentType: "")
|
||||
|
||||
metadataForUpload.session = NCNetworking.shared.sessionIdentifierBackground
|
||||
metadataForUpload.session = NCNetworking.shared.sessionUploadBackground
|
||||
metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile
|
||||
metadataForUpload.size = utilityFileSystem.getFileSize(filePath: toPath)
|
||||
metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina5_9" orientation="landscape" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
|
@ -16,7 +16,7 @@
|
|||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="TK1-KX-Qe0">
|
||||
<rect key="frame" x="10" y="0.0" width="355" height="30"/>
|
||||
<rect key="frame" x="60" y="0.0" width="255" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="Qvv-k4-hfY"/>
|
||||
</constraints>
|
||||
|
@ -30,10 +30,10 @@
|
|||
</connections>
|
||||
</button>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="qWG-SR-Qly">
|
||||
<rect key="frame" x="177.5" y="5" width="20" height="20"/>
|
||||
<rect key="frame" x="177.66666666666666" y="5" width="20" height="20"/>
|
||||
</activityIndicatorView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="s2m-yO-4x0" userLabel="separator">
|
||||
<rect key="frame" x="10" y="30" width="365" height="1"/>
|
||||
<rect key="frame" x="60" y="30" width="265" height="1"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
|
@ -41,7 +41,7 @@
|
|||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gzy-cT-Gjn" userLabel="LabelFooter">
|
||||
<rect key="frame" x="10" y="43.5" width="355" height="16"/>
|
||||
<rect key="frame" x="10" y="13.666666666666664" width="355" height="16"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
|
@ -53,7 +53,10 @@
|
|||
<constraint firstItem="EFn-SN-cxu" firstAttribute="trailing" secondItem="TK1-KX-Qe0" secondAttribute="trailing" constant="10" id="PoY-CD-99O"/>
|
||||
<constraint firstAttribute="trailing" secondItem="gzy-cT-Gjn" secondAttribute="trailing" constant="10" id="QzY-ac-CRO"/>
|
||||
<constraint firstItem="EFn-SN-cxu" firstAttribute="leading" secondItem="s2m-yO-4x0" secondAttribute="leading" constant="-10" id="ai4-Qy-YWi"/>
|
||||
<constraint firstItem="gzy-cT-Gjn" firstAttribute="centerY" secondItem="Vin-9E-7nW" secondAttribute="centerY" id="avP-sX-JB5"/>
|
||||
<constraint firstItem="gzy-cT-Gjn" firstAttribute="centerY" secondItem="Vin-9E-7nW" secondAttribute="centerY" constant="-30" id="avP-sX-JB5">
|
||||
<variation key="heightClass=compact-widthClass=regular" constant="-15"/>
|
||||
<variation key="heightClass=regular-widthClass=compact" constant="-15"/>
|
||||
</constraint>
|
||||
<constraint firstItem="qWG-SR-Qly" firstAttribute="centerY" secondItem="TK1-KX-Qe0" secondAttribute="centerY" id="baS-g9-E8a"/>
|
||||
<constraint firstItem="EFn-SN-cxu" firstAttribute="trailing" secondItem="s2m-yO-4x0" secondAttribute="trailing" id="dWj-wQ-cfb"/>
|
||||
<constraint firstItem="TK1-KX-Qe0" firstAttribute="bottom" secondItem="s2m-yO-4x0" secondAttribute="bottom" constant="-1" id="ekM-Ii-N58"/>
|
||||
|
@ -74,7 +77,7 @@
|
|||
</objects>
|
||||
<resources>
|
||||
<systemColor name="linkColor">
|
||||
<color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
|
@ -320,9 +320,9 @@ class NCSectionFooter: UICollectionReusableView, NCSectionFooterDelegate {
|
|||
}
|
||||
|
||||
if files > 1 {
|
||||
filesText = "\(files) " + NSLocalizedString("_files_", comment: "") + " " + utilityFileSystem.transformedSize(size)
|
||||
filesText = "\(files) " + NSLocalizedString("_files_", comment: "") + " • " + utilityFileSystem.transformedSize(size)
|
||||
} else if files == 1 {
|
||||
filesText = "1 " + NSLocalizedString("_file_", comment: "") + " " + utilityFileSystem.transformedSize(size)
|
||||
filesText = "1 " + NSLocalizedString("_file_", comment: "") + " • " + utilityFileSystem.transformedSize(size)
|
||||
}
|
||||
|
||||
if foldersText.isEmpty {
|
||||
|
@ -330,7 +330,7 @@ class NCSectionFooter: UICollectionReusableView, NCSectionFooterDelegate {
|
|||
} else if filesText.isEmpty {
|
||||
labelSection.text = foldersText
|
||||
} else {
|
||||
labelSection.text = foldersText + ", " + filesText
|
||||
labelSection.text = foldersText + " • " + filesText
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EFX-fO-Oip">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EFX-fO-Oip">
|
||||
<device id="retina5_9" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
@ -17,7 +17,7 @@
|
|||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="Zaz-Cl-qpZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="813"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="862"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="fF1-wd-0xN">
|
||||
<size key="itemSize" width="0.0" height="0.0"/>
|
||||
|
@ -37,7 +37,7 @@
|
|||
<constraints>
|
||||
<constraint firstItem="Zaz-Cl-qpZ" firstAttribute="leading" secondItem="Meh-VD-wWh" secondAttribute="leading" id="1bp-sm-u0X"/>
|
||||
<constraint firstItem="Meh-VD-wWh" firstAttribute="trailing" secondItem="Zaz-Cl-qpZ" secondAttribute="trailing" id="aNd-UL-hmu"/>
|
||||
<constraint firstItem="Meh-VD-wWh" firstAttribute="bottom" secondItem="Zaz-Cl-qpZ" secondAttribute="bottom" constant="-35" id="aNr-tf-2AH"/>
|
||||
<constraint firstItem="Meh-VD-wWh" firstAttribute="bottom" secondItem="Zaz-Cl-qpZ" secondAttribute="bottom" constant="-84" id="aNr-tf-2AH"/>
|
||||
<constraint firstItem="Zaz-Cl-qpZ" firstAttribute="top" secondItem="QEs-gO-Cmp" secondAttribute="top" id="nIB-3t-o2I"/>
|
||||
</constraints>
|
||||
</view>
|
||||
|
|
|
@ -23,44 +23,40 @@
|
|||
|
||||
import UIKit
|
||||
import NextcloudKit
|
||||
import JGProgressHUD
|
||||
import Queuer
|
||||
import RealmSwift
|
||||
|
||||
class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
|
||||
class NCMedia: UIViewController, NCEmptyDataSetDelegate {
|
||||
|
||||
@IBOutlet weak var collectionView: UICollectionView!
|
||||
|
||||
private var emptyDataSet: NCEmptyDataSet?
|
||||
private var mediaCommandView: NCMediaCommandView?
|
||||
private var gridLayout: NCGridMediaLayout!
|
||||
internal var documentPickerViewController: NCDocumentPickerViewController?
|
||||
var emptyDataSet: NCEmptyDataSet?
|
||||
var mediaCommandView: NCMediaCommandView?
|
||||
var layout: NCMediaGridLayout!
|
||||
var documentPickerViewController: NCDocumentPickerViewController?
|
||||
|
||||
internal let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
|
||||
internal let utilityFileSystem = NCUtilityFileSystem()
|
||||
internal let utility = NCUtility()
|
||||
let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
|
||||
let utilityFileSystem = NCUtilityFileSystem()
|
||||
let utility = NCUtility()
|
||||
|
||||
@ThreadSafe internal var metadatas: Results<tableMetadata>?
|
||||
internal var isEditMode = false
|
||||
internal var selectOcId: [String] = []
|
||||
internal var selectIndexPath: [IndexPath] = []
|
||||
var metadatas: ThreadSafeArray<tableMetadata>?
|
||||
var isEditMode = false
|
||||
var selectOcId: [String] = []
|
||||
|
||||
internal var showOnlyImages = false
|
||||
internal var showOnlyVideos = false
|
||||
var showOnlyImages = false
|
||||
var showOnlyVideos = false
|
||||
|
||||
private let maxImageGrid: CGFloat = 7
|
||||
private var cellHeigth: CGFloat = 0
|
||||
let maxImageGrid: CGFloat = 7
|
||||
var cellHeigth: CGFloat = 0
|
||||
|
||||
private var oldInProgress = false
|
||||
private var newInProgress = false
|
||||
var loadingTask: Task<Void, any Error>?
|
||||
|
||||
private var lastContentOffsetY: CGFloat = 0
|
||||
private var mediaPath = ""
|
||||
var lastContentOffsetY: CGFloat = 0
|
||||
var mediaPath = ""
|
||||
|
||||
private var timeIntervalSearchNewMedia: TimeInterval = 3.0
|
||||
private var timerSearchNewMedia: Timer?
|
||||
var timeIntervalSearchNewMedia: TimeInterval = 3.0
|
||||
var timerSearchNewMedia: Timer?
|
||||
|
||||
private let insetsTop: CGFloat = 75
|
||||
let insetsTop: CGFloat = 75
|
||||
|
||||
struct cacheImages {
|
||||
static var cellLivePhotoImage = UIImage()
|
||||
|
@ -75,35 +71,27 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
|
|||
|
||||
view.backgroundColor = .systemBackground
|
||||
|
||||
collectionView.register(UINib(nibName: "NCGridMediaCell", bundle: nil), forCellWithReuseIdentifier: "gridCell")
|
||||
layout = NCMediaGridLayout()
|
||||
layout.itemForLine = CGFloat(NCKeychain().mediaItemForLine)
|
||||
layout.sectionHeadersPinToVisibleBounds = true
|
||||
|
||||
collectionView.register(UINib(nibName: "NCGridMediaCell", bundle: nil), forCellWithReuseIdentifier: "gridCell")
|
||||
collectionView.alwaysBounceVertical = true
|
||||
collectionView.contentInset = UIEdgeInsets(top: insetsTop, left: 0, bottom: 50, right: 0)
|
||||
collectionView.backgroundColor = .systemBackground
|
||||
collectionView.prefetchDataSource = self
|
||||
collectionView.collectionViewLayout = layout
|
||||
|
||||
gridLayout = NCGridMediaLayout()
|
||||
gridLayout.itemForLine = CGFloat(min(NCKeychain().mediaWidthImage, 5))
|
||||
gridLayout.sectionHeadersPinToVisibleBounds = true
|
||||
|
||||
collectionView.collectionViewLayout = gridLayout
|
||||
|
||||
// Empty
|
||||
emptyDataSet = NCEmptyDataSet(view: collectionView, offset: 0, delegate: self)
|
||||
|
||||
mediaCommandView = Bundle.main.loadNibNamed("NCMediaCommandView", owner: self, options: nil)?.first as? NCMediaCommandView
|
||||
self.view.addSubview(mediaCommandView!)
|
||||
mediaCommandView?.mediaView = self
|
||||
mediaCommandView?.zoomInButton.isEnabled = !(gridLayout.itemForLine == 1)
|
||||
mediaCommandView?.zoomOutButton.isEnabled = !(gridLayout.itemForLine == maxImageGrid - 1)
|
||||
mediaCommandView?.collapseControlButtonView(true)
|
||||
mediaCommandView?.translatesAutoresizingMaskIntoConstraints = false
|
||||
mediaCommandView?.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
|
||||
mediaCommandView?.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
|
||||
mediaCommandView?.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
|
||||
mediaCommandView?.heightAnchor.constraint(equalToConstant: 150).isActive = true
|
||||
self.updateMediaControlVisibility()
|
||||
|
||||
collectionView.prefetchDataSource = self
|
||||
|
||||
cacheImages.cellLivePhotoImage = utility.loadImage(named: "livephoto", color: .white)
|
||||
cacheImages.cellPlayImage = utility.loadImage(named: "play.fill", color: .white)
|
||||
|
@ -119,34 +107,35 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
|
|||
navigationController?.setMediaAppreance()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(deleteFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDeleteFile), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(uploadedFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile), object: nil)
|
||||
|
||||
timerSearchNewMedia?.invalidate()
|
||||
timerSearchNewMedia = Timer.scheduledTimer(timeInterval: timeIntervalSearchNewMedia, target: self, selector: #selector(searchMediaUI), userInfo: nil, repeats: false)
|
||||
|
||||
if let metadatas = NCImageCache.shared.initialMetadatas() {
|
||||
self.metadatas = metadatas
|
||||
self.mediaCommandView?.setMoreButton()
|
||||
}
|
||||
timerSearchNewMedia?.invalidate()
|
||||
timerSearchNewMedia = Timer.scheduledTimer(timeInterval: timeIntervalSearchNewMedia, target: self, selector: #selector(searchNewMediaTimer), userInfo: nil, repeats: false)
|
||||
|
||||
collectionView.reloadData()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
mediaCommandTitle()
|
||||
mediaCommandView?.setMediaCommand()
|
||||
mediaCommandView?.createMenu()
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDeleteFile), object: nil)
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile), object: nil)
|
||||
}
|
||||
|
||||
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
super.viewWillTransition(to: size, with: coordinator)
|
||||
|
||||
self.collectionView?.collectionViewLayout.invalidateLayout()
|
||||
collectionView?.collectionViewLayout.invalidateLayout()
|
||||
mediaCommandView?.setMediaCommand()
|
||||
}
|
||||
|
||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
|
@ -158,103 +147,64 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
|
|||
@objc func deleteFile(_ notification: NSNotification) {
|
||||
|
||||
guard let userInfo = notification.userInfo as NSDictionary?,
|
||||
let ocIds = userInfo["ocId"] as? [String],
|
||||
let error = userInfo["error"] as? NKError else { return }
|
||||
|
||||
self.reloadDataSource()
|
||||
if !ocIds.isEmpty {
|
||||
var items: [IndexPath] = []
|
||||
self.metadatas = self.metadatas?.filter({ !ocIds.contains($0.ocId )})
|
||||
if let visibleCells = self.collectionView?.indexPathsForVisibleItems.sorted(by: { $0.row < $1.row }).compactMap({ self.collectionView?.cellForItem(at: $0) }) {
|
||||
for case let cell as NCGridMediaCell in visibleCells {
|
||||
if let ocId = cell.fileObjectId, ocIds.contains(ocId) {
|
||||
items.append(cell.indexPath)
|
||||
}
|
||||
}
|
||||
collectionView?.performBatchUpdates({
|
||||
collectionView?.deleteItems(at: items)
|
||||
}, completion: { _ in
|
||||
self.collectionView?.reloadData()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if error != .success {
|
||||
NCContentPresenter().showError(error: error)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func uploadedFile(_ notification: NSNotification) {
|
||||
|
||||
guard let userInfo = notification.userInfo as NSDictionary?,
|
||||
let error = userInfo["error"] as? NKError,
|
||||
error == .success,
|
||||
let account = userInfo["account"] as? String,
|
||||
account == appDelegate.account
|
||||
else { return }
|
||||
|
||||
self.reloadDataSource()
|
||||
}
|
||||
|
||||
// MARK: - Command
|
||||
|
||||
func mediaCommandTitle() {
|
||||
|
||||
mediaCommandView?.title.text = ""
|
||||
if let visibleCells = self.collectionView?.indexPathsForVisibleItems.sorted(by: { $0.row < $1.row }).compactMap({ self.collectionView?.cellForItem(at: $0) }) {
|
||||
if let cell = visibleCells.first as? NCGridMediaCell {
|
||||
mediaCommandView?.title.text = ""
|
||||
if let date = cell.date {
|
||||
mediaCommandView?.title.text = utility.getTitleFromDate(date)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func zoomOutGrid() {
|
||||
|
||||
UIView.animate(withDuration: 0.0, animations: {
|
||||
if self.gridLayout.itemForLine + 1 < self.maxImageGrid {
|
||||
self.gridLayout.itemForLine += 1
|
||||
self.mediaCommandView?.zoomInButton.isEnabled = true
|
||||
}
|
||||
if self.gridLayout.itemForLine == self.maxImageGrid - 1 {
|
||||
self.mediaCommandView?.zoomOutButton.isEnabled = false
|
||||
}
|
||||
|
||||
self.collectionView.collectionViewLayout.invalidateLayout()
|
||||
NCKeychain().mediaWidthImage = Int(self.gridLayout.itemForLine)
|
||||
})
|
||||
}
|
||||
|
||||
@objc func zoomInGrid() {
|
||||
|
||||
UIView.animate(withDuration: 0.0, animations: {
|
||||
if self.gridLayout.itemForLine - 1 > 0 {
|
||||
self.gridLayout.itemForLine -= 1
|
||||
self.mediaCommandView?.zoomOutButton.isEnabled = true
|
||||
}
|
||||
if self.gridLayout.itemForLine == 1 {
|
||||
self.mediaCommandView?.zoomInButton.isEnabled = false
|
||||
}
|
||||
|
||||
self.collectionView.collectionViewLayout.invalidateLayout()
|
||||
NCKeychain().mediaWidthImage = Int(self.gridLayout.itemForLine)
|
||||
})
|
||||
}
|
||||
|
||||
@objc func openMenuButtonMore(_ sender: Any) {
|
||||
|
||||
toggleMenu()
|
||||
}
|
||||
|
||||
// MARK: Select Path
|
||||
|
||||
func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], indexPath: [IndexPath], overwrite: Bool, copy: Bool, move: Bool) {
|
||||
|
||||
guard let serverUrl = serverUrl else { return }
|
||||
let home = utilityFileSystem.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId)
|
||||
mediaPath = serverUrl.replacingOccurrences(of: home, with: "")
|
||||
NCManageDatabase.shared.setAccountMediaPath(mediaPath, account: appDelegate.account)
|
||||
reloadDataSource()
|
||||
searchNewMedia()
|
||||
}
|
||||
|
||||
// MARK: - Empty
|
||||
|
||||
func emptyDataSetView(_ view: NCEmptyView) {
|
||||
|
||||
view.emptyImage.image = UIImage(named: "media")?.image(color: .gray, size: UIScreen.main.bounds.width)
|
||||
if oldInProgress || newInProgress {
|
||||
if loadingTask != nil {
|
||||
view.emptyTitle.text = NSLocalizedString("_search_in_progress_", comment: "")
|
||||
} else {
|
||||
view.emptyTitle.text = NSLocalizedString("_tutorial_photo_view_", comment: "")
|
||||
}
|
||||
view.emptyDescription.text = ""
|
||||
}
|
||||
|
||||
// MARK: - Image
|
||||
|
||||
func getImage(metadata: tableMetadata) -> UIImage? {
|
||||
|
||||
if let cachedImage = NCImageCache.shared.getMediaImage(ocId: metadata.ocId, etag: metadata.etag), case let .actual(image) = cachedImage {
|
||||
return image
|
||||
} else if FileManager().fileExists(atPath: utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) {
|
||||
if let image = UIImage(contentsOfFile: utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) {
|
||||
NCImageCache.shared.setMediaImage(ocId: metadata.ocId, etag: metadata.etag, image: .actual(image))
|
||||
return image
|
||||
}
|
||||
} else {
|
||||
if metadata.hasPreview && metadata.status == NCGlobal.shared.metadataStatusNormal && (!utilityFileSystem.fileProviderStoragePreviewIconExists(metadata.ocId, etag: metadata.etag)) {
|
||||
if NCNetworking.shared.downloadThumbnailQueue.operations.filter({ ($0 as? NCMediaDownloadThumbnaill)?.metadata.ocId == metadata.ocId }).isEmpty {
|
||||
NCNetworking.shared.downloadThumbnailQueue.addOperation(NCMediaDownloadThumbnaill(metadata: metadata, collectionView: collectionView))
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Collection View
|
||||
|
@ -267,20 +217,18 @@ extension NCMedia: UICollectionViewDelegate {
|
|||
if isEditMode {
|
||||
if let index = selectOcId.firstIndex(of: metadata.ocId) {
|
||||
selectOcId.remove(at: index)
|
||||
selectIndexPath.removeAll(where: { $0 == indexPath })
|
||||
} else {
|
||||
selectOcId.append(metadata.ocId)
|
||||
selectIndexPath.append(indexPath)
|
||||
}
|
||||
if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) {
|
||||
collectionView.reloadItems(at: [indexPath])
|
||||
}
|
||||
} else if let metadatas = self.metadatas {
|
||||
} else {
|
||||
// ACTIVE SERVERURL
|
||||
appDelegate.activeServerUrl = metadata.serverUrl
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as? NCGridMediaCell
|
||||
let arrayMetadatas = Array(metadatas.map { tableMetadata.init(value: $0) })
|
||||
NCViewer().view(viewController: self, metadata: metadata, metadatas: arrayMetadatas, imageIcon: cell?.imageItem.image)
|
||||
if let metadatas = self.metadatas?.getArray() {
|
||||
NCViewer().view(viewController: self, metadata: metadata, metadatas: metadatas, imageIcon: getImage(metadata: metadata))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -317,15 +265,18 @@ extension NCMedia: UICollectionViewDataSourcePrefetching {
|
|||
extension NCMedia: UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
guard let metadatas = self.metadatas else { return 0 }
|
||||
emptyDataSet?.numberOfItemsInSection(metadatas.count, section: section)
|
||||
return metadatas.count
|
||||
var numberOfItemsInSection = 0
|
||||
if let metadatas {
|
||||
numberOfItemsInSection = metadatas.count
|
||||
}
|
||||
emptyDataSet?.numberOfItemsInSection(numberOfItemsInSection, section: section)
|
||||
return numberOfItemsInSection
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
|
||||
guard let metadatas = self.metadatas else { return }
|
||||
guard let metadatas else { return }
|
||||
if !collectionView.indexPathsForVisibleItems.contains(indexPath) && indexPath.row < metadatas.count {
|
||||
let metadata = metadatas[indexPath.row]
|
||||
guard let metadata = metadatas[indexPath.row] else { return }
|
||||
for case let operation as NCMediaDownloadThumbnaill in NCNetworking.shared.downloadThumbnailQueue.operations where operation.metadata.ocId == metadata.ocId {
|
||||
operation.cancel()
|
||||
}
|
||||
|
@ -338,260 +289,47 @@ extension NCMedia: UICollectionViewDataSource {
|
|||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
|
||||
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as? NCGridMediaCell,
|
||||
let metadatas = self.metadatas else { return UICollectionViewCell() }
|
||||
let metadatas = self.metadatas,
|
||||
let metadata = metadatas[indexPath.row] else { return UICollectionViewCell() }
|
||||
|
||||
if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) && indexPath.row < metadatas.count {
|
||||
self.cellHeigth = cell.frame.size.height
|
||||
|
||||
let metadata = metadatas[indexPath.row]
|
||||
cell.date = metadata.date as Date
|
||||
cell.fileObjectId = metadata.ocId
|
||||
cell.indexPath = indexPath
|
||||
cell.fileUser = metadata.ownerId
|
||||
cell.imageStatus.image = nil
|
||||
|
||||
self.cellHeigth = cell.frame.size.height
|
||||
if let image = getImage(metadata: metadata) {
|
||||
cell.imageItem.backgroundColor = nil
|
||||
cell.imageItem.image = image
|
||||
}
|
||||
|
||||
cell.date = metadata.date as Date
|
||||
cell.fileObjectId = metadata.ocId
|
||||
cell.indexPath = indexPath
|
||||
cell.fileUser = metadata.ownerId
|
||||
// Convert OLD Live Photo
|
||||
if NCGlobal.shared.isLivePhotoServerAvailable, metadata.isLivePhoto, metadata.isNotFlaggedAsLivePhotoByServer {
|
||||
NCNetworking.shared.convertLivePhoto(metadata: metadata)
|
||||
}
|
||||
|
||||
if let cachedImage = NCImageCache.shared.getMediaImage(ocId: metadata.ocId, etag: metadata.etag), case let .actual(image) = cachedImage {
|
||||
cell.imageItem.backgroundColor = nil
|
||||
cell.imageItem.image = image
|
||||
} else if FileManager().fileExists(atPath: utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) {
|
||||
if let image = UIImage(contentsOfFile: utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) {
|
||||
cell.imageItem.backgroundColor = nil
|
||||
cell.imageItem.image = image
|
||||
NCImageCache.shared.setMediaImage(ocId: metadata.ocId, etag: metadata.etag, image: .actual(image))
|
||||
}
|
||||
if metadata.isAudioOrVideo {
|
||||
cell.imageStatus.image = cacheImages.cellPlayImage
|
||||
} else if metadata.isLivePhoto {
|
||||
cell.imageStatus.image = cacheImages.cellLivePhotoImage
|
||||
} else {
|
||||
cell.imageStatus.image = nil
|
||||
}
|
||||
|
||||
if isEditMode {
|
||||
cell.selectMode(true)
|
||||
if selectOcId.contains(metadata.ocId) {
|
||||
cell.selected(true)
|
||||
} else {
|
||||
if metadata.hasPreview && metadata.status == NCGlobal.shared.metadataStatusNormal && (!utilityFileSystem.fileProviderStoragePreviewIconExists(metadata.ocId, etag: metadata.etag)) {
|
||||
if NCNetworking.shared.downloadThumbnailQueue.operations.filter({ ($0 as? NCMediaDownloadThumbnaill)?.metadata.ocId == metadata.ocId }).isEmpty {
|
||||
NCNetworking.shared.downloadThumbnailQueue.addOperation(NCMediaDownloadThumbnaill(metadata: metadata, cell: cell, collectionView: collectionView))
|
||||
}
|
||||
}
|
||||
cell.imageStatus.image = nil
|
||||
}
|
||||
|
||||
// Convert OLD Live Photo
|
||||
if NCGlobal.shared.isLivePhotoServerAvailable, metadata.isLivePhoto, metadata.isNotFlaggedAsLivePhotoByServer {
|
||||
NCNetworking.shared.convertLivePhoto(metadata: metadata)
|
||||
}
|
||||
|
||||
if metadata.isAudioOrVideo {
|
||||
cell.imageStatus.image = cacheImages.cellPlayImage
|
||||
} else if metadata.isLivePhoto {
|
||||
cell.imageStatus.image = cacheImages.cellLivePhotoImage
|
||||
} else {
|
||||
cell.imageStatus.image = nil
|
||||
}
|
||||
|
||||
if isEditMode {
|
||||
cell.selectMode(true)
|
||||
if selectOcId.contains(metadata.ocId) {
|
||||
cell.selected(true)
|
||||
} else {
|
||||
cell.selected(false)
|
||||
}
|
||||
} else {
|
||||
cell.selectMode(false)
|
||||
}
|
||||
|
||||
return cell
|
||||
|
||||
} else {
|
||||
|
||||
return cell
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NCMedia: UICollectionViewDelegateFlowLayout {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
|
||||
return CGSize(width: collectionView.frame.width, height: 0)
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
|
||||
return CGSize(width: collectionView.frame.width, height: 0)
|
||||
}
|
||||
}
|
||||
|
||||
extension NCMedia {
|
||||
|
||||
func getPredicate(showAll: Bool = false) -> NSPredicate {
|
||||
|
||||
let startServerUrl = NCUtilityFileSystem().getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) + mediaPath
|
||||
|
||||
if showAll {
|
||||
return NSPredicate(format: NCImageCache.shared.showAllPredicateMediaString, appDelegate.account, startServerUrl)
|
||||
} else if showOnlyImages {
|
||||
return NSPredicate(format: NCImageCache.shared.showOnlyPredicateMediaString, appDelegate.account, startServerUrl, NKCommon.TypeClassFile.image.rawValue)
|
||||
} else if showOnlyVideos {
|
||||
return NSPredicate(format: NCImageCache.shared.showOnlyPredicateMediaString, appDelegate.account, startServerUrl, NKCommon.TypeClassFile.video.rawValue)
|
||||
} else {
|
||||
return NSPredicate(format: NCImageCache.shared.showBothPredicateMediaString, appDelegate.account, startServerUrl)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func reloadDataSource() {
|
||||
guard !appDelegate.account.isEmpty else { return }
|
||||
|
||||
metadatas = NCImageCache.shared.getMediaMetadatas(account: self.appDelegate.account, predicate: self.getPredicate())
|
||||
DispatchQueue.main.async {
|
||||
self.collectionView?.reloadData()
|
||||
self.updateMediaControlVisibility()
|
||||
self.mediaCommandTitle()
|
||||
}
|
||||
}
|
||||
|
||||
func updateMediaControlVisibility() {
|
||||
|
||||
if let metadatas = self.metadatas, metadatas.isEmpty {
|
||||
if !self.showOnlyImages && !self.showOnlyVideos {
|
||||
self.mediaCommandView?.toggleEmptyView(isEmpty: true)
|
||||
self.mediaCommandView?.isHidden = false
|
||||
} else {
|
||||
self.mediaCommandView?.toggleEmptyView(isEmpty: true)
|
||||
self.mediaCommandView?.isHidden = false
|
||||
cell.selected(false)
|
||||
}
|
||||
} else {
|
||||
self.mediaCommandView?.toggleEmptyView(isEmpty: false)
|
||||
self.mediaCommandView?.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Search media
|
||||
|
||||
private func searchOldMedia(value: Int = -30, limit: Int = 300) {
|
||||
|
||||
if oldInProgress { return } else { oldInProgress = true }
|
||||
DispatchQueue.main.async {
|
||||
self.collectionView.reloadData()
|
||||
var bottom: CGFloat = 0
|
||||
if let mainTabBar = self.tabBarController?.tabBar as? NCMainTabBar {
|
||||
bottom = -mainTabBar.getHeight()
|
||||
}
|
||||
NCActivityIndicator.shared.start(backgroundView: self.view, bottom: bottom - 5, style: .medium)
|
||||
cell.selectMode(false)
|
||||
}
|
||||
|
||||
var lessDate = Date()
|
||||
let predicate = getPredicate()
|
||||
if let metadata = NCManageDatabase.shared.getMetadata(predicate: predicate, sorted: "date", ascending: true) {
|
||||
lessDate = metadata.date as Date
|
||||
}
|
||||
|
||||
var greaterDate: Date
|
||||
if value == -999 {
|
||||
greaterDate = Date.distantPast
|
||||
} else {
|
||||
greaterDate = Calendar.current.date(byAdding: .day, value: value, to: lessDate)!
|
||||
}
|
||||
|
||||
let options = NKRequestOptions(timeout: 300, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
|
||||
|
||||
NextcloudKit.shared.searchMedia(path: mediaPath, lessDate: lessDate, greaterDate: greaterDate, elementDate: "d:getlastmodified/", limit: limit, showHiddenFiles: NCKeychain().showHiddenFiles, options: options) { account, files, _, error in
|
||||
|
||||
self.oldInProgress = false
|
||||
DispatchQueue.main.async {
|
||||
NCActivityIndicator.shared.stop()
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
|
||||
if error == .success && account == self.appDelegate.account {
|
||||
if !files.isEmpty {
|
||||
NCManageDatabase.shared.convertFilesToMetadatas(files, useMetadataFolder: false) { _, _, metadatas in
|
||||
var predicate = NSPredicate(format: "date > %@ AND date < %@", greaterDate as NSDate, lessDate as NSDate)
|
||||
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, self.getPredicate(showAll: true)])
|
||||
let results = NCManageDatabase.shared.updateMetadatas(metadatas, predicate: predicate)
|
||||
if results.metadatasChangedCount == 0 {
|
||||
self.researchOldMedia(value: value, limit: limit, withElseReloadDataSource: true)
|
||||
} else if results.metadatasChanged {
|
||||
self.reloadDataSource()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.researchOldMedia(value: value, limit: limit, withElseReloadDataSource: false)
|
||||
}
|
||||
} else if error != .success {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Media search old media error code \(error.errorCode) " + error.errorDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func researchOldMedia(value: Int, limit: Int, withElseReloadDataSource: Bool) {
|
||||
|
||||
if value == -30 {
|
||||
searchOldMedia(value: -90)
|
||||
} else if value == -90 {
|
||||
searchOldMedia(value: -180)
|
||||
} else if value == -180 {
|
||||
searchOldMedia(value: -999)
|
||||
} else if value == -999 && limit > 0 {
|
||||
searchOldMedia(value: -999, limit: 0)
|
||||
} else {
|
||||
if withElseReloadDataSource {
|
||||
self.reloadDataSource()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func searchNewMediaTimer() {
|
||||
|
||||
self.searchNewMedia()
|
||||
}
|
||||
|
||||
@objc func searchNewMedia() {
|
||||
|
||||
if newInProgress { return } else {
|
||||
newInProgress = true
|
||||
mediaCommandView?.activityIndicator.startAnimating()
|
||||
}
|
||||
|
||||
var limit: Int = 1000
|
||||
guard var lessDate = Calendar.current.date(byAdding: .second, value: 1, to: Date()) else { return }
|
||||
guard var greaterDate = Calendar.current.date(byAdding: .day, value: -30, to: Date()) else { return }
|
||||
|
||||
if let visibleCells = self.collectionView?.indexPathsForVisibleItems.sorted(by: { $0.row < $1.row }).compactMap({ self.collectionView?.cellForItem(at: $0) }) {
|
||||
if let cell = visibleCells.first as? NCGridMediaCell {
|
||||
if cell.date != nil {
|
||||
if cell.date != self.metadatas?.first?.date as Date? {
|
||||
lessDate = Calendar.current.date(byAdding: .second, value: 1, to: cell.date!)!
|
||||
limit = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
if let cell = visibleCells.last as? NCGridMediaCell {
|
||||
if cell.date != nil {
|
||||
greaterDate = Calendar.current.date(byAdding: .second, value: -1, to: cell.date!)!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collectionView?.reloadData()
|
||||
|
||||
let options = NKRequestOptions(timeout: 300, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
|
||||
|
||||
NextcloudKit.shared.searchMedia(path: self.mediaPath, lessDate: lessDate, greaterDate: greaterDate, elementDate: "d:getlastmodified/", limit: limit, showHiddenFiles: NCKeychain().showHiddenFiles, options: options) { account, files, _, error in
|
||||
|
||||
self.newInProgress = false
|
||||
DispatchQueue.main.async {
|
||||
self.mediaCommandView?.activityIndicator.stopAnimating()
|
||||
}
|
||||
|
||||
if error == .success, account == self.appDelegate.account {
|
||||
if !files.isEmpty {
|
||||
NCManageDatabase.shared.convertFilesToMetadatas(files, useMetadataFolder: false) { _, _, metadatas in
|
||||
var predicate = NSPredicate(format: "date > %@ AND date < %@", greaterDate as NSDate, lessDate as NSDate)
|
||||
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, self.getPredicate(showAll: true)])
|
||||
let results = NCManageDatabase.shared.updateMetadatas(metadatas, predicate: predicate)
|
||||
if results.metadatasChangedCount != 0 || results.metadatasChanged {
|
||||
self.reloadDataSource()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.searchOldMedia()
|
||||
}
|
||||
} else if error != .success {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Media search new media error code \(error.errorCode) " + error.errorDescription)
|
||||
}
|
||||
}
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -600,246 +338,48 @@ extension NCMedia {
|
|||
extension NCMedia: UIScrollViewDelegate {
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
|
||||
if lastContentOffsetY == 0 || lastContentOffsetY + cellHeigth / 2 <= scrollView.contentOffset.y || lastContentOffsetY - cellHeigth / 2 >= scrollView.contentOffset.y {
|
||||
|
||||
mediaCommandTitle()
|
||||
mediaCommandView?.setMediaCommand()
|
||||
lastContentOffsetY = scrollView.contentOffset.y
|
||||
}
|
||||
}
|
||||
|
||||
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
||||
|
||||
mediaCommandView?.collapseControlButtonView(true)
|
||||
}
|
||||
|
||||
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||||
|
||||
if !decelerate {
|
||||
timerSearchNewMedia?.invalidate()
|
||||
timerSearchNewMedia = Timer.scheduledTimer(timeInterval: timeIntervalSearchNewMedia, target: self, selector: #selector(searchNewMediaTimer), userInfo: nil, repeats: false)
|
||||
|
||||
if scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height) {
|
||||
searchOldMedia()
|
||||
if !decelerate {
|
||||
timerSearchNewMedia?.invalidate()
|
||||
timerSearchNewMedia = Timer.scheduledTimer(timeInterval: timeIntervalSearchNewMedia, target: self, selector: #selector(searchMediaUI), userInfo: nil, repeats: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
||||
|
||||
timerSearchNewMedia?.invalidate()
|
||||
timerSearchNewMedia = Timer.scheduledTimer(timeInterval: timeIntervalSearchNewMedia, target: self, selector: #selector(searchNewMediaTimer), userInfo: nil, repeats: false)
|
||||
|
||||
if scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height) {
|
||||
searchOldMedia()
|
||||
}
|
||||
timerSearchNewMedia = Timer.scheduledTimer(timeInterval: timeIntervalSearchNewMedia, target: self, selector: #selector(searchMediaUI), userInfo: nil, repeats: false)
|
||||
}
|
||||
|
||||
func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
|
||||
|
||||
let y = view.safeAreaInsets.top
|
||||
scrollView.contentOffset.y = -(insetsTop + y)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Media Command View
|
||||
// MARK: - NCSelect Delegate
|
||||
|
||||
class NCMediaCommandView: UIView {
|
||||
extension NCMedia: NCSelectDelegate {
|
||||
|
||||
@IBOutlet weak var moreView: UIVisualEffectView!
|
||||
@IBOutlet weak var gridSwitchButton: UIButton!
|
||||
@IBOutlet weak var separatorView: UIView!
|
||||
@IBOutlet weak var buttonControlWidthConstraint: NSLayoutConstraint!
|
||||
@IBOutlet weak var zoomInButton: UIButton!
|
||||
@IBOutlet weak var zoomOutButton: UIButton!
|
||||
@IBOutlet weak var moreButton: UIButton!
|
||||
@IBOutlet weak var controlButtonView: UIVisualEffectView!
|
||||
@IBOutlet weak var title: UILabel!
|
||||
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
|
||||
func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], indexPath: [IndexPath], overwrite: Bool, copy: Bool, move: Bool) {
|
||||
|
||||
var mediaView: NCMedia?
|
||||
private let gradient: CAGradientLayer = CAGradientLayer()
|
||||
|
||||
override func awakeFromNib() {
|
||||
moreView.layer.cornerRadius = 20
|
||||
moreView.layer.masksToBounds = true
|
||||
controlButtonView.layer.cornerRadius = 20
|
||||
controlButtonView.layer.masksToBounds = true
|
||||
controlButtonView.effect = UIBlurEffect(style: .dark)
|
||||
gradient.frame = bounds
|
||||
gradient.startPoint = CGPoint(x: 0, y: 0.5)
|
||||
gradient.endPoint = CGPoint(x: 0, y: 1)
|
||||
gradient.colors = [UIColor.black.withAlphaComponent(UIAccessibility.isReduceTransparencyEnabled ? 0.8 : 0.4).cgColor, UIColor.clear.cgColor]
|
||||
layer.insertSublayer(gradient, at: 0)
|
||||
moreButton.setImage(UIImage(named: "more")!.image(color: .white, size: 25), for: .normal)
|
||||
title.text = ""
|
||||
}
|
||||
|
||||
func toggleEmptyView(isEmpty: Bool) {
|
||||
if isEmpty {
|
||||
UIView.animate(withDuration: 0.3) {
|
||||
self.moreView.effect = UIBlurEffect(style: .dark)
|
||||
self.gradient.isHidden = true
|
||||
self.controlButtonView.isHidden = true
|
||||
}
|
||||
} else {
|
||||
UIView.animate(withDuration: 0.3) {
|
||||
self.moreView.effect = UIBlurEffect(style: .dark)
|
||||
self.gradient.isHidden = false
|
||||
self.controlButtonView.isHidden = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func moreButtonPressed(_ sender: UIButton) {
|
||||
mediaView?.openMenuButtonMore(sender)
|
||||
}
|
||||
|
||||
@IBAction func zoomInPressed(_ sender: UIButton) {
|
||||
mediaView?.zoomInGrid()
|
||||
}
|
||||
|
||||
@IBAction func zoomOutPressed(_ sender: UIButton) {
|
||||
mediaView?.zoomOutGrid()
|
||||
}
|
||||
|
||||
@IBAction func gridSwitchButtonPressed(_ sender: Any) {
|
||||
self.collapseControlButtonView(false)
|
||||
}
|
||||
|
||||
func collapseControlButtonView(_ collapse: Bool) {
|
||||
if collapse {
|
||||
self.buttonControlWidthConstraint.constant = 40
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
self.zoomOutButton.isHidden = true
|
||||
self.zoomInButton.isHidden = true
|
||||
self.separatorView.isHidden = true
|
||||
self.gridSwitchButton.isHidden = false
|
||||
self.layoutIfNeeded()
|
||||
}
|
||||
} else {
|
||||
self.buttonControlWidthConstraint.constant = 80
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
self.zoomOutButton.isHidden = false
|
||||
self.zoomInButton.isHidden = false
|
||||
self.separatorView.isHidden = false
|
||||
self.gridSwitchButton.isHidden = true
|
||||
self.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||
return moreView.frame.contains(point) || controlButtonView.frame.contains(point)
|
||||
}
|
||||
|
||||
override func layoutSublayers(of layer: CALayer) {
|
||||
super.layoutSublayers(of: layer)
|
||||
gradient.frame = bounds
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Media Grid Layout
|
||||
|
||||
class NCGridMediaLayout: UICollectionViewFlowLayout {
|
||||
|
||||
var marginLeftRight: CGFloat = 2
|
||||
var itemForLine: CGFloat = 3
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
|
||||
sectionHeadersPinToVisibleBounds = false
|
||||
|
||||
minimumInteritemSpacing = 0
|
||||
minimumLineSpacing = marginLeftRight
|
||||
|
||||
self.scrollDirection = .vertical
|
||||
self.sectionInset = UIEdgeInsets(top: 0, left: marginLeftRight, bottom: 0, right: marginLeftRight)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override var itemSize: CGSize {
|
||||
get {
|
||||
if let collectionView = collectionView {
|
||||
|
||||
let itemWidth: CGFloat = (collectionView.frame.width - marginLeftRight * 2 - marginLeftRight * (itemForLine - 1)) / itemForLine
|
||||
let itemHeight: CGFloat = itemWidth
|
||||
|
||||
return CGSize(width: itemWidth, height: itemHeight)
|
||||
}
|
||||
|
||||
// Default fallback
|
||||
return CGSize(width: 100, height: 100)
|
||||
}
|
||||
set {
|
||||
super.itemSize = newValue
|
||||
}
|
||||
}
|
||||
|
||||
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint {
|
||||
return proposedContentOffset
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
class NCMediaDownloadThumbnaill: ConcurrentOperation {
|
||||
|
||||
var metadata: tableMetadata
|
||||
var cell: NCCellProtocol?
|
||||
var collectionView: UICollectionView?
|
||||
var fileNamePath: String
|
||||
var fileNamePreviewLocalPath: String
|
||||
var fileNameIconLocalPath: String
|
||||
let utilityFileSystem = NCUtilityFileSystem()
|
||||
|
||||
init(metadata: tableMetadata, cell: NCCellProtocol?, collectionView: UICollectionView?) {
|
||||
self.metadata = tableMetadata.init(value: metadata)
|
||||
self.cell = cell
|
||||
self.collectionView = collectionView
|
||||
self.fileNamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId)
|
||||
self.fileNamePreviewLocalPath = utilityFileSystem.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)
|
||||
self.fileNameIconLocalPath = utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)
|
||||
}
|
||||
|
||||
override func start() {
|
||||
|
||||
guard !isCancelled else { return self.finish() }
|
||||
|
||||
var etagResource: String?
|
||||
if FileManager.default.fileExists(atPath: fileNameIconLocalPath) && FileManager.default.fileExists(atPath: fileNamePreviewLocalPath) {
|
||||
etagResource = metadata.etagResource
|
||||
}
|
||||
|
||||
NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: fileNamePath,
|
||||
fileNamePreviewLocalPath: fileNamePreviewLocalPath,
|
||||
widthPreview: NCGlobal.shared.sizePreview,
|
||||
heightPreview: NCGlobal.shared.sizePreview,
|
||||
fileNameIconLocalPath: fileNameIconLocalPath,
|
||||
sizeIcon: NCGlobal.shared.sizeIcon,
|
||||
etag: etagResource,
|
||||
options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { _, imagePreview, _, _, etag, error in
|
||||
|
||||
if error == .success, let image = imagePreview {
|
||||
NCManageDatabase.shared.setMetadataEtagResource(ocId: self.metadata.ocId, etagResource: etag)
|
||||
DispatchQueue.main.async {
|
||||
if self.metadata.ocId == self.cell?.fileObjectId, let filePreviewImageView = self.cell?.filePreviewImageView {
|
||||
UIView.transition(with: filePreviewImageView,
|
||||
duration: 0.75,
|
||||
options: .transitionCrossDissolve,
|
||||
animations: { filePreviewImageView.image = image },
|
||||
completion: nil)
|
||||
} else {
|
||||
self.collectionView?.reloadData()
|
||||
}
|
||||
}
|
||||
NCImageCache.shared.setMediaImage(ocId: self.metadata.ocId, etag: self.metadata.etag, image: .actual(image))
|
||||
}
|
||||
self.finish()
|
||||
}
|
||||
guard let serverUrl = serverUrl else { return }
|
||||
let home = utilityFileSystem.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId)
|
||||
mediaPath = serverUrl.replacingOccurrences(of: home, with: "")
|
||||
NCManageDatabase.shared.setAccountMediaPath(mediaPath, account: appDelegate.account)
|
||||
reloadDataSource()
|
||||
timerSearchNewMedia?.invalidate()
|
||||
timerSearchNewMedia = Timer.scheduledTimer(timeInterval: timeIntervalSearchNewMedia, target: self, selector: #selector(self.searchMediaUI), userInfo: nil, repeats: false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
//
|
||||
// NCMediaCommandView.swift
|
||||
// Nextcloud
|
||||
//
|
||||
// Created by Marino Faggiana on 25/01/24.
|
||||
// Copyright © 2024 Marino Faggiana. All rights reserved.
|
||||
//
|
||||
// Author Marino Faggiana <marino.faggiana@nextcloud.com>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import NextcloudKit
|
||||
|
||||
class NCMediaCommandView: UIView {
|
||||
|
||||
@IBOutlet weak var title: UILabel!
|
||||
@IBOutlet weak var selectButton: UIButton!
|
||||
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
|
||||
@IBOutlet weak var moreButton: UIButton!
|
||||
|
||||
var mediaView: NCMedia!
|
||||
var attributesZoomIn: UIMenuElement.Attributes = []
|
||||
var attributesZoomOut: UIMenuElement.Attributes = []
|
||||
let gradient: CAGradientLayer = CAGradientLayer()
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
title.text = ""
|
||||
|
||||
selectButton.backgroundColor = .systemGray4.withAlphaComponent(0.6)
|
||||
selectButton.layer.cornerRadius = 15
|
||||
selectButton.layer.masksToBounds = true
|
||||
selectButton.setTitle( NSLocalizedString("_select_", comment: ""), for: .normal)
|
||||
|
||||
moreButton.changesSelectionAsPrimaryAction = false
|
||||
|
||||
gradient.frame = bounds
|
||||
gradient.startPoint = CGPoint(x: 0, y: 0.5)
|
||||
gradient.endPoint = CGPoint(x: 0, y: 1)
|
||||
gradient.colors = [UIColor.black.withAlphaComponent(UIAccessibility.isReduceTransparencyEnabled ? 0.8 : 0.4).cgColor, UIColor.clear.cgColor]
|
||||
layer.insertSublayer(gradient, at: 0)
|
||||
}
|
||||
|
||||
override func layoutSublayers(of layer: CALayer) {
|
||||
super.layoutSublayers(of: layer)
|
||||
gradient.frame = bounds
|
||||
}
|
||||
|
||||
@IBAction func selectButtonPressed(_ sender: UIButton) {
|
||||
if mediaView.isEditMode {
|
||||
setMoreButton()
|
||||
} else {
|
||||
setMoreButtonDelete()
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func trashButtonPressed(_ sender: UIButton) {
|
||||
|
||||
if !mediaView.selectOcId.isEmpty {
|
||||
let selectOcId = mediaView.selectOcId
|
||||
var title = NSLocalizedString("_delete_", comment: "")
|
||||
if selectOcId.count > 1 {
|
||||
title = NSLocalizedString("_delete_selected_files_", comment: "")
|
||||
}
|
||||
let alertController = UIAlertController(
|
||||
title: title,
|
||||
message: "",
|
||||
preferredStyle: .alert)
|
||||
alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (_: UIAlertAction) in
|
||||
|
||||
self.setMoreButton()
|
||||
|
||||
Task {
|
||||
var error = NKError()
|
||||
var ocIds: [String] = []
|
||||
for ocId in selectOcId where error == .success {
|
||||
if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
|
||||
error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false)
|
||||
if error == .success {
|
||||
ocIds.append(metadata.ocId)
|
||||
}
|
||||
}
|
||||
}
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocIds, "onlyLocalCache": false, "error": error])
|
||||
}
|
||||
})
|
||||
alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (_: UIAlertAction) in })
|
||||
|
||||
mediaView.present(alertController, animated: true, completion: { })
|
||||
}
|
||||
}
|
||||
|
||||
func setMoreButton() {
|
||||
|
||||
moreButton.backgroundColor = .systemGray4.withAlphaComponent(0.6)
|
||||
moreButton.layer.cornerRadius = 15
|
||||
moreButton.layer.masksToBounds = true
|
||||
moreButton.showsMenuAsPrimaryAction = true
|
||||
moreButton.configuration = UIButton.Configuration.plain()
|
||||
let image = UIImage(systemName: "ellipsis")
|
||||
moreButton.setImage(image, for: .normal)
|
||||
|
||||
mediaView.isEditMode = false
|
||||
mediaView.selectOcId.removeAll()
|
||||
mediaView.collectionView?.reloadData()
|
||||
|
||||
selectButton.setTitle( NSLocalizedString("_select_", comment: ""), for: .normal)
|
||||
}
|
||||
|
||||
func setMoreButtonDelete() {
|
||||
|
||||
moreButton.backgroundColor = .clear
|
||||
moreButton.showsMenuAsPrimaryAction = false
|
||||
moreButton.configuration = UIButton.Configuration.plain()
|
||||
let image = UIImage(systemName: "trash.circle", withConfiguration: UIImage.SymbolConfiguration(pointSize: 25))?.withTintColor(.red, renderingMode: .alwaysOriginal)
|
||||
moreButton.setImage(image, for: .normal)
|
||||
|
||||
mediaView.isEditMode = true
|
||||
|
||||
selectButton.setTitle( NSLocalizedString("_cancel_", comment: ""), for: .normal)
|
||||
}
|
||||
|
||||
func createMenu() {
|
||||
|
||||
if let itemForLine = mediaView?.layout.itemForLine, let maxImageGrid = mediaView?.maxImageGrid {
|
||||
if itemForLine >= maxImageGrid - 1 {
|
||||
self.attributesZoomIn = []
|
||||
self.attributesZoomOut = .disabled
|
||||
} else if itemForLine <= 1 {
|
||||
self.attributesZoomIn = .disabled
|
||||
self.attributesZoomOut = []
|
||||
} else {
|
||||
self.attributesZoomIn = []
|
||||
self.attributesZoomOut = []
|
||||
}
|
||||
}
|
||||
|
||||
let topAction = UIMenu(title: "", options: .displayInline, children: [
|
||||
UIMenu(title: NSLocalizedString("_zoom_", comment: ""), children: [
|
||||
UIAction(title: NSLocalizedString("_zoom_out_", comment: ""), image: UIImage(systemName: "minus.magnifyingglass"), attributes: self.attributesZoomOut) { _ in
|
||||
guard let mediaView = self.mediaView else { return }
|
||||
UIView.animate(withDuration: 0.0, animations: {
|
||||
mediaView.layout.itemForLine += 1
|
||||
self.createMenu()
|
||||
mediaView.collectionView.collectionViewLayout.invalidateLayout()
|
||||
NCKeychain().mediaItemForLine = Int(mediaView.layout.itemForLine)
|
||||
})
|
||||
},
|
||||
UIAction(title: NSLocalizedString("_zoom_in_", comment: ""), image: UIImage(systemName: "plus.magnifyingglass"), attributes: self.attributesZoomIn) { _ in
|
||||
UIView.animate(withDuration: 0.0, animations: {
|
||||
self.mediaView.layout.itemForLine -= 1
|
||||
self.createMenu()
|
||||
self.mediaView.collectionView.collectionViewLayout.invalidateLayout()
|
||||
NCKeychain().mediaItemForLine = Int(self.mediaView.layout.itemForLine)
|
||||
})
|
||||
}
|
||||
]),
|
||||
UIMenu(title: NSLocalizedString("_media_view_options_", comment: ""), children: [
|
||||
UIAction(title: NSLocalizedString("_media_viewimage_show_", comment: ""), image: UIImage(systemName: "photo")) { _ in
|
||||
self.mediaView.showOnlyImages = true
|
||||
self.mediaView.showOnlyVideos = false
|
||||
self.mediaView.reloadDataSource()
|
||||
},
|
||||
UIAction(title: NSLocalizedString("_media_viewvideo_show_", comment: ""), image: UIImage(systemName: "video")) { _ in
|
||||
self.mediaView.showOnlyImages = false
|
||||
self.mediaView.showOnlyVideos = true
|
||||
self.mediaView.reloadDataSource()
|
||||
},
|
||||
UIAction(title: NSLocalizedString("_media_show_all_", comment: ""), image: UIImage(systemName: "photo.on.rectangle")) { _ in
|
||||
self.mediaView.showOnlyImages = false
|
||||
self.mediaView.showOnlyVideos = false
|
||||
self.mediaView.reloadDataSource()
|
||||
}
|
||||
]),
|
||||
UIAction(title: NSLocalizedString("_select_media_folder_", comment: ""), image: UIImage(systemName: "folder"), handler: { _ in
|
||||
guard let navigationController = UIStoryboard(name: "NCSelect", bundle: nil).instantiateInitialViewController() as? UINavigationController,
|
||||
let viewController = navigationController.topViewController as? NCSelect else { return }
|
||||
viewController.delegate = self.mediaView
|
||||
viewController.typeOfCommandView = .select
|
||||
viewController.type = "mediaFolder"
|
||||
self.mediaView.present(navigationController, animated: true, completion: nil)
|
||||
})
|
||||
])
|
||||
|
||||
let playFile = UIAction(title: NSLocalizedString("_play_from_files_", comment: ""), image: UIImage(systemName: "play.circle")) { _ in
|
||||
guard let tabBarController = self.mediaView.appDelegate.window?.rootViewController as? UITabBarController else { return }
|
||||
self.mediaView.documentPickerViewController = NCDocumentPickerViewController(tabBarController: tabBarController, isViewerMedia: true, allowsMultipleSelection: false, viewController: self.mediaView)
|
||||
}
|
||||
let playURL = UIAction(title: NSLocalizedString("_play_from_url_", comment: ""), image: UIImage(systemName: "link")) { _ in
|
||||
let alert = UIAlertController(title: NSLocalizedString("_valid_video_url_", comment: ""), message: nil, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil))
|
||||
alert.addTextField(configurationHandler: { textField in
|
||||
textField.placeholder = "http://myserver.com/movie.mkv"
|
||||
})
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in
|
||||
guard let stringUrl = alert.textFields?.first?.text, !stringUrl.isEmpty, let url = URL(string: stringUrl) else { return }
|
||||
let fileName = url.lastPathComponent
|
||||
let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
|
||||
let metadata = NCManageDatabase.shared.createMetadata(account: appDelegate.account, user: appDelegate.user, userId: appDelegate.userId, fileName: fileName, fileNameView: fileName, ocId: NSUUID().uuidString, serverUrl: "", urlBase: appDelegate.urlBase, url: stringUrl, contentType: "")
|
||||
NCManageDatabase.shared.addMetadata(metadata)
|
||||
NCViewer().view(viewController: self.mediaView, metadata: metadata, metadatas: [metadata], imageIcon: nil)
|
||||
}))
|
||||
self.mediaView.present(alert, animated: true)
|
||||
}
|
||||
|
||||
moreButton.menu = UIMenu(title: "", children: [topAction, playFile, playURL])
|
||||
}
|
||||
|
||||
func setMediaCommand() {
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
self.title.text = ""
|
||||
if let visibleCells = self.mediaView.collectionView?.indexPathsForVisibleItems.sorted(by: { $0.row < $1.row }).compactMap({ self.mediaView.collectionView?.cellForItem(at: $0) }) {
|
||||
if let cell = visibleCells.first as? NCGridMediaCell {
|
||||
self.title.text = ""
|
||||
if let date = cell.date {
|
||||
self.title.text = self.mediaView.utility.getTitleFromDate(date)
|
||||
}
|
||||
}
|
||||
}
|
||||
if let metadatas = self.mediaView.metadatas, !metadatas.isEmpty {
|
||||
self.selectButton.isHidden = false
|
||||
if self.gradient.isHidden {
|
||||
UIView.animate(withDuration: 0.3) {
|
||||
self.gradient.isHidden = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.selectButton.isHidden = true
|
||||
if !self.gradient.isHidden {
|
||||
UIView.animate(withDuration: 0.3) {
|
||||
self.gradient.isHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@
|
|||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22130"/>
|
||||
<capability name="Image references" minToolsVersion="12.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
@ -15,164 +14,65 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="i1s-Qa-dG1">
|
||||
<rect key="frame" x="297" y="69" width="40" height="40"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="e3Q-e0-SQa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="40" height="40"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="jSO-Vb-jcU">
|
||||
<rect key="frame" x="0.0" y="0.0" width="40" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="40" id="5zz-h5-hx9"/>
|
||||
<constraint firstAttribute="height" constant="40" id="lzK-bd-NlR"/>
|
||||
</constraints>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="imageEdgeInsets" minX="12" minY="12" maxX="12" maxY="12"/>
|
||||
<state key="normal" image="plus.forwardslash.minus" catalog="system">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<state key="disabled">
|
||||
<color key="titleColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="gridSwitchButtonPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="0jB-EV-iMe"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ZkU-dK-sp1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="19.666666666666668" height="40"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="imageEdgeInsets" minX="12" minY="12" maxX="12" maxY="12"/>
|
||||
<state key="normal" image="plus" catalog="system">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<state key="disabled">
|
||||
<color key="titleColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="zoomInPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="YPO-oL-Gf5"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NwM-bk-QAK">
|
||||
<rect key="frame" x="19.666666666666686" y="8" width="1" height="24"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="1" id="1cE-rd-mYI"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="swp-Cd-CbD">
|
||||
<rect key="frame" x="20.666666666666686" y="0.0" width="19.333333333333329" height="40"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="imageEdgeInsets" minX="12" minY="12" maxX="12" maxY="12"/>
|
||||
<state key="normal">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<imageReference key="image" image="minus" catalog="system" symbolScale="default"/>
|
||||
</state>
|
||||
<state key="disabled">
|
||||
<color key="titleColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="zoomOutPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="xIo-6p-l7h"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="NwM-bk-QAK" firstAttribute="top" secondItem="e3Q-e0-SQa" secondAttribute="top" constant="8" id="3V7-Bl-HeS"/>
|
||||
<constraint firstItem="jSO-Vb-jcU" firstAttribute="centerY" secondItem="e3Q-e0-SQa" secondAttribute="centerY" id="5ap-Yp-VlG"/>
|
||||
<constraint firstItem="NwM-bk-QAK" firstAttribute="centerX" secondItem="e3Q-e0-SQa" secondAttribute="centerX" id="70K-vU-VR6"/>
|
||||
<constraint firstItem="NwM-bk-QAK" firstAttribute="leading" secondItem="ZkU-dK-sp1" secondAttribute="trailing" id="Lcu-89-Iys"/>
|
||||
<constraint firstAttribute="bottom" secondItem="NwM-bk-QAK" secondAttribute="bottom" constant="8" id="O8t-uT-Dhh"/>
|
||||
<constraint firstItem="jSO-Vb-jcU" firstAttribute="centerX" secondItem="e3Q-e0-SQa" secondAttribute="centerX" id="YFf-Kh-lAp"/>
|
||||
<constraint firstAttribute="bottom" secondItem="swp-Cd-CbD" secondAttribute="bottom" id="dgT-Np-dTd"/>
|
||||
<constraint firstItem="ZkU-dK-sp1" firstAttribute="leading" secondItem="e3Q-e0-SQa" secondAttribute="leading" id="fyg-tQ-tfR"/>
|
||||
<constraint firstItem="ZkU-dK-sp1" firstAttribute="top" secondItem="e3Q-e0-SQa" secondAttribute="top" id="o2e-4h-ylb"/>
|
||||
<constraint firstAttribute="trailing" secondItem="swp-Cd-CbD" secondAttribute="trailing" id="oaa-Rc-bYC"/>
|
||||
<constraint firstItem="swp-Cd-CbD" firstAttribute="leading" secondItem="NwM-bk-QAK" secondAttribute="trailing" id="omu-Hf-g4C"/>
|
||||
<constraint firstAttribute="bottom" secondItem="ZkU-dK-sp1" secondAttribute="bottom" id="pfE-6t-fCg"/>
|
||||
<constraint firstItem="swp-Cd-CbD" firstAttribute="top" secondItem="e3Q-e0-SQa" secondAttribute="top" id="yoe-G6-vaw"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="mEu-PL-xc2"/>
|
||||
<constraint firstAttribute="width" constant="40" id="wkm-j1-5v4"/>
|
||||
</constraints>
|
||||
<blurEffect style="regular"/>
|
||||
</visualEffectView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IxY-xH-yZQ">
|
||||
<rect key="frame" x="8" y="69" width="281" height="40"/>
|
||||
<rect key="frame" x="8" y="67" width="213" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="S6o-Pa-sxy"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="24"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="enp-xt-Y5y">
|
||||
<rect key="frame" x="345" y="69" width="40" height="40"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="KKR-Hr-av8">
|
||||
<rect key="frame" x="0.0" y="0.0" width="40" height="40"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3qs-Hm-qLL">
|
||||
<rect key="frame" x="0.0" y="0.0" width="40" height="40"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="imageEdgeInsets" minX="4" minY="4" maxX="4" maxY="4"/>
|
||||
<state key="normal" image="ellipsis" catalog="system"/>
|
||||
<connections>
|
||||
<action selector="moreButtonPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="EeF-Eg-Pqi"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="3qs-Hm-qLL" secondAttribute="bottom" id="B32-ni-kC4"/>
|
||||
<constraint firstItem="3qs-Hm-qLL" firstAttribute="leading" secondItem="KKR-Hr-av8" secondAttribute="leading" id="NSe-Qy-mmd"/>
|
||||
<constraint firstItem="3qs-Hm-qLL" firstAttribute="top" secondItem="KKR-Hr-av8" secondAttribute="top" id="URa-a2-sfx"/>
|
||||
<constraint firstAttribute="trailing" secondItem="3qs-Hm-qLL" secondAttribute="trailing" id="fjn-eP-8DS"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="Ftv-5S-RKc"/>
|
||||
<constraint firstAttribute="width" constant="40" id="JJ2-fQ-ew9"/>
|
||||
</constraints>
|
||||
<blurEffect style="regular"/>
|
||||
</visualEffectView>
|
||||
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="XVj-jD-9KA">
|
||||
<rect key="frame" x="186.66666666666666" y="50" width="20" height="20"/>
|
||||
<rect key="frame" x="229" y="77" width="20" height="20"/>
|
||||
<color key="color" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</activityIndicatorView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3qs-Hm-qLL">
|
||||
<rect key="frame" x="355" y="72" width="30" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="l6a-hf-7l2"/>
|
||||
<constraint firstAttribute="width" constant="30" id="uVw-bC-TZq"/>
|
||||
</constraints>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="imageEdgeInsets" minX="4" minY="4" maxX="4" maxY="4"/>
|
||||
<connections>
|
||||
<action selector="trashButtonPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="7mo-8p-bep"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EFV-eb-pFF">
|
||||
<rect key="frame" x="257" y="72" width="90" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="90" id="Hf1-Hv-Jpi"/>
|
||||
<constraint firstAttribute="height" constant="30" id="tTh-bW-DMw"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="Select"/>
|
||||
<connections>
|
||||
<action selector="selectButtonPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="YfJ-ms-0G1"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="XVj-jD-9KA" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="-9" id="Cpb-Vg-sov"/>
|
||||
<constraint firstItem="i1s-Qa-dG1" firstAttribute="leading" secondItem="IxY-xH-yZQ" secondAttribute="trailing" constant="8" id="Owq-aa-Sr6"/>
|
||||
<constraint firstItem="enp-xt-Y5y" firstAttribute="leading" secondItem="i1s-Qa-dG1" secondAttribute="trailing" constant="8" id="XcU-G8-k0a"/>
|
||||
<constraint firstItem="XVj-jD-9KA" firstAttribute="centerY" secondItem="IxY-xH-yZQ" secondAttribute="centerY" id="4nZ-Ea-KMB"/>
|
||||
<constraint firstItem="3qs-Hm-qLL" firstAttribute="centerY" secondItem="IxY-xH-yZQ" secondAttribute="centerY" id="AgJ-WD-mqU"/>
|
||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="3qs-Hm-qLL" secondAttribute="trailing" constant="8" id="FtF-ES-dyl"/>
|
||||
<constraint firstItem="EFV-eb-pFF" firstAttribute="leading" secondItem="XVj-jD-9KA" secondAttribute="trailing" constant="8" id="I7N-mB-wyc"/>
|
||||
<constraint firstItem="IxY-xH-yZQ" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="8" id="ZhO-pY-Qwi"/>
|
||||
<constraint firstItem="i1s-Qa-dG1" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="10" id="cWc-xe-8un"/>
|
||||
<constraint firstItem="XVj-jD-9KA" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="lqb-pC-WUR"/>
|
||||
<constraint firstItem="IxY-xH-yZQ" firstAttribute="centerY" secondItem="i1s-Qa-dG1" secondAttribute="centerY" id="mJJ-pT-yA3"/>
|
||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="enp-xt-Y5y" secondAttribute="trailing" constant="8" id="rSU-Dz-YXW"/>
|
||||
<constraint firstItem="enp-xt-Y5y" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="10" id="z6I-sd-mmD"/>
|
||||
<constraint firstItem="IxY-xH-yZQ" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="8" id="mX3-Fm-K1m"/>
|
||||
<constraint firstItem="EFV-eb-pFF" firstAttribute="centerY" secondItem="IxY-xH-yZQ" secondAttribute="centerY" id="ozT-m6-dct"/>
|
||||
<constraint firstItem="3qs-Hm-qLL" firstAttribute="leading" secondItem="EFV-eb-pFF" secondAttribute="trailing" constant="8" id="t2r-N2-lJR"/>
|
||||
<constraint firstItem="XVj-jD-9KA" firstAttribute="leading" secondItem="IxY-xH-yZQ" secondAttribute="trailing" constant="8" id="ztz-0d-9Mr"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="activityIndicator" destination="XVj-jD-9KA" id="cSB-RJ-RCZ"/>
|
||||
<outlet property="buttonControlWidthConstraint" destination="wkm-j1-5v4" id="SHm-F2-NjB"/>
|
||||
<outlet property="controlButtonView" destination="i1s-Qa-dG1" id="5q4-uE-oC5"/>
|
||||
<outlet property="gridSwitchButton" destination="jSO-Vb-jcU" id="geS-eg-obV"/>
|
||||
<outlet property="moreButton" destination="3qs-Hm-qLL" id="OPi-J6-wkl"/>
|
||||
<outlet property="moreView" destination="enp-xt-Y5y" id="Fqg-Wl-V7h"/>
|
||||
<outlet property="separatorView" destination="NwM-bk-QAK" id="wRe-37-oxD"/>
|
||||
<outlet property="selectButton" destination="EFV-eb-pFF" id="AJu-vY-GS3"/>
|
||||
<outlet property="title" destination="IxY-xH-yZQ" id="ZNZ-Jy-JbH"/>
|
||||
<outlet property="zoomInButton" destination="ZkU-dK-sp1" id="bC0-Wo-2as"/>
|
||||
<outlet property="zoomOutButton" destination="swp-Cd-CbD" id="wvm-jt-8nI"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="138.75" y="152.5"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="ellipsis" catalog="system" width="128" height="37"/>
|
||||
<image name="minus" catalog="system" width="128" height="26"/>
|
||||
<image name="plus" catalog="system" width="128" height="113"/>
|
||||
<image name="plus.forwardslash.minus" catalog="system" width="128" height="115"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
//
|
||||
// NCMediaDataSource.swift
|
||||
// Nextcloud
|
||||
//
|
||||
// Created by Marino Faggiana on 25/01/24.
|
||||
// Copyright © 2024 Marino Faggiana. All rights reserved.
|
||||
//
|
||||
// Author Marino Faggiana <marino.faggiana@nextcloud.com>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import NextcloudKit
|
||||
|
||||
extension NCMedia {
|
||||
|
||||
func getPredicate(showAll: Bool = false) -> NSPredicate {
|
||||
|
||||
let startServerUrl = NCUtilityFileSystem().getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) + mediaPath
|
||||
|
||||
if showAll {
|
||||
return NSPredicate(format: NCImageCache.shared.showAllPredicateMediaString, appDelegate.account, startServerUrl)
|
||||
} else if showOnlyImages {
|
||||
return NSPredicate(format: NCImageCache.shared.showOnlyPredicateMediaString, appDelegate.account, startServerUrl, NKCommon.TypeClassFile.image.rawValue)
|
||||
} else if showOnlyVideos {
|
||||
return NSPredicate(format: NCImageCache.shared.showOnlyPredicateMediaString, appDelegate.account, startServerUrl, NKCommon.TypeClassFile.video.rawValue)
|
||||
} else {
|
||||
return NSPredicate(format: NCImageCache.shared.showBothPredicateMediaString, appDelegate.account, startServerUrl)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func reloadDataSource() {
|
||||
guard !appDelegate.account.isEmpty else { return }
|
||||
|
||||
self.metadatas = NCImageCache.shared.getMediaMetadatas(account: self.appDelegate.account, predicate: self.getPredicate())
|
||||
DispatchQueue.main.async {
|
||||
self.collectionView?.reloadData()
|
||||
self.mediaCommandView?.setMediaCommand()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Search media
|
||||
|
||||
@objc func searchMediaUI() {
|
||||
|
||||
var lessDate: Date?
|
||||
var greaterDate: Date?
|
||||
let firstMetadataDate = metadatas?.first?.date as? Date
|
||||
let lastMetadataDate = metadatas?.last?.date as? Date
|
||||
|
||||
guard loadingTask == nil, !isEditMode else {
|
||||
return
|
||||
}
|
||||
|
||||
if let visibleCells = self.collectionView?.indexPathsForVisibleItems.sorted(by: { $0.row < $1.row }).compactMap({ self.collectionView?.cellForItem(at: $0) }) {
|
||||
// first date
|
||||
let firstCellDate = (visibleCells.first as? NCGridMediaCell)?.date
|
||||
if firstCellDate == firstMetadataDate {
|
||||
lessDate = Date.distantFuture
|
||||
} else {
|
||||
if let date = firstCellDate {
|
||||
lessDate = Calendar.current.date(byAdding: .second, value: 1, to: date)!
|
||||
} else {
|
||||
lessDate = Date.distantFuture
|
||||
}
|
||||
}
|
||||
// last date
|
||||
let lastCellDate = (visibleCells.last as? NCGridMediaCell)?.date
|
||||
if lastCellDate == lastMetadataDate {
|
||||
greaterDate = Date.distantPast
|
||||
} else {
|
||||
if let date = lastCellDate {
|
||||
greaterDate = Calendar.current.date(byAdding: .second, value: -1, to: date)!
|
||||
} else {
|
||||
greaterDate = Date.distantPast
|
||||
}
|
||||
}
|
||||
|
||||
if let lessDate, let greaterDate {
|
||||
mediaCommandView?.activityIndicator.startAnimating()
|
||||
loadingTask = Task.detached {
|
||||
await self.collectionView.reloadData()
|
||||
let results = await self.searchMedia(account: self.appDelegate.account, lessDate: lessDate, greaterDate: greaterDate)
|
||||
print("Media results changed items: \(results.isChanged)")
|
||||
if results.error != .success {
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Media search new media error code \(results.error.errorCode) " + results.error.errorDescription)
|
||||
}
|
||||
await self.mediaCommandView?.activityIndicator.stopAnimating()
|
||||
Task { @MainActor in
|
||||
self.loadingTask = nil
|
||||
}
|
||||
if results.error == .success, results.lessDate == Date.distantFuture, results.greaterDate == Date.distantPast, !results.isChanged, results.metadatasCount == 0 {
|
||||
Task { @MainActor in
|
||||
self.metadatas = nil
|
||||
}
|
||||
await self.collectionView.reloadData()
|
||||
}
|
||||
if results.isChanged {
|
||||
await self.reloadDataSource()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func searchMedia(account: String, lessDate: Date, greaterDate: Date, limit: Int = 300, timeout: TimeInterval = 60) async -> (account: String, lessDate: Date?, greaterDate: Date?, metadatasCount: Int, isChanged: Bool, error: NKError) {
|
||||
|
||||
guard let mediaPath = NCManageDatabase.shared.getActiveAccount()?.mediaPath else {
|
||||
return(account, lessDate, greaterDate, 0, false, NKError())
|
||||
}
|
||||
let options = NKRequestOptions(timeout: timeout, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
|
||||
let results = await NextcloudKit.shared.searchMedia(path: mediaPath, lessDate: lessDate, greaterDate: greaterDate, elementDate: "d:getlastmodified/", limit: limit, showHiddenFiles: NCKeychain().showHiddenFiles, includeHiddenFiles: [], options: options)
|
||||
|
||||
if results.account == account, results.error == .success {
|
||||
let metadatas = await NCManageDatabase.shared.convertFilesToMetadatas(results.files, useMetadataFolder: false).metadatas
|
||||
var predicate = NSPredicate(format: "date > %@ AND date < %@", greaterDate as NSDate, lessDate as NSDate)
|
||||
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, self.getPredicate(showAll: true)])
|
||||
let resultsUpdate = NCManageDatabase.shared.updateMetadatas(metadatas, predicate: predicate)
|
||||
let isChaged: Bool = resultsUpdate.metadatasChanged || resultsUpdate.metadatasChangedCount != 0
|
||||
return(account, lessDate, greaterDate, metadatas.count, isChaged, results.error)
|
||||
} else {
|
||||
return(account, lessDate, greaterDate, 0, false, results.error)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// NCMediaDownloadThumbnaill.swift
|
||||
// Nextcloud
|
||||
//
|
||||
// Created by Marino Faggiana on 25/01/24.
|
||||
// Copyright © 2024 Marino Faggiana. All rights reserved.
|
||||
//
|
||||
// Author Marino Faggiana <marino.faggiana@nextcloud.com>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import NextcloudKit
|
||||
import Queuer
|
||||
|
||||
class NCMediaDownloadThumbnaill: ConcurrentOperation {
|
||||
|
||||
var metadata: tableMetadata
|
||||
var collectionView: UICollectionView?
|
||||
var fileNamePath: String
|
||||
var fileNamePreviewLocalPath: String
|
||||
var fileNameIconLocalPath: String
|
||||
let utilityFileSystem = NCUtilityFileSystem()
|
||||
|
||||
init(metadata: tableMetadata, collectionView: UICollectionView?) {
|
||||
self.metadata = tableMetadata.init(value: metadata)
|
||||
self.collectionView = collectionView
|
||||
self.fileNamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId)
|
||||
self.fileNamePreviewLocalPath = utilityFileSystem.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)
|
||||
self.fileNameIconLocalPath = utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)
|
||||
}
|
||||
|
||||
override func start() {
|
||||
|
||||
guard !isCancelled else { return self.finish() }
|
||||
|
||||
var etagResource: String?
|
||||
if FileManager.default.fileExists(atPath: fileNameIconLocalPath) && FileManager.default.fileExists(atPath: fileNamePreviewLocalPath) {
|
||||
etagResource = metadata.etagResource
|
||||
}
|
||||
|
||||
NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: fileNamePath,
|
||||
fileNamePreviewLocalPath: fileNamePreviewLocalPath,
|
||||
widthPreview: NCGlobal.shared.sizePreview,
|
||||
heightPreview: NCGlobal.shared.sizePreview,
|
||||
fileNameIconLocalPath: fileNameIconLocalPath,
|
||||
sizeIcon: NCGlobal.shared.sizeIcon,
|
||||
etag: etagResource,
|
||||
options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { _, imagePreview, _, _, etag, error in
|
||||
|
||||
if error == .success, let image = imagePreview {
|
||||
NCManageDatabase.shared.setMetadataEtagResource(ocId: self.metadata.ocId, etagResource: etag)
|
||||
DispatchQueue.main.async {
|
||||
if let visibleCells = self.collectionView?.indexPathsForVisibleItems.sorted(by: { $0.row < $1.row }).compactMap({ self.collectionView?.cellForItem(at: $0) }) {
|
||||
for case let cell as NCGridMediaCell in visibleCells {
|
||||
if cell.fileObjectId == self.metadata.ocId, let filePreviewImageView = cell.filePreviewImageView {
|
||||
UIView.transition(with: filePreviewImageView,
|
||||
duration: 0.75,
|
||||
options: .transitionCrossDissolve,
|
||||
animations: { filePreviewImageView.image = image },
|
||||
completion: nil)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NCImageCache.shared.setMediaImage(ocId: self.metadata.ocId, etag: self.metadata.etag, image: .actual(image))
|
||||
}
|
||||
self.finish()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// NCMediaGridLayout.swift
|
||||
// Nextcloud
|
||||
//
|
||||
// Created by Marino Faggiana on 27/01/24.
|
||||
// Copyright © 2024 Marino Faggiana. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class NCMediaGridLayout: UICollectionViewFlowLayout {
|
||||
|
||||
var marginLeftRight: CGFloat = 2
|
||||
var itemForLine: CGFloat = 3
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
|
||||
sectionHeadersPinToVisibleBounds = false
|
||||
|
||||
minimumInteritemSpacing = 0
|
||||
minimumLineSpacing = marginLeftRight
|
||||
|
||||
self.scrollDirection = .vertical
|
||||
self.sectionInset = UIEdgeInsets(top: 0, left: marginLeftRight, bottom: 0, right: marginLeftRight)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override var itemSize: CGSize {
|
||||
get {
|
||||
if let collectionView = collectionView {
|
||||
|
||||
let itemWidth: CGFloat = (collectionView.frame.width - marginLeftRight * 2 - marginLeftRight * (itemForLine - 1)) / itemForLine
|
||||
let itemHeight: CGFloat = itemWidth
|
||||
|
||||
return CGSize(width: itemWidth, height: itemHeight)
|
||||
}
|
||||
|
||||
// Default fallback
|
||||
return CGSize(width: 100, height: 100)
|
||||
}
|
||||
set {
|
||||
super.itemSize = newValue
|
||||
}
|
||||
}
|
||||
|
||||
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint {
|
||||
return proposedContentOffset
|
||||
}
|
||||
}
|
||||
|
||||
extension NCMedia: UICollectionViewDelegateFlowLayout {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
|
||||
return CGSize(width: collectionView.frame.width, height: 0)
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
|
||||
return CGSize(width: collectionView.frame.width, height: 0)
|
||||
}
|
||||
}
|
|
@ -287,9 +287,16 @@ extension NCCollectionViewCommon {
|
|||
order: 110,
|
||||
action: { _ in
|
||||
if self.utilityFileSystem.fileProviderStorageExists(metadata) {
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": NCGlobal.shared.selectorSaveAsScan, "error": NKError(), "account": metadata.account])
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"selector": NCGlobal.shared.selectorSaveAsScan,
|
||||
"error": NKError(),
|
||||
"account": metadata.account])
|
||||
} else {
|
||||
NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorSaveAsScan) { _, _ in }
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: NCGlobal.shared.selectorSaveAsScan) else { return }
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: true)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -347,9 +354,16 @@ extension NCCollectionViewCommon {
|
|||
order: 150,
|
||||
action: { _ in
|
||||
if self.utilityFileSystem.fileProviderStorageExists(metadata) {
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": NCGlobal.shared.selectorLoadFileQuickLook, "error": NKError(), "account": metadata.account])
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"selector": NCGlobal.shared.selectorLoadFileQuickLook,
|
||||
"error": NKError(),
|
||||
"account": metadata.account])
|
||||
} else {
|
||||
NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadFileQuickLook) { _, _ in }
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: NCGlobal.shared.selectorLoadFileQuickLook) else { return }
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: true)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -74,10 +74,18 @@ class NCContextMenu: NSObject {
|
|||
let openIn = UIAction(title: NSLocalizedString("_open_in_", comment: ""),
|
||||
image: UIImage(systemName: "square.and.arrow.up") ) { _ in
|
||||
if self.utilityFileSystem.fileProviderStorageExists(metadata) {
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": NCGlobal.shared.selectorOpenIn, "error": NKError(), "account": metadata.account])
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"selector": NCGlobal.shared.selectorOpenIn,
|
||||
"error": NKError(),
|
||||
"account": metadata.account])
|
||||
} else {
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: NCGlobal.shared.selectorOpenIn) else { return }
|
||||
hud.show(in: viewController.view)
|
||||
NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorOpenIn, notificationCenterProgressTask: false) { request in
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: false) {
|
||||
} requestHandler: { request in
|
||||
downloadRequest = request
|
||||
} progressHandler: { progress in
|
||||
hud.progress = Float(progress.fractionCompleted)
|
||||
|
@ -106,8 +114,10 @@ class NCContextMenu: NSObject {
|
|||
if self.utilityFileSystem.fileProviderStorageExists(metadata) {
|
||||
NCActionCenter.shared.saveAlbum(metadata: metadata)
|
||||
} else {
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: NCGlobal.shared.selectorSaveAlbum) else { return }
|
||||
hud.show(in: viewController.view)
|
||||
NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorSaveAlbum, notificationCenterProgressTask: false) { request in
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: false) {
|
||||
} requestHandler: { request in
|
||||
downloadRequest = request
|
||||
} progressHandler: { progress in
|
||||
hud.progress = Float(progress.fractionCompleted)
|
||||
|
@ -127,10 +137,18 @@ class NCContextMenu: NSObject {
|
|||
let modify = UIAction(title: NSLocalizedString("_modify_", comment: ""),
|
||||
image: UIImage(systemName: "pencil.tip.crop.circle")) { _ in
|
||||
if self.utilityFileSystem.fileProviderStorageExists(metadata) {
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": NCGlobal.shared.selectorLoadFileQuickLook, "error": NKError(), "account": metadata.account])
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"selector": NCGlobal.shared.selectorLoadFileQuickLook,
|
||||
"error": NKError(),
|
||||
"account": metadata.account])
|
||||
} else {
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: NCGlobal.shared.selectorLoadFileQuickLook) else { return }
|
||||
hud.show(in: viewController.view)
|
||||
NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadFileQuickLook, notificationCenterProgressTask: false) { request in
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: false) {
|
||||
} requestHandler: { request in
|
||||
downloadRequest = request
|
||||
} progressHandler: { progress in
|
||||
hud.progress = Float(progress.fractionCompleted)
|
||||
|
|
|
@ -1,205 +0,0 @@
|
|||
//
|
||||
// NCMedia+Menu.swift
|
||||
// Nextcloud
|
||||
//
|
||||
// Created by Marino Faggiana on 03/03/2021.
|
||||
// Copyright © 2021 Marino Faggiana. All rights reserved.
|
||||
//
|
||||
// Author Marino Faggiana <marino.faggiana@nextcloud.com>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
import NextcloudKit
|
||||
|
||||
extension NCMedia {
|
||||
func tapSelect() {
|
||||
self.isEditMode = false
|
||||
self.selectOcId.removeAll()
|
||||
self.selectIndexPath.removeAll()
|
||||
self.collectionView?.reloadData()
|
||||
}
|
||||
|
||||
func toggleMenu() {
|
||||
|
||||
var actions: [NCMenuAction] = []
|
||||
|
||||
defer { presentMenu(with: actions) }
|
||||
|
||||
if !isEditMode {
|
||||
if let metadatas = self.metadatas, !metadatas.isEmpty {
|
||||
actions.append(
|
||||
NCMenuAction(
|
||||
title: NSLocalizedString("_select_", comment: ""),
|
||||
icon: utility.loadImage(named: "checkmark.circle.fill"),
|
||||
action: { _ in
|
||||
self.isEditMode = true
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
actions.append(.seperator(order: 0))
|
||||
|
||||
actions.append(
|
||||
NCMenuAction(
|
||||
title: NSLocalizedString("_select_media_folder_", comment: ""),
|
||||
icon: utility.loadImage(named: "folder"),
|
||||
action: { _ in
|
||||
if let navigationController = UIStoryboard(name: "NCSelect", bundle: nil).instantiateInitialViewController() as? UINavigationController,
|
||||
let viewController = navigationController.topViewController as? NCSelect {
|
||||
|
||||
viewController.delegate = self
|
||||
viewController.typeOfCommandView = .select
|
||||
viewController.type = "mediaFolder"
|
||||
viewController.selectIndexPath = self.selectIndexPath
|
||||
|
||||
self.present(navigationController, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
actions.append(.seperator(order: 0))
|
||||
|
||||
actions.append(
|
||||
NCMenuAction(
|
||||
title: NSLocalizedString("_media_viewimage_show_", comment: ""),
|
||||
icon: utility.loadImage(named: "photo"),
|
||||
selected: showOnlyImages,
|
||||
on: true,
|
||||
action: { _ in
|
||||
self.showOnlyImages = true
|
||||
self.showOnlyVideos = false
|
||||
self.reloadDataSource()
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
actions.append(
|
||||
NCMenuAction(
|
||||
title: NSLocalizedString("_media_viewvideo_show_", comment: ""),
|
||||
icon: utility.loadImage(named: "video"),
|
||||
selected: showOnlyVideos,
|
||||
on: true,
|
||||
action: { _ in
|
||||
self.showOnlyImages = false
|
||||
self.showOnlyVideos = true
|
||||
self.reloadDataSource()
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
actions.append(
|
||||
NCMenuAction(
|
||||
title: NSLocalizedString("_media_show_all_", comment: ""),
|
||||
icon: utility.loadImage(named: "photo.on.rectangle.angled"),
|
||||
selected: !showOnlyImages && !showOnlyVideos,
|
||||
on: true,
|
||||
action: { _ in
|
||||
self.showOnlyImages = false
|
||||
self.showOnlyVideos = false
|
||||
self.reloadDataSource()
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
actions.append(.seperator(order: 0))
|
||||
|
||||
actions.append(
|
||||
NCMenuAction(
|
||||
title: NSLocalizedString("_play_from_files_", comment: ""),
|
||||
icon: utility.loadImage(named: "play.circle"),
|
||||
action: { _ in
|
||||
if let tabBarController = self.appDelegate.window?.rootViewController as? UITabBarController {
|
||||
self.documentPickerViewController = NCDocumentPickerViewController(tabBarController: tabBarController, isViewerMedia: true, allowsMultipleSelection: false, viewController: self)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
actions.append(
|
||||
NCMenuAction(
|
||||
title: NSLocalizedString("_play_from_url_", comment: ""),
|
||||
icon: utility.loadImage(named: "network"),
|
||||
action: { _ in
|
||||
|
||||
let alert = UIAlertController(title: NSLocalizedString("_valid_video_url_", comment: ""), message: nil, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil))
|
||||
|
||||
alert.addTextField(configurationHandler: { textField in
|
||||
textField.placeholder = "http://myserver.com/movie.mkv"
|
||||
})
|
||||
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in
|
||||
guard let stringUrl = alert.textFields?.first?.text, !stringUrl.isEmpty, let url = URL(string: stringUrl) else { return }
|
||||
let fileName = url.lastPathComponent
|
||||
let metadata = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: fileName, fileNameView: fileName, ocId: NSUUID().uuidString, serverUrl: "", urlBase: self.appDelegate.urlBase, url: stringUrl, contentType: "")
|
||||
NCManageDatabase.shared.addMetadata(metadata)
|
||||
NCViewer().view(viewController: self, metadata: metadata, metadatas: [metadata], imageIcon: nil)
|
||||
}))
|
||||
|
||||
self.present(alert, animated: true)
|
||||
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// CANCEL
|
||||
//
|
||||
actions.append(
|
||||
NCMenuAction(
|
||||
title: NSLocalizedString("_cancel_", comment: ""),
|
||||
icon: utility.loadImage(named: "xmark"),
|
||||
action: { _ in self.tapSelect() }
|
||||
)
|
||||
)
|
||||
|
||||
guard !selectOcId.isEmpty else { return }
|
||||
let selectedMetadatas = selectOcId.compactMap(NCManageDatabase.shared.getMetadataFromOcId)
|
||||
|
||||
//
|
||||
// OPEN IN
|
||||
//
|
||||
actions.append(.openInAction(selectedMetadatas: selectedMetadatas, viewController: self, completion: tapSelect))
|
||||
|
||||
//
|
||||
// SAVE TO PHOTO GALLERY
|
||||
//
|
||||
actions.append(.saveMediaAction(selectedMediaMetadatas: selectedMetadatas, completion: tapSelect))
|
||||
|
||||
//
|
||||
// COPY - MOVE
|
||||
//
|
||||
actions.append(.moveOrCopyAction(selectedMetadatas: selectedMetadatas, indexPath: selectIndexPath, completion: tapSelect))
|
||||
|
||||
//
|
||||
// COPY
|
||||
//
|
||||
actions.append(.copyAction(selectOcId: selectOcId, completion: tapSelect))
|
||||
|
||||
//
|
||||
// DELETE
|
||||
// can't delete from cache because is needed for NCMedia view, and if locked can't delete from server either.
|
||||
if !selectedMetadatas.contains(where: { $0.lock && $0.lockOwner != appDelegate.userId }) {
|
||||
actions.append(.deleteAction(selectedMetadatas: selectedMetadatas, indexPath: selectIndexPath, metadataFolder: nil, viewController: self, completion: tapSelect))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -279,9 +279,16 @@ extension NCMenuAction {
|
|||
order: order,
|
||||
action: { _ in
|
||||
if NCUtilityFileSystem().fileProviderStorageExists(metadata) {
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": NCGlobal.shared.selectorPrint, "error": NKError(), "account": metadata.account])
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"selector": NCGlobal.shared.selectorPrint,
|
||||
"error": NKError(),
|
||||
"account": metadata.account])
|
||||
} else {
|
||||
NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorPrint) { _, _ in }
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: NCGlobal.shared.selectorPrint) else { return }
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: true)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
import UIKit
|
||||
import Queuer
|
||||
import JGProgressHUD
|
||||
import NextcloudKit
|
||||
|
||||
class NCOperationSaveLivePhoto: ConcurrentOperation {
|
||||
|
||||
|
@ -39,7 +40,9 @@ class NCOperationSaveLivePhoto: ConcurrentOperation {
|
|||
}
|
||||
|
||||
override func start() {
|
||||
guard !isCancelled else { return self.finish() }
|
||||
guard !isCancelled,
|
||||
let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: ""),
|
||||
let metadataLive = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: self.metadataMOV.ocId, selector: "") else { return self.finish() }
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.hud.indicatorView = JGProgressHUDRingIndicatorView()
|
||||
|
@ -51,7 +54,8 @@ class NCOperationSaveLivePhoto: ConcurrentOperation {
|
|||
self.hud.show(in: (self.appDelegate?.window?.rootViewController?.view)!)
|
||||
}
|
||||
|
||||
NCNetworking.shared.download(metadata: metadata, selector: "", notificationCenterProgressTask: false, checkfileProviderStorageExists: true) { _ in
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: false) {
|
||||
} requestHandler: { _ in
|
||||
} progressHandler: { progress in
|
||||
self.hud.progress = Float(progress.fractionCompleted)
|
||||
} completion: { _, error in
|
||||
|
@ -63,7 +67,7 @@ class NCOperationSaveLivePhoto: ConcurrentOperation {
|
|||
}
|
||||
return self.finish()
|
||||
}
|
||||
NCNetworking.shared.download(metadata: self.metadataMOV, selector: "", notificationCenterProgressTask: false, checkfileProviderStorageExists: true) { _ in
|
||||
NCNetworking.shared.download(metadata: metadataLive, withNotificationProgressTask: false, checkfileProviderStorageExists: true) {
|
||||
DispatchQueue.main.async {
|
||||
self.hud.textLabel.text = NSLocalizedString("_download_video_", comment: "")
|
||||
self.hud.detailTextLabel.text = self.metadataMOV.fileName
|
||||
|
|
|
@ -111,9 +111,16 @@ extension NCViewer {
|
|||
icon: utility.loadImage(named: "printer"),
|
||||
action: { _ in
|
||||
if self.utilityFileSystem.fileProviderStorageExists(metadata) {
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": NCGlobal.shared.selectorPrint, "error": NKError(), "account": metadata.account])
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"selector": NCGlobal.shared.selectorPrint,
|
||||
"error": NKError(),
|
||||
"account": metadata.account])
|
||||
} else {
|
||||
NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorPrint) { _, _ in }
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: NCGlobal.shared.selectorPrint) else { return }
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: true)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -158,9 +165,16 @@ extension NCViewer {
|
|||
icon: utility.loadImage(named: "viewfinder.circle"),
|
||||
action: { _ in
|
||||
if self.utilityFileSystem.fileProviderStorageExists(metadata) {
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": NCGlobal.shared.selectorSaveAsScan, "error": NKError(), "account": metadata.account])
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"selector": NCGlobal.shared.selectorSaveAsScan,
|
||||
"error": NKError(),
|
||||
"account": metadata.account])
|
||||
} else {
|
||||
NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorSaveAsScan) { _, _ in }
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: NCGlobal.shared.selectorSaveAsScan) else { return }
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: true)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -216,7 +230,8 @@ extension NCViewer {
|
|||
title: NSLocalizedString("_download_locally_", comment: ""),
|
||||
icon: utility.loadImage(named: "icloud.and.arrow.down"),
|
||||
action: { _ in
|
||||
NCNetworking.shared.download(metadata: metadata, selector: "") { _, _ in }
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: "") else { return }
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: true)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
@ -257,9 +272,16 @@ extension NCViewer {
|
|||
icon: utility.loadImage(named: "pencil.tip.crop.circle"),
|
||||
action: { _ in
|
||||
if self.utilityFileSystem.fileProviderStorageExists(metadata) {
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": NCGlobal.shared.selectorLoadFileQuickLook, "error": NKError(), "account": metadata.account])
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"selector": NCGlobal.shared.selectorLoadFileQuickLook,
|
||||
"error": NKError(),
|
||||
"account": metadata.account])
|
||||
} else {
|
||||
NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadFileQuickLook) { _, _ in }
|
||||
guard let metadata = NCManageDatabase.shared.setMetadataSessionInWaitDownload(ocId: metadata.ocId, selector: NCGlobal.shared.selectorLoadFileQuickLook) else { return }
|
||||
NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: true)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -128,7 +128,7 @@ class NCGlobal: NSObject {
|
|||
// E2EE
|
||||
//
|
||||
let e2eePassphraseTest = "more over television factory tendency independence international intellectual impress interest sentence pony"
|
||||
@objc let e2eeVersions = ["1.1", "1.2"] // ["1.1", "1.2", "2.0"]
|
||||
@objc let e2eeVersions = ["1.1", "1.2", "2.0"]
|
||||
let e2eeVersionV11 = "1.1"
|
||||
let e2eeVersionV12 = "1.2"
|
||||
let e2eeVersionV20 = "2.0"
|
||||
|
@ -218,6 +218,8 @@ class NCGlobal: NSObject {
|
|||
@objc let errorMethodNotSupported: Int = 405
|
||||
@objc let errorConflict: Int = 409
|
||||
@objc let errorPreconditionFailed: Int = 412
|
||||
@objc let errorUnsupportedMediaType: Int = 415
|
||||
@objc let errorInternalServerError: Int = 500
|
||||
@objc let errorQuota: Int = 507
|
||||
@objc let errorUnauthorized997: Int = 997
|
||||
@objc let errorExplicitlyCancelled: Int = -999
|
||||
|
@ -322,17 +324,12 @@ class NCGlobal: NSObject {
|
|||
let metadataStatusNormal: Int = 0
|
||||
|
||||
let metadataStatusWaitDownload: Int = -1
|
||||
let metadataStatusInDownload: Int = -2
|
||||
let metadataStatusDownloading: Int = -3
|
||||
let metadataStatusDownloadError: Int = -4
|
||||
let metadataStatusDownloading: Int = -2
|
||||
let metadataStatusDownloadError: Int = -3
|
||||
|
||||
let metadataStatusWaitUpload: Int = 1
|
||||
let metadataStatusInUpload: Int = 2
|
||||
let metadataStatusUploading: Int = 3
|
||||
let metadataStatusUploadError: Int = 4
|
||||
|
||||
// Queue Concurrent Operation Download
|
||||
let maxConcurrentOperationCountDownload: Int = 10
|
||||
let metadataStatusUploading: Int = 2
|
||||
let metadataStatusUploadError: Int = 3
|
||||
|
||||
// Hidden files included in the read
|
||||
//
|
||||
|
@ -356,12 +353,10 @@ class NCGlobal: NSObject {
|
|||
let notificationCenterRichdocumentGrabFocus = "richdocumentGrabFocus"
|
||||
let notificationCenterReloadDataNCShare = "reloadDataNCShare"
|
||||
let notificationCenterCloseRichWorkspaceWebView = "closeRichWorkspaceWebView"
|
||||
let notificationCenterUpdateBadgeNumber = "updateBadgeNumber" // userInfo: counterDownload, counterUpload
|
||||
let notificationCenterReloadAvatar = "reloadAvatar"
|
||||
|
||||
@objc let notificationCenterReloadDataSource = "reloadDataSource"
|
||||
let notificationCenterReloadDataSourceNetwork = "reloadDataSourceNetwork"
|
||||
let notificationCenterReloadDataSourceNetworkForced = "reloadDataSourceNetworkForced"
|
||||
|
||||
let notificationCenterChangeStatusFolderE2EE = "changeStatusFolderE2EE" // userInfo: serverUrl
|
||||
|
||||
|
@ -371,10 +366,14 @@ class NCGlobal: NSObject {
|
|||
|
||||
let notificationCenterUploadStartFile = "uploadStartFile" // userInfo: ocId, serverUrl, account, fileName, sessionSelector
|
||||
@objc let notificationCenterUploadedFile = "uploadedFile" // userInfo: ocId, serverUrl, account, fileName, ocIdTemp, error
|
||||
let notificationCenterUploadedLivePhoto = "uploadedLivePhoto" // userInfo: ocId, serverUrl, account, fileName, ocIdTemp, error
|
||||
|
||||
let notificationCenterUploadCancelFile = "uploadCancelFile" // userInfo: ocId, serverUrl, account
|
||||
|
||||
let notificationCenterProgressTask = "progressTask" // userInfo: account, ocId, serverUrl, status, chunk, e2eEncrypted, progress, totalBytes, totalBytesExpected
|
||||
|
||||
let notificationCenterUpdateBadgeNumber = "updateBadgeNumber"
|
||||
|
||||
let notificationCenterCreateFolder = "createFolder" // userInfo: ocId, serverUrl, account, withPush
|
||||
let notificationCenterDeleteFile = "deleteFile" // userInfo: [ocId], [indexPath], onlyLocalCache, error
|
||||
let notificationCenterMoveFile = "moveFile" // userInfo: [ocId], [indexPath], error
|
||||
|
@ -476,6 +475,8 @@ class NCGlobal: NSObject {
|
|||
return capabilityServerVersionMajor >= nextcloudVersion28
|
||||
}
|
||||
|
||||
var capabilitySecurityGuardDiagnostics = false
|
||||
|
||||
// MORE NEXTCLOUD APPS
|
||||
let talkSchemeUrl = "nextcloudtalk://"
|
||||
let notesSchemeUrl = "nextcloudnotes://"
|
||||
|
@ -490,4 +491,16 @@ class NCGlobal: NSObject {
|
|||
// FORBIDDEN CHARACTERS
|
||||
//
|
||||
let forbiddenCharacters = ["/", "\\", ":", "\"", "|", "?", "*", "<", ">"]
|
||||
|
||||
// DIAGNOSTICS CLIENTS
|
||||
//
|
||||
let diagnosticIssueSyncConflicts = "sync_conflicts"
|
||||
let diagnosticIssueProblems = "problems"
|
||||
let diagnosticIssueVirusDetected = "virus_detected"
|
||||
let diagnosticIssueE2eeErrors = "e2ee_errors"
|
||||
|
||||
let diagnosticProblemsForbidden = "CHARACTERS_FORBIDDEN"
|
||||
let diagnosticProblemsBadResponse = "BAD_SERVER_RESPONSE"
|
||||
let diagnosticProblemsUploadServerError = "UploadError.SERVER_ERROR"
|
||||
|
||||
}
|
||||
|
|
|
@ -43,12 +43,17 @@ import RealmSwift
|
|||
case actual(_ image: UIImage)
|
||||
}
|
||||
|
||||
struct metadataInfo {
|
||||
var etag: String
|
||||
var date: NSDate
|
||||
}
|
||||
|
||||
private typealias ThumbnailLRUCache = LRUCache<String, ImageType>
|
||||
private lazy var cache: ThumbnailLRUCache = {
|
||||
return ThumbnailLRUCache(countLimit: limit)
|
||||
}()
|
||||
private var ocIdEtag: [String: String] = [:]
|
||||
@ThreadSafe private var metadatas: Results<tableMetadata>?
|
||||
private var metadatasInfo: [String: metadataInfo] = [:]
|
||||
private var metadatas: ThreadSafeArray<tableMetadata>?
|
||||
|
||||
let showAllPredicateMediaString = "account == %@ AND serverUrl BEGINSWITH %@ AND (classFile == '\(NKCommon.TypeClassFile.image.rawValue)' OR classFile == '\(NKCommon.TypeClassFile.video.rawValue)') AND NOT (session CONTAINS[c] 'upload')"
|
||||
let showBothPredicateMediaString = "account == %@ AND serverUrl BEGINSWITH %@ AND (classFile == '\(NKCommon.TypeClassFile.image.rawValue)' OR classFile == '\(NKCommon.TypeClassFile.video.rawValue)') AND NOT (session CONTAINS[c] 'upload') AND NOT (livePhotoFile != '' AND classFile == '\(NKCommon.TypeClassFile.video.rawValue)')"
|
||||
|
@ -61,7 +66,7 @@ import RealmSwift
|
|||
guard account != self.account, !account.isEmpty else { return }
|
||||
self.account = account
|
||||
|
||||
ocIdEtag.removeAll()
|
||||
self.metadatasInfo.removeAll()
|
||||
self.metadatas = nil
|
||||
self.metadatas = getMediaMetadatas(account: account)
|
||||
guard let metadatas = self.metadatas, !metadatas.isEmpty else { return }
|
||||
|
@ -76,8 +81,8 @@ import RealmSwift
|
|||
var files: [FileInfo] = []
|
||||
let startDate = Date()
|
||||
|
||||
for metadata in metadatas {
|
||||
ocIdEtag[metadata.ocId] = metadata.etag
|
||||
metadatas.forEach { metadata in
|
||||
metadatasInfo[metadata.ocId] = metadataInfo(etag: metadata.etag, date: metadata.date)
|
||||
}
|
||||
|
||||
if let enumerator = manager.enumerator(at: URL(fileURLWithPath: NCUtilityFileSystem().directoryProviderStorage), includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles]) {
|
||||
|
@ -87,10 +92,10 @@ import RealmSwift
|
|||
guard let resourceValues = try? fileURL.resourceValues(forKeys: resourceKeys),
|
||||
let size = resourceValues.fileSize,
|
||||
size > 0,
|
||||
let date = resourceValues.creationDate,
|
||||
let etag = ocIdEtag[ocId],
|
||||
let date = metadatasInfo[ocId]?.date,
|
||||
let etag = metadatasInfo[ocId]?.etag,
|
||||
fileName == etag + ext else { continue }
|
||||
files.append(FileInfo(path: fileURL, ocIdEtag: ocId + etag, date: date))
|
||||
files.append(FileInfo(path: fileURL, ocIdEtag: ocId + etag, date: date as Date))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +109,7 @@ import RealmSwift
|
|||
var counter: Int = 0
|
||||
for file in files {
|
||||
counter += 1
|
||||
if counter > limit { break }
|
||||
if counter > (limit - 100) { break }
|
||||
autoreleasepool {
|
||||
if let image = UIImage(contentsOfFile: file.path.path) {
|
||||
cache.setValue(.actual(image), forKey: file.ocIdEtag)
|
||||
|
@ -120,7 +125,7 @@ import RealmSwift
|
|||
NextcloudKit.shared.nkCommonInstance.writeLog("--------- ThumbnailLRUCache image process ---------")
|
||||
}
|
||||
|
||||
func initialMetadatas() -> Results<tableMetadata>? {
|
||||
func initialMetadatas() -> ThreadSafeArray<tableMetadata>? {
|
||||
defer { self.metadatas = nil }
|
||||
return self.metadatas
|
||||
}
|
||||
|
@ -134,16 +139,16 @@ import RealmSwift
|
|||
}
|
||||
|
||||
@objc func clearMediaCache() {
|
||||
self.ocIdEtag.removeAll()
|
||||
self.metadatasInfo.removeAll()
|
||||
self.metadatas = nil
|
||||
cache.removeAllValues()
|
||||
}
|
||||
|
||||
func getMediaMetadatas(account: String, predicate: NSPredicate? = nil) -> Results<tableMetadata>? {
|
||||
func getMediaMetadatas(account: String, predicate: NSPredicate? = nil) -> ThreadSafeArray<tableMetadata>? {
|
||||
guard let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) else { return nil }
|
||||
let startServerUrl = NCUtilityFileSystem().getHomeServer(urlBase: account.urlBase, userId: account.userId) + account.mediaPath
|
||||
let predicateBoth = NSPredicate(format: showBothPredicateMediaString, account.account, startServerUrl)
|
||||
return NCManageDatabase.shared.getResultsMetadatas(predicate: predicate ?? predicateBoth, sorted: "date")
|
||||
return NCManageDatabase.shared.getMediaMetadatas(predicate: predicate ?? predicateBoth)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
|
|
@ -146,7 +146,7 @@ extension NCEndToEndMetadata {
|
|||
var encryptedInitializationVector: NSString?
|
||||
var encryptedTag: NSString?
|
||||
|
||||
if let metadataKeyFiledrop = (e2eEncryption.metadataKeyFiledrop.data(using: .utf8)?.base64EncodedString().data(using: .utf8)),
|
||||
if let metadataKeyFiledrop = (e2eEncryption.metadataKey.data(using: .utf8)?.base64EncodedString().data(using: .utf8)),
|
||||
let metadataKeyEncrypted = NCEndToEndEncryption.sharedManager().encryptAsymmetricData(metadataKeyFiledrop, privateKey: privateKey) {
|
||||
encryptedKey = metadataKeyEncrypted.base64EncodedString()
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ extension NCEndToEndMetadata {
|
|||
// Create "encrypted"
|
||||
var json = try encoder.encode(encrypted)
|
||||
json = json.base64EncodedString().data(using: .utf8)!
|
||||
if let encrypted = NCEndToEndEncryption.sharedManager().encryptPayloadFile(json, key: e2eEncryption.metadataKeyFiledrop, initializationVector: &encryptedInitializationVector, authenticationTag: &encryptedTag) {
|
||||
if let encrypted = NCEndToEndEncryption.sharedManager().encryptPayloadFile(json, key: e2eEncryption.metadataKey, initializationVector: &encryptedInitializationVector, authenticationTag: &encryptedTag) {
|
||||
let record = E2eeV12.Filedrop(initializationVector: e2eEncryption.initializationVector, authenticationTag: e2eEncryption.authenticationTag, encrypted: encrypted, encryptedKey: encryptedKey, encryptedTag: encryptedTag as? String, encryptedInitializationVector: encryptedInitializationVector as? String)
|
||||
filedrop.updateValue(record, forKey: e2eEncryption.fileNameIdentifier)
|
||||
}
|
||||
|
@ -315,7 +315,6 @@ extension NCEndToEndMetadata {
|
|||
object.blob = "filedrop"
|
||||
object.fileName = encrypted.filename
|
||||
object.key = encrypted.key
|
||||
object.metadataKeyFiledrop = metadataKeyFiledrop ?? ""
|
||||
object.initializationVector = filedrop.initializationVector
|
||||
object.metadataKey = metadataKey
|
||||
object.metadataVersion = metadataVersion
|
||||
|
|
|
@ -29,26 +29,26 @@ extension NCEndToEndMetadata {
|
|||
|
||||
struct E2eeV20: Codable {
|
||||
|
||||
struct Files: Codable {
|
||||
let authenticationTag: String
|
||||
let filename: String
|
||||
let key: String
|
||||
let mimetype: String
|
||||
let nonce: String
|
||||
}
|
||||
|
||||
struct ciphertext: Codable {
|
||||
let counter: Int
|
||||
let deleted: Bool?
|
||||
let keyChecksums: [String]?
|
||||
let files: [String: Files]?
|
||||
let folders: [String: String]?
|
||||
}
|
||||
|
||||
struct Metadata: Codable {
|
||||
let ciphertext: String
|
||||
let nonce: String
|
||||
let authenticationTag: String
|
||||
|
||||
struct ciphertext: Codable {
|
||||
let counter: Int
|
||||
let deleted: Bool?
|
||||
let keyChecksums: [String]?
|
||||
let files: [String: Files]?
|
||||
let folders: [String: String]?
|
||||
|
||||
struct Files: Codable {
|
||||
let authenticationTag: String
|
||||
let filename: String
|
||||
let key: String
|
||||
let mimetype: String
|
||||
let nonce: String
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Users: Codable {
|
||||
|
@ -58,20 +58,20 @@ extension NCEndToEndMetadata {
|
|||
}
|
||||
|
||||
struct Filedrop: Codable {
|
||||
let ciphertext: String?
|
||||
let nonce: String?
|
||||
let authenticationTag: String?
|
||||
let users: [UsersFiledrop]?
|
||||
let ciphertext: String
|
||||
let nonce: String
|
||||
let authenticationTag: String
|
||||
let users: [UsersFiledrop]
|
||||
|
||||
struct UsersFiledrop: Codable {
|
||||
let userId: String?
|
||||
let encryptedFiledropKey: String?
|
||||
let userId: String
|
||||
let encryptedFiledropKey: String
|
||||
}
|
||||
}
|
||||
|
||||
let metadata: Metadata
|
||||
let users: [Users]?
|
||||
let filedrop: [Filedrop]?
|
||||
let filedrop: [String: Filedrop]?
|
||||
let version: String
|
||||
}
|
||||
|
||||
|
@ -108,9 +108,7 @@ extension NCEndToEndMetadata {
|
|||
var metadataKey: String?
|
||||
var keyChecksums: [String] = []
|
||||
var usersCodable: [E2eeV20.Users] = []
|
||||
var usersFileDropCodable: [E2eeV20.Filedrop.UsersFiledrop] = []
|
||||
var filesCodable: [String: E2eeV20.Files] = [:]
|
||||
var filedropCodable: [E2eeV20.Filedrop] = []
|
||||
var filesCodable: [String: E2eeV20.Metadata.ciphertext.Files] = [:]
|
||||
var folders: [String: String] = [:]
|
||||
var counter: Int = 1
|
||||
|
||||
|
@ -130,7 +128,7 @@ extension NCEndToEndMetadata {
|
|||
guard var key = NCEndToEndEncryption.sharedManager()?.generateKey() as? Data else {
|
||||
return (nil, nil, 0, NKError(errorCode: NCGlobal.shared.errorUnexpectedResponseFromDB, errorDescription: "_e2e_error_"))
|
||||
}
|
||||
if let tableUserId = NCManageDatabase.shared.getE2EUsers(account: account, ocIdServerUrl: directoryTop.ocId, userId: userId),
|
||||
if let tableUserId = NCManageDatabase.shared.getE2EUser(account: account, ocIdServerUrl: directoryTop.ocId, userId: userId),
|
||||
let metadataKey = tableUserId.metadataKey {
|
||||
key = metadataKey
|
||||
} else {
|
||||
|
@ -155,7 +153,7 @@ extension NCEndToEndMetadata {
|
|||
|
||||
} else {
|
||||
|
||||
guard let tableUserId = NCManageDatabase.shared.getE2EUsers(account: account, ocIdServerUrl: directoryTop.ocId, userId: userId), let key = tableUserId.metadataKey else {
|
||||
guard let tableUserId = NCManageDatabase.shared.getE2EUser(account: account, ocIdServerUrl: directoryTop.ocId, userId: userId), let key = tableUserId.metadataKey else {
|
||||
return (nil, nil, 0, NKError(errorCode: NCGlobal.shared.errorUnexpectedResponseFromDB, errorDescription: "_e2e_error_"))
|
||||
}
|
||||
|
||||
|
@ -169,7 +167,6 @@ extension NCEndToEndMetadata {
|
|||
for user in users {
|
||||
if isDirectoryTop {
|
||||
usersCodable.append(E2eeV20.Users(userId: user.userId, certificate: user.certificate, encryptedMetadataKey: user.encryptedMetadataKey))
|
||||
// usersFileDropCodable.append(E2eeV20.Filedrop.UsersFiledrop(userId: user.userId, encryptedFiledropKey: user.encryptedFiledropKey))
|
||||
}
|
||||
if let hash = NCEndToEndEncryption.sharedManager().createSHA256(user.metadataKey) {
|
||||
keyChecksums.append(hash)
|
||||
|
@ -189,39 +186,17 @@ extension NCEndToEndMetadata {
|
|||
|
||||
for e2eEncryption in e2eEncryptions {
|
||||
if e2eEncryption.blob == "files" {
|
||||
let file = E2eeV20.Files(authenticationTag: e2eEncryption.authenticationTag, filename: e2eEncryption.fileName, key: e2eEncryption.key, mimetype: e2eEncryption.mimeType, nonce: e2eEncryption.initializationVector)
|
||||
let file = E2eeV20.Metadata.ciphertext.Files(authenticationTag: e2eEncryption.authenticationTag, filename: e2eEncryption.fileName, key: e2eEncryption.key, mimetype: e2eEncryption.mimeType, nonce: e2eEncryption.initializationVector)
|
||||
filesCodable.updateValue(file, forKey: e2eEncryption.fileNameIdentifier)
|
||||
} else if e2eEncryption.blob == "folders" {
|
||||
folders[e2eEncryption.fileNameIdentifier] = e2eEncryption.fileName
|
||||
} else if e2eEncryption.blob == "filedrop" {
|
||||
let filedrop = E2eeV20.Files(authenticationTag: e2eEncryption.authenticationTag, filename: e2eEncryption.fileName, key: e2eEncryption.key, mimetype: e2eEncryption.mimeType, nonce: e2eEncryption.initializationVector)
|
||||
var authenticationTag: NSString?
|
||||
var initializationVector: NSString?
|
||||
do {
|
||||
let json = try JSONEncoder().encode(filedrop)
|
||||
let jsonZip = try json.gzipped()
|
||||
let ciphertext = NCEndToEndEncryption.sharedManager().encryptPayloadFile(jsonZip, key: metadataKey, initializationVector: &initializationVector, authenticationTag: &authenticationTag)
|
||||
|
||||
guard var ciphertext, let initializationVector = initializationVector as? String, let authenticationTag = authenticationTag as? String else {
|
||||
return (nil, nil, counter, NKError(errorCode: NCGlobal.shared.errorE2EEEncryptPayloadFile, errorDescription: "_e2e_error_"))
|
||||
}
|
||||
|
||||
// Add initializationVector [ANDROID]
|
||||
ciphertext = ciphertext + "|" + initializationVector
|
||||
|
||||
let filedrop = E2eeV20.Filedrop(ciphertext: ciphertext, nonce: initializationVector, authenticationTag: authenticationTag, users: usersFileDropCodable)
|
||||
filedropCodable.append(filedrop)
|
||||
|
||||
} catch let error {
|
||||
return (nil, nil, counter, NKError(errorCode: NCGlobal.shared.errorE2EEJSon, errorDescription: error.localizedDescription))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
var authenticationTag: NSString?
|
||||
var initializationVector: NSString?
|
||||
let json = try JSONEncoder().encode(E2eeV20.ciphertext(counter: counter, deleted: false, keyChecksums: keyChecksums, files: filesCodable, folders: folders))
|
||||
let json = try JSONEncoder().encode(E2eeV20.Metadata.ciphertext(counter: counter, deleted: false, keyChecksums: keyChecksums, files: filesCodable, folders: folders))
|
||||
let jsonZip = try json.gzipped()
|
||||
let ciphertextMetadata = NCEndToEndEncryption.sharedManager().encryptPayloadFile(jsonZip, key: metadataKey, initializationVector: &initializationVector, authenticationTag: &authenticationTag)
|
||||
guard var ciphertextMetadata, let initializationVector = initializationVector as? String, let authenticationTag = authenticationTag as? String else {
|
||||
|
@ -232,7 +207,7 @@ extension NCEndToEndMetadata {
|
|||
ciphertextMetadata = ciphertextMetadata + "|" + initializationVector
|
||||
|
||||
let metadataCodable = E2eeV20.Metadata(ciphertext: ciphertextMetadata, nonce: initializationVector, authenticationTag: authenticationTag)
|
||||
let e2eeCodable = E2eeV20(metadata: metadataCodable, users: usersCodable, filedrop: filedropCodable, version: NCGlobal.shared.e2eeVersionV20)
|
||||
let e2eeCodable = E2eeV20(metadata: metadataCodable, users: usersCodable, filedrop: nil, version: NCGlobal.shared.e2eeVersionV20)
|
||||
let e2eeData = try JSONEncoder().encode(e2eeCodable)
|
||||
e2eeData.printJson()
|
||||
|
||||
|
@ -257,6 +232,8 @@ extension NCEndToEndMetadata {
|
|||
return NKError(errorCode: NCGlobal.shared.errorE2EEKeyDecodeMetadata, errorDescription: "_e2e_error_")
|
||||
}
|
||||
|
||||
let isDirectoryTop = utilityFileSystem.isDirectoryE2EETop(account: account, serverUrl: serverUrl)
|
||||
|
||||
func addE2eEncryption(fileNameIdentifier: String, filename: String, authenticationTag: String, key: String, initializationVector: String, metadataKey: String, mimetype: String, blob: String) {
|
||||
|
||||
if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND fileName == %@", account, fileNameIdentifier)) {
|
||||
|
@ -296,53 +273,65 @@ extension NCEndToEndMetadata {
|
|||
let filesdrop = json.filedrop
|
||||
let version = json.version as String? ?? NCGlobal.shared.e2eeVersionV20
|
||||
|
||||
// SAVE IN DB ALL USER
|
||||
//
|
||||
if let users {
|
||||
for user in users {
|
||||
var metadataKey: Data?
|
||||
if let encryptedMetadataKey = user.encryptedMetadataKey {
|
||||
let data = Data(base64Encoded: encryptedMetadataKey)
|
||||
if let decrypted = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(data, privateKey: NCKeychain().getEndToEndPrivateKey(account: account)) {
|
||||
metadataKey = decrypted
|
||||
if isDirectoryTop {
|
||||
|
||||
// SAVE IN DB ALL USER
|
||||
//
|
||||
if let users {
|
||||
for user in users {
|
||||
var metadataKey: Data?
|
||||
if let encryptedMetadataKey = user.encryptedMetadataKey {
|
||||
let data = Data(base64Encoded: encryptedMetadataKey)
|
||||
if let decrypted = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(data, privateKey: NCKeychain().getEndToEndPrivateKey(account: account)) {
|
||||
metadataKey = decrypted
|
||||
}
|
||||
}
|
||||
NCManageDatabase.shared.addE2EUsers(account: account, serverUrl: serverUrl, ocIdServerUrl: ocIdServerUrl, userId: user.userId, certificate: user.certificate, encryptedMetadataKey: user.encryptedMetadataKey, metadataKey: metadataKey)
|
||||
}
|
||||
NCManageDatabase.shared.addE2EUsers(account: account, serverUrl: serverUrl, ocIdServerUrl: ocIdServerUrl, userId: user.userId, certificate: user.certificate, encryptedMetadataKey: user.encryptedMetadataKey, metadataKey: metadataKey)
|
||||
}
|
||||
}
|
||||
|
||||
// GET metadataKey, decryptedMetadataKey
|
||||
//
|
||||
guard let objUsers = NCManageDatabase.shared.getE2EUsers(account: account, ocIdServerUrl: directoryTop.ocId, userId: userId),
|
||||
let metadataKey = objUsers.metadataKey?.base64EncodedString(),
|
||||
let decryptedMetadataKey = objUsers.metadataKey else {
|
||||
guard let tableUser = NCManageDatabase.shared.getE2EUser(account: account, ocIdServerUrl: directoryTop.ocId, userId: userId),
|
||||
let metadataKey = tableUser.metadataKey?.base64EncodedString(),
|
||||
let decryptedMetadataKey = tableUser.metadataKey else {
|
||||
return NKError(errorCode: NCGlobal.shared.errorE2EENoUserFound, errorDescription: "_e2e_error_")
|
||||
}
|
||||
|
||||
// SIGNATURE CHECK
|
||||
//
|
||||
guard let signature,
|
||||
verifySignature(account: account, signature: signature, userId: objUsers.userId, metadata: metadata, users: users, version: version, certificate: objUsers.certificate) else {
|
||||
return NKError(errorCode: NCGlobal.shared.errorE2EEKeyVerifySignature, errorDescription: "_e2e_error_")
|
||||
|
||||
if let signature {
|
||||
if !verifySignature(account: account, signature: signature, userId: tableUser.userId, metadata: metadata, users: users, version: version, certificate: tableUser.certificate) {
|
||||
return NKError(errorCode: NCGlobal.shared.errorE2EEKeyVerifySignature, errorDescription: "_e2e_error_")
|
||||
}
|
||||
}
|
||||
|
||||
// FILEDROP
|
||||
/*
|
||||
if let filesdrop, let filedropKey = tableE2eUsersV2.filedropKey?.base64EncodedString() {
|
||||
for filedrop in filesdrop {
|
||||
guard let decryptedFiledrop = NCEndToEndEncryption.sharedManager().decryptPayloadFile(filedrop.ciphertext, key: filedropKey, initializationVector: filedrop.nonce, authenticationTag: filedrop.authenticationTag),
|
||||
decryptedFiledrop.isGzipped else {
|
||||
return NKError(errorCode: NCGlobal.shared.errorE2EEKeyFiledropCiphertext, errorDescription: "_e2e_error_")
|
||||
//
|
||||
if let filesdrop {
|
||||
for filedop in filesdrop {
|
||||
let fileNameIdentifier = filedop.key
|
||||
let ciphertext = filedop.value.ciphertext
|
||||
let nonce = filedop.value.nonce
|
||||
let authenticationTag = filedop.value.authenticationTag
|
||||
for user in filedop.value.users where user.userId == userId {
|
||||
let data = Data(base64Encoded: user.encryptedFiledropKey)
|
||||
if let decryptedFiledropKey = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(data, privateKey: NCKeychain().getEndToEndPrivateKey(account: account)) {
|
||||
let filedropKey = decryptedFiledropKey.base64EncodedString()
|
||||
guard let decryptedFiledrop = NCEndToEndEncryption.sharedManager().decryptPayloadFile(ciphertext, key: filedropKey, initializationVector: nonce, authenticationTag: authenticationTag),
|
||||
decryptedFiledrop.isGzipped else {
|
||||
return NKError(errorCode: NCGlobal.shared.errorE2EEKeyFiledropCiphertext, errorDescription: "_e2e_error_")
|
||||
}
|
||||
let data = try decryptedFiledrop.gunzipped()
|
||||
if let jsonText = String(data: data, encoding: .utf8) { print(jsonText) }
|
||||
let file = try JSONDecoder().decode(E2eeV20.Metadata.ciphertext.Files.self, from: data)
|
||||
print(file)
|
||||
addE2eEncryption(fileNameIdentifier: fileNameIdentifier, filename: file.filename, authenticationTag: file.authenticationTag, key: file.key, initializationVector: file.nonce, metadataKey: filedropKey, mimetype: file.mimetype, blob: "files")
|
||||
}
|
||||
}
|
||||
let data = try decryptedFiledrop.gunzipped()
|
||||
if let jsonText = String(data: data, encoding: .utf8) { print(jsonText) }
|
||||
let file = try JSONDecoder().decode(E2eeV20.Files.self, from: data)
|
||||
print(file)
|
||||
addE2eEncryption(fileNameIdentifier: file.key, filename: file.filename, authenticationTag: file.authenticationTag, key: file.key, initializationVector: file.nonce, metadataKey: filedropKey, mimetype: file.mimetype, blob: "filedrop")
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// CIPHERTEXT METADATA
|
||||
//
|
||||
|
@ -353,14 +342,15 @@ extension NCEndToEndMetadata {
|
|||
|
||||
let data = try decryptedMetadata.gunzipped()
|
||||
if let jsonText = String(data: data, encoding: .utf8) { print(jsonText) }
|
||||
let jsonCiphertextMetadata = try JSONDecoder().decode(E2eeV20.ciphertext.self, from: data)
|
||||
let jsonCiphertextMetadata = try JSONDecoder().decode(E2eeV20.Metadata.ciphertext.self, from: data)
|
||||
|
||||
// CHECKSUM CHECK
|
||||
//
|
||||
guard let keyChecksums = jsonCiphertextMetadata.keyChecksums,
|
||||
let hash = NCEndToEndEncryption.sharedManager().createSHA256(decryptedMetadataKey),
|
||||
keyChecksums.contains(hash) else {
|
||||
return NKError(errorCode: NCGlobal.shared.errorE2EEKeyChecksums, errorDescription: NSLocalizedString("_e2e_error_", comment: ""))
|
||||
if let keyChecksums = jsonCiphertextMetadata.keyChecksums {
|
||||
guard let hash = NCEndToEndEncryption.sharedManager().createSHA256(decryptedMetadataKey),
|
||||
keyChecksums.contains(hash) else {
|
||||
return NKError(errorCode: NCGlobal.shared.errorE2EEKeyChecksums, errorDescription: NSLocalizedString("_e2e_error_", comment: ""))
|
||||
}
|
||||
}
|
||||
|
||||
print("\n\nCOUNTER -------------------------------")
|
||||
|
@ -459,24 +449,32 @@ extension NCEndToEndMetadata {
|
|||
|
||||
func verifySignature(account: String, signature: String, userId: String, metadata: E2eeV20.Metadata, users: [E2eeV20.Users]?, version: String, certificate: String) -> Bool {
|
||||
|
||||
guard let users else { return false }
|
||||
var signatureCodable: E2eeV20Signature?
|
||||
var certificates: [String] = []
|
||||
|
||||
var usersSignatureCodable: [E2eeV20Signature.Users] = []
|
||||
for user in users {
|
||||
usersSignatureCodable.append(E2eeV20Signature.Users(userId: user.userId, certificate: user.certificate, encryptedMetadataKey: user.encryptedMetadataKey))
|
||||
if let users {
|
||||
var usersSignatureCodable: [E2eeV20Signature.Users] = []
|
||||
for user in users {
|
||||
usersSignatureCodable.append(E2eeV20Signature.Users(userId: user.userId, certificate: user.certificate, encryptedMetadataKey: user.encryptedMetadataKey))
|
||||
}
|
||||
signatureCodable = E2eeV20Signature(metadata: E2eeV20Signature.Metadata(ciphertext: metadata.ciphertext, nonce: metadata.nonce, authenticationTag: metadata.authenticationTag), users: usersSignatureCodable, version: version)
|
||||
certificates = users.map { $0.certificate }
|
||||
} else {
|
||||
signatureCodable = E2eeV20Signature(metadata: E2eeV20Signature.Metadata(ciphertext: metadata.ciphertext, nonce: metadata.nonce, authenticationTag: metadata.authenticationTag), users: nil, version: version)
|
||||
certificates = [certificate]
|
||||
}
|
||||
let signatureCodable = E2eeV20Signature(metadata: E2eeV20Signature.Metadata(ciphertext: metadata.ciphertext, nonce: metadata.nonce, authenticationTag: metadata.authenticationTag), users: usersSignatureCodable, version: version)
|
||||
|
||||
do {
|
||||
let jsonEncoder = JSONEncoder()
|
||||
let json = try jsonEncoder.encode(signatureCodable)
|
||||
let dataSerialization = try JSONSerialization.jsonObject(with: json, options: [])
|
||||
let decoded = try? JSONSerialization.data(withJSONObject: dataSerialization, options: [.sortedKeys, .withoutEscapingSlashes])
|
||||
let base64 = decoded!.base64EncodedString()
|
||||
if let base64Data = base64.data(using: .utf8),
|
||||
let signatureData = Data(base64Encoded: signature) {
|
||||
let certificates = users.map { $0.certificate }
|
||||
return NCEndToEndEncryption.sharedManager().verifySignatureCMS(signatureData, data: base64Data, certificates: certificates)
|
||||
if var dataSerialization = dataSerialization as? [String: Any?] {
|
||||
dataSerialization = dataSerialization.compactMapValues { $0 }
|
||||
let decodedSignatureCodable = try JSONSerialization.data(withJSONObject: dataSerialization, options: [.sortedKeys, .withoutEscapingSlashes])
|
||||
let base64 = decodedSignatureCodable.base64EncodedString()
|
||||
if let data = base64.data(using: .utf8), let signatureData = Data(base64Encoded: signature) {
|
||||
return NCEndToEndEncryption.sharedManager().verifySignatureCMS(signatureData, data: data, certificates: certificates)
|
||||
}
|
||||
}
|
||||
|
||||
} catch {
|
||||
|
|
|
@ -26,7 +26,7 @@ class NCNetworkingE2EE: NSObject {
|
|||
|
||||
func isInUpload(account: String, serverUrl: String) -> Bool {
|
||||
|
||||
let counter = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND (status == %d OR status == %d OR status == %d)", account, serverUrl, NCGlobal.shared.metadataStatusWaitUpload, NCGlobal.shared.metadataStatusInUpload, NCGlobal.shared.metadataStatusUploading)).count
|
||||
let counter = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND (status == %d OR status == %d)", account, serverUrl, NCGlobal.shared.metadataStatusWaitUpload, NCGlobal.shared.metadataStatusUploading)).count
|
||||
|
||||
return counter > 0 ? true : false
|
||||
}
|
||||
|
@ -38,6 +38,12 @@ class NCNetworkingE2EE: NSObject {
|
|||
return UUID
|
||||
}
|
||||
|
||||
func getOptions() -> NKRequestOptions {
|
||||
|
||||
let version = NCGlobal.shared.capabilityE2EEApiVersion == "2.0" ? "v2" : "v1"
|
||||
return NKRequestOptions(version: version)
|
||||
}
|
||||
|
||||
func uploadMetadata(account: String, serverUrl: String, userId: String, addUserId: String? = nil, removeUserId: String? = nil) async -> NKError {
|
||||
|
||||
var addCertificate: String?
|
||||
|
@ -47,7 +53,7 @@ class NCNetworkingE2EE: NSObject {
|
|||
}
|
||||
|
||||
if let addUserId {
|
||||
let results = await NextcloudKit.shared.getE2EECertificate(user: addUserId)
|
||||
let results = await NextcloudKit.shared.getE2EECertificate(user: addUserId, options: NCNetworkingE2EE().getOptions())
|
||||
if results.error == .success, let certificateUser = results.certificateUser {
|
||||
addCertificate = certificateUser
|
||||
} else {
|
||||
|
@ -64,7 +70,7 @@ class NCNetworkingE2EE: NSObject {
|
|||
|
||||
// METHOD
|
||||
//
|
||||
let resultsGetE2EEMetadata = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken)
|
||||
let resultsGetE2EEMetadata = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken, options: NCNetworkingE2EE().getOptions())
|
||||
if resultsGetE2EEMetadata.error == .success {
|
||||
method = "PUT"
|
||||
} else if resultsGetE2EEMetadata.error.errorCode != NCGlobal.shared.errorResourceNotFound {
|
||||
|
@ -102,13 +108,15 @@ class NCNetworkingE2EE: NSObject {
|
|||
fileId: String,
|
||||
e2eToken: String) async -> NKError {
|
||||
|
||||
let resultsGetE2EEMetadata = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken)
|
||||
let resultsGetE2EEMetadata = await NextcloudKit.shared.getE2EEMetadata(fileId: fileId, e2eToken: e2eToken, options: NCNetworkingE2EE().getOptions())
|
||||
guard resultsGetE2EEMetadata.error == .success, let e2eMetadata = resultsGetE2EEMetadata.e2eMetadata else {
|
||||
return resultsGetE2EEMetadata.error
|
||||
}
|
||||
|
||||
let resultsDecodeMetadataError = NCEndToEndMetadata().decodeMetadata(e2eMetadata, signature: resultsGetE2EEMetadata.signature, serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId)
|
||||
guard resultsDecodeMetadataError == .success else {
|
||||
// Client Diagnostic
|
||||
NCManageDatabase.shared.addDiagnostic(account: account, issue: NCGlobal.shared.diagnosticIssueE2eeErrors)
|
||||
return resultsDecodeMetadataError
|
||||
}
|
||||
|
||||
|
@ -128,10 +136,12 @@ class NCNetworkingE2EE: NSObject {
|
|||
|
||||
let resultsEncodeMetadata = NCEndToEndMetadata().encodeMetadata(account: account, serverUrl: serverUrl, userId: userId, addUserId: addUserId, addCertificate: addCertificate, removeUserId: removeUserId)
|
||||
guard resultsEncodeMetadata.error == .success, let e2eMetadata = resultsEncodeMetadata.metadata else {
|
||||
// Client Diagnostic
|
||||
NCManageDatabase.shared.addDiagnostic(account: account, issue: NCGlobal.shared.diagnosticIssueE2eeErrors)
|
||||
return resultsEncodeMetadata.error
|
||||
}
|
||||
|
||||
let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: e2eToken, e2eMetadata: e2eMetadata, signature: resultsEncodeMetadata.signature, method: method)
|
||||
let putE2EEMetadataResults = await NextcloudKit.shared.putE2EEMetadata(fileId: fileId, e2eToken: e2eToken, e2eMetadata: e2eMetadata, signature: resultsEncodeMetadata.signature, method: method, options: NCNetworkingE2EE().getOptions())
|
||||
guard putE2EEMetadataResults.error == .success else {
|
||||
return putE2EEMetadataResults.error
|
||||
}
|
||||
|
@ -148,7 +158,7 @@ class NCNetworkingE2EE: NSObject {
|
|||
func lock(account: String, serverUrl: String) async -> (fileId: String?, e2eToken: String?, error: NKError) {
|
||||
|
||||
var e2eToken: String?
|
||||
var e2eCounter = "0"
|
||||
var e2eCounter = "1"
|
||||
|
||||
guard let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl)) else {
|
||||
return (nil, nil, NKError(errorCode: NCGlobal.shared.errorUnexpectedResponseFromDB, errorDescription: "_e2e_error_"))
|
||||
|
@ -163,7 +173,7 @@ class NCNetworkingE2EE: NSObject {
|
|||
e2eCounter = "\(counter)"
|
||||
}
|
||||
|
||||
let resultsLockE2EEFolder = await NextcloudKit.shared.lockE2EEFolder(fileId: directory.fileId, e2eToken: e2eToken, e2eCounter: e2eCounter, method: "POST")
|
||||
let resultsLockE2EEFolder = await NextcloudKit.shared.lockE2EEFolder(fileId: directory.fileId, e2eToken: e2eToken, e2eCounter: e2eCounter, method: "POST", options: NCNetworkingE2EE().getOptions())
|
||||
if resultsLockE2EEFolder.error == .success, let e2eToken = resultsLockE2EEFolder.e2eToken {
|
||||
NCManageDatabase.shared.setE2ETokenLock(account: account, serverUrl: serverUrl, fileId: directory.fileId, e2eToken: e2eToken)
|
||||
}
|
||||
|
@ -177,7 +187,7 @@ class NCNetworkingE2EE: NSObject {
|
|||
return
|
||||
}
|
||||
|
||||
let resultsLockE2EEFolder = await NextcloudKit.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, e2eCounter: nil, method: "DELETE")
|
||||
let resultsLockE2EEFolder = await NextcloudKit.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, e2eCounter: nil, method: "DELETE", options: NCNetworkingE2EE().getOptions())
|
||||
if resultsLockE2EEFolder.error == .success {
|
||||
NCManageDatabase.shared.deleteE2ETokenLock(account: account, serverUrl: serverUrl)
|
||||
}
|
||||
|
@ -191,7 +201,7 @@ class NCNetworkingE2EE: NSObject {
|
|||
|
||||
Task {
|
||||
for result in NCManageDatabase.shared.getE2EAllTokenLock(account: account) {
|
||||
let resultsLockE2EEFolder = await NextcloudKit.shared.lockE2EEFolder(fileId: result.fileId, e2eToken: result.e2eToken, e2eCounter: nil, method: "DELETE")
|
||||
let resultsLockE2EEFolder = await NextcloudKit.shared.lockE2EEFolder(fileId: result.fileId, e2eToken: result.e2eToken, e2eCounter: nil, method: "DELETE", options: NCNetworkingE2EE().getOptions())
|
||||
if resultsLockE2EEFolder.error == .success {
|
||||
NCManageDatabase.shared.deleteE2ETokenLock(account: account, serverUrl: result.serverUrl)
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ class NCNetworkingE2EECreateFolder: NSObject {
|
|||
|
||||
// SET FOLDER AS E2EE
|
||||
//
|
||||
let resultsMarkE2EEFolder = await NextcloudKit.shared.markE2EEFolder(fileId: fileId, delete: false)
|
||||
let resultsMarkE2EEFolder = await NextcloudKit.shared.markE2EEFolder(fileId: fileId, delete: false, options: NCNetworkingE2EE().getOptions())
|
||||
guard resultsMarkE2EEFolder.error == .success else {
|
||||
await networkingE2EE.unlock(account: account, serverUrl: serverUrl)
|
||||
return resultsMarkE2EEFolder.error
|
||||
|
|
|
@ -31,7 +31,7 @@ class NCNetworkingE2EEMarkFolder: NSObject {
|
|||
let resultsReadFileOrFolder = await NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "0")
|
||||
guard resultsReadFileOrFolder.error == .success, let file = resultsReadFileOrFolder.files.first else { return resultsReadFileOrFolder.error }
|
||||
|
||||
let resultsMarkE2EEFolder = await NextcloudKit.shared.markE2EEFolder(fileId: file.fileId, delete: false)
|
||||
let resultsMarkE2EEFolder = await NextcloudKit.shared.markE2EEFolder(fileId: file.fileId, delete: false, options: NCNetworkingE2EE().getOptions())
|
||||
guard resultsMarkE2EEFolder.error == .success else { return resultsMarkE2EEFolder.error }
|
||||
|
||||
file.e2eEncrypted = true
|
||||
|
|
|
@ -125,7 +125,15 @@ class NCNetworkingE2EEUpload: NSObject {
|
|||
let resultsLock = await networkingE2EE.lock(account: metadata.account, serverUrl: metadata.serverUrl)
|
||||
guard let e2eToken = resultsLock.e2eToken, let fileId = resultsLock.fileId, resultsLock.error == .success else {
|
||||
NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp))
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account, "fileName": metadata.fileName, "ocIdTemp": ocIdTemp, "error": NKError(errorCode: NCGlobal.shared.errorE2EELock, errorDescription: NSLocalizedString("_e2e_error_", comment: ""))])
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"serverUrl": metadata.serverUrl,
|
||||
"account": metadata.account,
|
||||
"fileName": metadata.fileName,
|
||||
"ocIdTemp": ocIdTemp,
|
||||
"error": NKError(errorCode: NCGlobal.shared.errorE2EELock, errorDescription: NSLocalizedString("_e2e_error_", comment: ""))])
|
||||
return NKError(errorCode: NCGlobal.shared.errorE2EELock, errorDescription: NSLocalizedString("_e2e_error_", comment: ""))
|
||||
}
|
||||
|
||||
|
@ -144,7 +152,15 @@ class NCNetworkingE2EEUpload: NSObject {
|
|||
guard sendE2eeError == .success else {
|
||||
DispatchQueue.main.async { hud?.dismiss() }
|
||||
NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp))
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account, "fileName": metadata.fileName, "ocIdTemp": ocIdTemp, "error": sendE2eeError])
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"serverUrl": metadata.serverUrl,
|
||||
"account": metadata.account,
|
||||
"fileName": metadata.fileName,
|
||||
"ocIdTemp": ocIdTemp,
|
||||
"error": sendE2eeError])
|
||||
await networkingE2EE.unlock(account: metadata.account, serverUrl: metadata.serverUrl)
|
||||
return sendE2eeError
|
||||
}
|
||||
|
@ -179,7 +195,15 @@ class NCNetworkingE2EEUpload: NSObject {
|
|||
|
||||
utilityFileSystem.removeFile(atPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId))
|
||||
NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account, "fileName": metadata.fileName, "ocIdTemp": ocIdTemp, "error": resultsSendFile.error])
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"serverUrl": metadata.serverUrl,
|
||||
"account": metadata.account,
|
||||
"fileName": metadata.fileName,
|
||||
"ocIdTemp": ocIdTemp,
|
||||
"error": resultsSendFile.error])
|
||||
|
||||
} else if resultsSendFile.error == .success, let ocId = resultsSendFile.ocId {
|
||||
|
||||
|
@ -193,18 +217,36 @@ class NCNetworkingE2EEUpload: NSObject {
|
|||
|
||||
metadata.session = ""
|
||||
metadata.sessionError = ""
|
||||
metadata.sessionTaskIdentifier = 0
|
||||
metadata.status = NCGlobal.shared.metadataStatusNormal
|
||||
|
||||
NCManageDatabase.shared.addMetadata(metadata)
|
||||
NCManageDatabase.shared.addLocalFile(metadata: metadata)
|
||||
utility.createImageFrom(fileNameView: metadata.fileNameView, ocId: metadata.ocId, etag: metadata.etag, classFile: metadata.classFile)
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account, "fileName": metadata.fileName, "ocIdTemp": ocIdTemp, "error": resultsSendFile.error])
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"serverUrl": metadata.serverUrl,
|
||||
"account": metadata.account,
|
||||
"fileName": metadata.fileName,
|
||||
"ocIdTemp": ocIdTemp,
|
||||
"error": resultsSendFile.error])
|
||||
|
||||
} else {
|
||||
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: nil, sessionError: resultsSendFile.error.errorDescription, sessionSelector: nil, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusUploadError, errorCode: resultsSendFile.error.errorCode)
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account, "fileName": metadata.fileName, "ocIdTemp": ocIdTemp, "error": resultsSendFile.error])
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
|
||||
sessionError: resultsSendFile.error.errorDescription,
|
||||
status: NCGlobal.shared.metadataStatusUploadError,
|
||||
errorCode: resultsSendFile.error.errorCode)
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile),
|
||||
object: nil,
|
||||
userInfo: ["ocId": metadata.ocId,
|
||||
"serverUrl": metadata.serverUrl,
|
||||
"account": metadata.account,
|
||||
"fileName": metadata.fileName,
|
||||
"ocIdTemp": ocIdTemp,
|
||||
"error": resultsSendFile.error])
|
||||
}
|
||||
|
||||
return (resultsSendFile.error)
|
||||
|
|
|
@ -50,7 +50,7 @@ class NCAutoUpload: NSObject {
|
|||
NCManageDatabase.shared.setAccountAutoUploadProperty("autoUpload", state: false)
|
||||
return completion(0)
|
||||
}
|
||||
Task {
|
||||
DispatchQueue.global().async {
|
||||
self.uploadAssetsNewAndFull(viewController: viewController, selector: NCGlobal.shared.selectorUploadAutoUpload, log: "Init Auto Upload") { items in
|
||||
completion(items)
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ class NCAutoUpload: NSObject {
|
|||
let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_create_full_upload_")
|
||||
NCContentPresenter().showWarning(error: error, priority: .max)
|
||||
NCActivityIndicator.shared.start()
|
||||
Task {
|
||||
DispatchQueue.global().async {
|
||||
self.uploadAssetsNewAndFull(viewController: viewController, selector: NCGlobal.shared.selectorUploadAutoUploadAll, log: log) { _ in
|
||||
NCActivityIndicator.shared.stop()
|
||||
}
|
||||
|
@ -125,14 +125,14 @@ class NCAutoUpload: NSObject {
|
|||
session = NextcloudKit.shared.nkCommonInstance.sessionIdentifierUpload
|
||||
} else {
|
||||
if assetMediaType == PHAssetMediaType.image && account.autoUploadWWAnPhoto == false {
|
||||
session = NCNetworking.shared.sessionIdentifierBackground
|
||||
session = NCNetworking.shared.sessionUploadBackground
|
||||
} else if assetMediaType == PHAssetMediaType.video && account.autoUploadWWAnVideo == false {
|
||||
session = NCNetworking.shared.sessionIdentifierBackground
|
||||
session = NCNetworking.shared.sessionUploadBackground
|
||||
} else if assetMediaType == PHAssetMediaType.image && account.autoUploadWWAnPhoto {
|
||||
session = NCNetworking.shared.sessionIdentifierBackgroundWWan
|
||||
session = NCNetworking.shared.sessionUploadBackgroundWWan
|
||||
} else if assetMediaType == PHAssetMediaType.video && account.autoUploadWWAnVideo {
|
||||
session = NCNetworking.shared.sessionIdentifierBackgroundWWan
|
||||
} else { session = NCNetworking.shared.sessionIdentifierBackground }
|
||||
session = NCNetworking.shared.sessionUploadBackgroundWWan
|
||||
} else { session = NCNetworking.shared.sessionUploadBackground }
|
||||
}
|
||||
|
||||
if account.autoUploadCreateSubfolder {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -33,10 +33,11 @@ class NCNetworkingCheckRemoteUser {
|
|||
!token.isEmpty,
|
||||
let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
|
||||
|
||||
NCNetworking.shared.cancelAllQueue()
|
||||
NCNetworking.shared.cancelDataTask()
|
||||
NCNetworking.shared.cancelDownloadTasks()
|
||||
NCNetworking.shared.cancelUploadTasks()
|
||||
NCNetworking.shared.cancelUploadBackgroundTask()
|
||||
NCNetworking.shared.cancelUploadBackgroundTask(withNotification: false)
|
||||
|
||||
if NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion17 {
|
||||
|
||||
|
|
|
@ -110,16 +110,11 @@ class NCNetworkingProcessUpload: NSObject {
|
|||
|
||||
queue.async {
|
||||
|
||||
let metadatasUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND (status == %d OR status == %d)", self.appDelegate.account, NCGlobal.shared.metadataStatusInUpload, NCGlobal.shared.metadataStatusUploading))
|
||||
let metadatasUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND status == %d", self.appDelegate.account, NCGlobal.shared.metadataStatusUploading))
|
||||
let isWiFi = NCNetworking.shared.networkReachability == NKCommon.TypeReachability.reachableEthernetOrWiFi
|
||||
var counterUpload = metadatasUpload.count
|
||||
let sessionSelectors = [NCGlobal.shared.selectorUploadFileNODelete, NCGlobal.shared.selectorUploadFile, NCGlobal.shared.selectorUploadAutoUpload, NCGlobal.shared.selectorUploadAutoUploadAll]
|
||||
|
||||
// Update Badge
|
||||
let counterBadgeDownload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "status < 0"))
|
||||
let counterBadgeUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "status > 0"))
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUpdateBadgeNumber, userInfo: ["counterDownload": counterBadgeDownload.count, "counterUpload": counterBadgeUpload.count])
|
||||
|
||||
// ** TEST ONLY ONE **
|
||||
// E2EE
|
||||
let uniqueMetadatas = metadatasUpload.unique(map: { $0.serverUrl })
|
||||
|
@ -154,7 +149,7 @@ class NCNetworkingProcessUpload: NSObject {
|
|||
}
|
||||
|
||||
// Session Extension ? skipped
|
||||
if metadata.session == NCNetworking.shared.sessionIdentifierBackgroundExtension {
|
||||
if metadata.session == NCNetworking.shared.sessionUploadBackgroundExtension {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -170,7 +165,7 @@ class NCNetworkingProcessUpload: NSObject {
|
|||
let isInDirectoryE2EE = metadata.isDirectoryE2EE
|
||||
|
||||
// NO WiFi
|
||||
if !isWiFi && metadata.session == NCNetworking.shared.sessionIdentifierBackgroundWWan {
|
||||
if !isWiFi && metadata.session == NCNetworking.shared.sessionUploadBackgroundWWan {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -178,7 +173,7 @@ class NCNetworkingProcessUpload: NSObject {
|
|||
continue
|
||||
}
|
||||
|
||||
if let metadata = NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusInUpload) {
|
||||
if let metadata = NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusUploading) {
|
||||
NCNetworking.shared.upload(metadata: metadata, hudView: self.hudView, hud: self.hud)
|
||||
if isInDirectoryE2EE || metadata.chunk > 0 {
|
||||
maxConcurrentOperationUpload = 1
|
||||
|
@ -192,6 +187,11 @@ class NCNetworkingProcessUpload: NSObject {
|
|||
}
|
||||
}
|
||||
|
||||
// Update Badge Number
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUpdateBadgeNumber),
|
||||
object: nil)
|
||||
|
||||
// No upload available ? --> Retry Upload in Error
|
||||
if counterUpload == 0 {
|
||||
let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND status == %d", self.appDelegate.account, NCGlobal.shared.metadataStatusUploadError))
|
||||
|
@ -200,11 +200,17 @@ class NCNetworkingProcessUpload: NSObject {
|
|||
if metadata.sessionError.contains("\(NCGlobal.shared.errorQuota)") {
|
||||
NextcloudKit.shared.getUserProfile { _, userProfile, _, error in
|
||||
if error == .success, let userProfile, userProfile.quotaFree > 0, userProfile.quotaFree > metadata.size {
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: NCNetworking.shared.sessionIdentifierBackground, sessionError: "", sessionSelector: nil, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusWaitUpload, errorCode: nil)
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
|
||||
session: NCNetworking.shared.sessionUploadBackground,
|
||||
sessionError: "",
|
||||
status: NCGlobal.shared.metadataStatusWaitUpload)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: NCNetworking.shared.sessionIdentifierBackground, sessionError: "", sessionSelector: nil, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusWaitUpload, errorCode: nil)
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
|
||||
session: NCNetworking.shared.sessionUploadBackground,
|
||||
sessionError: "",
|
||||
status: NCGlobal.shared.metadataStatusWaitUpload)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,75 +277,72 @@ class NCNetworkingProcessUpload: NSObject {
|
|||
|
||||
func verifyUploadZombie() {
|
||||
|
||||
var session: URLSession?
|
||||
let utilityFileSystem = NCUtilityFileSystem()
|
||||
Task {
|
||||
let utilityFileSystem = NCUtilityFileSystem()
|
||||
var notificationCenter: Bool = false
|
||||
|
||||
// remove leaning upload share extension
|
||||
let metadatasUploadShareExtension = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "session == %@ AND sessionSelector == %@", NextcloudKit.shared.nkCommonInstance.sessionIdentifierUpload, NCGlobal.shared.selectorUploadFileShareExtension))
|
||||
for metadata in metadatasUploadShareExtension {
|
||||
NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
|
||||
utilityFileSystem.removeFile(atPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId))
|
||||
}
|
||||
|
||||
// verify metadataStatusInUpload (BACKGROUND)
|
||||
let metadatasInUploadBackground = NCManageDatabase.shared.getMetadatas(
|
||||
predicate: NSPredicate(
|
||||
format: "(session == %@ OR session == %@ OR session == %@) AND status == %d AND sessionTaskIdentifier == 0",
|
||||
NCNetworking.shared.sessionIdentifierBackground,
|
||||
NCNetworking.shared.sessionIdentifierBackgroundExtension,
|
||||
NCNetworking.shared.sessionIdentifierBackgroundWWan,
|
||||
NCGlobal.shared.metadataStatusInUpload))
|
||||
for metadata in metadatasInUploadBackground {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
|
||||
if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "ocId == %@ AND status == %d AND sessionTaskIdentifier == 0", metadata.ocId, NCGlobal.shared.metadataStatusInUpload)) {
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: NCNetworking.shared.sessionIdentifierBackground, sessionError: "", sessionSelector: nil, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusWaitUpload, errorCode: nil)
|
||||
// selectorUploadFileShareExtension (FOREGROUND)
|
||||
if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "session == %@ AND sessionSelector == %@", NextcloudKit.shared.nkCommonInstance.sessionIdentifierUpload, NCGlobal.shared.selectorUploadFileShareExtension)) {
|
||||
for metadata in results {
|
||||
NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
|
||||
utilityFileSystem.removeFile(atPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId))
|
||||
notificationCenter = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// metadataStatusUploading (BACKGROUND)
|
||||
let metadatasUploadingBackground = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "(session == %@ OR session == %@ OR session == %@) AND status == %d", NCNetworking.shared.sessionIdentifierBackground, NCNetworking.shared.sessionIdentifierBackgroundWWan, NCNetworking.shared.sessionIdentifierBackgroundExtension, NCGlobal.shared.metadataStatusUploading))
|
||||
for metadata in metadatasUploadingBackground {
|
||||
|
||||
if metadata.session == NCNetworking.shared.sessionIdentifierBackground {
|
||||
session = NCNetworking.shared.sessionManagerBackground
|
||||
} else if metadata.session == NCNetworking.shared.sessionIdentifierBackgroundWWan {
|
||||
session = NCNetworking.shared.sessionManagerBackgroundWWan
|
||||
}
|
||||
|
||||
var taskUpload: URLSessionTask?
|
||||
|
||||
session?.getAllTasks(completionHandler: { tasks in
|
||||
for task in tasks {
|
||||
if task.taskIdentifier == metadata.sessionTaskIdentifier {
|
||||
taskUpload = task
|
||||
// metadataStatusUploading (FOREGROUND)
|
||||
if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "session == %@ AND status == %d", NextcloudKit.shared.nkCommonInstance.sessionIdentifierUpload, NCGlobal.shared.metadataStatusUploading)) {
|
||||
if results.isEmpty { NCNetworking.shared.transferInForegorund = nil }
|
||||
for metadata in results {
|
||||
let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
|
||||
if NCNetworking.shared.uploadRequest[fileNameLocalPath] == nil {
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
|
||||
status: NCGlobal.shared.metadataStatusWaitUpload)
|
||||
notificationCenter = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if taskUpload == nil {
|
||||
if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "ocId == %@ AND status == %d", metadata.ocId, NCGlobal.shared.metadataStatusUploading)) {
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: NCNetworking.shared.sessionIdentifierBackground, sessionError: "", sessionSelector: nil, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusWaitUpload, errorCode: nil)
|
||||
// metadataStatusDownloading (FOREGROUND)
|
||||
if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "session == %@ AND status == %d", NextcloudKit.shared.nkCommonInstance.sessionIdentifierDownload, NCGlobal.shared.metadataStatusDownloading)) {
|
||||
for metadata in results {
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
|
||||
session: "",
|
||||
sessionError: "",
|
||||
selector: "",
|
||||
status: NCGlobal.shared.metadataStatusNormal,
|
||||
errorCode: 0)
|
||||
notificationCenter = true
|
||||
}
|
||||
}
|
||||
|
||||
// metadataStatusUploading (BACKGROUND)
|
||||
let results = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "(session == %@ OR session == %@ OR session == %@) AND status == %d", NCNetworking.shared.sessionUploadBackground, NCNetworking.shared.sessionUploadBackgroundWWan, NCNetworking.shared.sessionUploadBackgroundExtension, NCGlobal.shared.metadataStatusUploading))
|
||||
for metadata in results {
|
||||
var taskUpload: URLSessionTask?
|
||||
var session: URLSession?
|
||||
if metadata.session == NCNetworking.shared.sessionUploadBackground {
|
||||
session = NCNetworking.shared.sessionManagerUploadBackground
|
||||
} else if metadata.session == NCNetworking.shared.sessionUploadBackgroundWWan {
|
||||
session = NCNetworking.shared.sessionManagerUploadBackgroundWWan
|
||||
}
|
||||
if let tasks = await session?.allTasks {
|
||||
for task in tasks {
|
||||
if task.taskIdentifier == metadata.sessionTaskIdentifier { taskUpload = task }
|
||||
}
|
||||
if taskUpload == nil, let metadata = NCManageDatabase.shared.getResultMetadata(predicate: NSPredicate(format: "ocId == %@ AND status == %d", metadata.ocId, NCGlobal.shared.metadataStatusUploading)) {
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
|
||||
session: NCNetworking.shared.sessionUploadBackground,
|
||||
sessionError: "",
|
||||
status: NCGlobal.shared.metadataStatusWaitUpload)
|
||||
notificationCenter = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// metadataStatusUploading OR metadataStatusInUpload (FOREGROUND)
|
||||
let metadatasUploading = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "session == %@ AND (status == %d OR status == %d)", NextcloudKit.shared.nkCommonInstance.sessionIdentifierUpload, NCGlobal.shared.metadataStatusUploading, NCGlobal.shared.metadataStatusInUpload))
|
||||
if metadatasUploading.isEmpty {
|
||||
NCNetworking.shared.transferInForegorund = nil
|
||||
}
|
||||
for metadata in metadatasUploading {
|
||||
let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
|
||||
if NCNetworking.shared.uploadRequest[fileNameLocalPath] == nil {
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: nil, sessionError: "", sessionSelector: nil, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusWaitUpload, errorCode: nil)
|
||||
}
|
||||
}
|
||||
|
||||
// download
|
||||
let metadatasDownload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "session == %@", NextcloudKit.shared.nkCommonInstance.sessionIdentifierDownload))
|
||||
for metadata in metadatasDownload {
|
||||
NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: "", sessionError: "", sessionSelector: "", sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusNormal, errorCode: 0)
|
||||
if notificationCenter {
|
||||
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,8 +51,7 @@ class NCService: NSObject {
|
|||
requestDashboardWidget()
|
||||
NCNetworkingE2EE().unlockAll(account: account)
|
||||
NCNetworkingProcessUpload.shared.verifyUploadZombie()
|
||||
// TODO: sendClientDiagnosticsRemoteOperation(account: account)
|
||||
// sendClientDiagnosticsRemoteOperation(account: account)
|
||||
sendClientDiagnosticsRemoteOperation(account: account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +132,6 @@ class NCService: NSObject {
|
|||
|
||||
func synchronize() {
|
||||
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] start synchronize Favorite")
|
||||
NextcloudKit.shared.listingFavorites(showHiddenFiles: NCKeychain().showHiddenFiles,
|
||||
options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { account, files, _, error in
|
||||
|
||||
|
@ -141,8 +139,7 @@ class NCService: NSObject {
|
|||
NCManageDatabase.shared.convertFilesToMetadatas(files, useMetadataFolder: false) { _, _, metadatas in
|
||||
NCManageDatabase.shared.updateMetadatasFavorite(account: account, metadatas: metadatas)
|
||||
}
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] end synchronize Favorite")
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] start synchronize Offline")
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Synchronize Favorite")
|
||||
self.synchronizeOffline(account: account)
|
||||
}
|
||||
}
|
||||
|
@ -291,9 +288,11 @@ class NCService: NSObject {
|
|||
@objc func synchronizeOffline(account: String) {
|
||||
|
||||
// Synchronize Directory
|
||||
if let directories = NCManageDatabase.shared.getTablesDirectory(predicate: NSPredicate(format: "account == %@ AND offline == true", account), sorted: "serverUrl", ascending: true) {
|
||||
for directory: tableDirectory in directories {
|
||||
NCNetworking.shared.synchronizationServerUrl(directory.serverUrl, account: account, selector: NCGlobal.shared.selectorSynchronizationOffline)
|
||||
Task {
|
||||
if let directories = NCManageDatabase.shared.getTablesDirectory(predicate: NSPredicate(format: "account == %@ AND offline == true", account), sorted: "serverUrl", ascending: true) {
|
||||
for directory: tableDirectory in directories {
|
||||
await NCNetworking.shared.synchronization(account: account, serverUrl: directory.serverUrl, selector: NCGlobal.shared.selectorSynchronizationOffline)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,47 +300,116 @@ class NCService: NSObject {
|
|||
let files = NCManageDatabase.shared.getTableLocalFiles(predicate: NSPredicate(format: "account == %@ AND offline == true", account), sorted: "fileName", ascending: true)
|
||||
for file: tableLocalFile in files {
|
||||
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(file.ocId) else { continue }
|
||||
if NCNetworking.shared.synchronizeMetadata(metadata),
|
||||
if metadata.isSynchronizable,
|
||||
NCNetworking.shared.downloadQueue.operations.filter({ ($0 as? NCOperationDownload)?.metadata.ocId == metadata.ocId }).isEmpty {
|
||||
NCNetworking.shared.downloadQueue.addOperation(NCOperationDownload(metadata: metadata, selector: NCGlobal.shared.selectorDownloadFile))
|
||||
}
|
||||
}
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] end synchronize offline")
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
func sendClientDiagnosticsRemoteOperation(account: String) {
|
||||
|
||||
struct Problem: Codable {
|
||||
let count: Int
|
||||
let oldest: TimeInterval
|
||||
}
|
||||
guard NCGlobal.shared.capabilitySecurityGuardDiagnostics,
|
||||
NCManageDatabase.shared.existsDiagnostics(account: account) else { return }
|
||||
|
||||
struct Problems: Codable {
|
||||
var problems: [String: Problem] = [:]
|
||||
}
|
||||
struct Issues: Codable {
|
||||
|
||||
var problems = Problems()
|
||||
|
||||
guard let metadatas = NCManageDatabase.shared.getMetadatasInError(account: account), !metadatas.isEmpty else { return }
|
||||
for metadata in metadatas {
|
||||
guard let oldest = metadata.errorCodeDate?.timeIntervalSince1970 else { continue }
|
||||
var key = String(metadata.errorCode)
|
||||
if !metadata.sessionError.isEmpty {
|
||||
key = key + " - " + metadata.sessionError
|
||||
struct SyncConflicts: Codable {
|
||||
var count: Int?
|
||||
var oldest: TimeInterval?
|
||||
}
|
||||
let value = Problem(count: metadata.errorCodeCounter, oldest: oldest)
|
||||
problems.problems[key] = value
|
||||
|
||||
struct VirusDetected: Codable {
|
||||
var count: Int?
|
||||
var oldest: TimeInterval?
|
||||
}
|
||||
|
||||
struct E2EError: Codable {
|
||||
var count: Int?
|
||||
var oldest: TimeInterval?
|
||||
}
|
||||
|
||||
struct Problem: Codable {
|
||||
struct Error: Codable {
|
||||
var count: Int
|
||||
var oldest: TimeInterval
|
||||
}
|
||||
|
||||
var forbidden: Error? // NCGlobal.shared.diagnosticProblemsForbidden
|
||||
var badResponse: Error? // NCGlobal.shared.diagnosticProblemsBadResponse
|
||||
var uploadServerError: Error? // NCGlobal.shared.diagnosticProblemsUploadServerError
|
||||
}
|
||||
|
||||
var syncConflicts: SyncConflicts
|
||||
var virusDetected: VirusDetected
|
||||
var e2eeErrors: E2EError
|
||||
var problems: Problem?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case syncConflicts = "sync_conflicts"
|
||||
case virusDetected = "virus_detected"
|
||||
case e2eeErrors = "e2ee_errors"
|
||||
case problems
|
||||
}
|
||||
}
|
||||
|
||||
var ids: [ObjectId] = []
|
||||
|
||||
var syncConflicts: Issues.SyncConflicts = Issues.SyncConflicts()
|
||||
var virusDetected: Issues.VirusDetected = Issues.VirusDetected()
|
||||
var e2eeErrors: Issues.E2EError = Issues.E2EError()
|
||||
|
||||
var problems: Issues.Problem? = Issues.Problem()
|
||||
var problemForbidden: Issues.Problem.Error?
|
||||
var problemBadResponse: Issues.Problem.Error?
|
||||
var problemUploadServerError: Issues.Problem.Error?
|
||||
|
||||
if let result = NCManageDatabase.shared.getDiagnostics(account: account, issue: NCGlobal.shared.diagnosticIssueSyncConflicts)?.first {
|
||||
syncConflicts = Issues.SyncConflicts(count: result.counter, oldest: result.oldest)
|
||||
ids.append(result.id)
|
||||
}
|
||||
if let result = NCManageDatabase.shared.getDiagnostics(account: account, issue: NCGlobal.shared.diagnosticIssueVirusDetected)?.first {
|
||||
virusDetected = Issues.VirusDetected(count: result.counter, oldest: result.oldest)
|
||||
ids.append(result.id)
|
||||
}
|
||||
if let result = NCManageDatabase.shared.getDiagnostics(account: account, issue: NCGlobal.shared.diagnosticIssueE2eeErrors)?.first {
|
||||
e2eeErrors = Issues.E2EError(count: result.counter, oldest: result.oldest)
|
||||
ids.append(result.id)
|
||||
}
|
||||
if let results = NCManageDatabase.shared.getDiagnostics(account: account, issue: NCGlobal.shared.diagnosticIssueProblems) {
|
||||
for result in results {
|
||||
switch result.error {
|
||||
case NCGlobal.shared.diagnosticProblemsForbidden:
|
||||
if result.counter >= 1 {
|
||||
problemForbidden = Issues.Problem.Error(count: result.counter, oldest: result.oldest)
|
||||
ids.append(result.id)
|
||||
}
|
||||
case NCGlobal.shared.diagnosticProblemsBadResponse:
|
||||
if result.counter >= 2 {
|
||||
problemBadResponse = Issues.Problem.Error(count: result.counter, oldest: result.oldest)
|
||||
ids.append(result.id)
|
||||
}
|
||||
case NCGlobal.shared.diagnosticProblemsUploadServerError:
|
||||
if result.counter >= 1 {
|
||||
problemUploadServerError = Issues.Problem.Error(count: result.counter, oldest: result.oldest)
|
||||
ids.append(result.id)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
problems = Issues.Problem(forbidden: problemForbidden, badResponse: problemBadResponse, uploadServerError: problemUploadServerError)
|
||||
}
|
||||
|
||||
do {
|
||||
@ThreadSafe var metadatas = metadatas
|
||||
let data = try JSONEncoder().encode(problems)
|
||||
let issues = Issues(syncConflicts: syncConflicts, virusDetected: virusDetected, e2eeErrors: e2eeErrors, problems: problems)
|
||||
let data = try JSONEncoder().encode(issues)
|
||||
data.printJson()
|
||||
NextcloudKit.shared.sendClientDiagnosticsRemoteOperation(problems: data, options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { _, error in
|
||||
NextcloudKit.shared.sendClientDiagnosticsRemoteOperation(data: data, options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { _, error in
|
||||
if error == .success {
|
||||
NCManageDatabase.shared.clearErrorCodeMetadatas(metadatas: metadatas)
|
||||
NCManageDatabase.shared.deleteDiagnostics(account: account, ids: ids)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
|
|
@ -67,7 +67,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty
|
|||
super.viewWillAppear(animated)
|
||||
|
||||
appDelegate.activeViewController = self
|
||||
navigationController?.setFileAppreance()
|
||||
navigationController?.setNavigationBarAppearance()
|
||||
getNetwokingNotification()
|
||||
}
|
||||
|
||||
|
|
|
@ -44,12 +44,13 @@ class NCOffline: NCCollectionViewCommon {
|
|||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
navigationController?.setFileAppreance()
|
||||
reloadDataSource()
|
||||
}
|
||||
|
||||
// MARK: - DataSource + NC Endpoint
|
||||
|
||||
override func queryDB(isForced: Bool) {
|
||||
override func queryDB() {
|
||||
super.queryDB()
|
||||
|
||||
var ocIds: [String] = []
|
||||
var metadatas: [tableMetadata] = []
|
||||
|
@ -81,21 +82,9 @@ class NCOffline: NCCollectionViewCommon {
|
|||
searchResults: self.searchResults)
|
||||
}
|
||||
|
||||
override func reloadDataSource(isForced: Bool = true) {
|
||||
super.reloadDataSource()
|
||||
override func reloadDataSourceNetwork() {
|
||||
super.reloadDataSourceNetwork()
|
||||
|
||||
DispatchQueue.global().async {
|
||||
self.queryDB(isForced: isForced)
|
||||
DispatchQueue.main.async {
|
||||
self.refreshControl.endRefreshing()
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func reloadDataSourceNetwork(isForced: Bool = false) {
|
||||
super.reloadDataSourceNetwork(isForced: isForced)
|
||||
|
||||
return self.reloadDataSource()
|
||||
reloadDataSource()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,12 +105,12 @@
|
|||
NSData *pushPublicKey = [[[NCKeychain alloc] init] getPushNotificationPublicKeyWithAccount:account];
|
||||
NSString *pushDevicePublicKey = [[NSString alloc] initWithData:pushPublicKey encoding:NSUTF8StringEncoding];
|
||||
NSString *proxyServerPath = [NCBrandOptions shared].pushNotificationServerProxy;
|
||||
NKRequestOptions *options = [[NKRequestOptions alloc] initWithEndpoint:nil customHeader:nil customUserAgent:nil contentType:nil e2eToken:nil timeout:60 queue:dispatch_get_main_queue()];
|
||||
NKRequestOptions *options = [[NKRequestOptions alloc] initWithEndpoint:nil version:nil customHeader:nil customUserAgent:nil contentType:nil e2eToken:nil timeout:60 queue:dispatch_get_main_queue()];
|
||||
|
||||
[[NextcloudKit shared] subscribingPushNotificationWithServerUrl:urlBase account:account user:user password:[[[NCKeychain alloc] init] getPasswordWithAccount:account] pushTokenHash:pushTokenHash devicePublicKey:pushDevicePublicKey proxyServerUrl:proxyServerPath options:options completion:^(NSString *account, NSString *deviceIdentifier, NSString *signature, NSString *publicKey, NSData *data, NKError *error) {
|
||||
if (error == NKError.success) {
|
||||
NSString *userAgent = [NSString stringWithFormat:@"%@ (Strict VoIP)", [[NCBrandOptions shared] getUserAgent]];
|
||||
NKRequestOptions *options = [[NKRequestOptions alloc] initWithEndpoint:nil customHeader:nil customUserAgent:userAgent contentType:nil e2eToken:nil timeout:60 queue:dispatch_get_main_queue()];
|
||||
NKRequestOptions *options = [[NKRequestOptions alloc] initWithEndpoint:nil version:nil customHeader:nil customUserAgent:userAgent contentType:nil e2eToken:nil timeout:60 queue:dispatch_get_main_queue()];
|
||||
|
||||
[[NextcloudKit shared] subscribingPushProxyWithProxyServerUrl:proxyServerPath pushToken:self.pushKitToken deviceIdentifier:deviceIdentifier signature:signature publicKey:publicKey options:options completion:^(NKError *error) {
|
||||
if (error == NKError.success) {
|
||||
|
@ -134,13 +134,13 @@
|
|||
NSString *deviceIdentifier = [[[NCKeychain alloc] init] getPushNotificationDeviceIdentifierWithAccount:account];
|
||||
NSString *signature = [[[NCKeychain alloc] init] getPushNotificationDeviceIdentifierSignatureWithAccount:account];
|
||||
NSString *publicKey = [[[NCKeychain alloc] init] getPushNotificationSubscribingPublicKeyWithAccount:account];
|
||||
NKRequestOptions *options = [[NKRequestOptions alloc] initWithEndpoint:nil customHeader:nil customUserAgent:nil contentType:nil e2eToken:nil timeout:60 queue:dispatch_get_main_queue()];
|
||||
NKRequestOptions *options = [[NKRequestOptions alloc] initWithEndpoint:nil version:nil customHeader:nil customUserAgent:nil contentType:nil e2eToken:nil timeout:60 queue:dispatch_get_main_queue()];
|
||||
|
||||
[[NextcloudKit shared] unsubscribingPushNotificationWithServerUrl:urlBase account:account user:user password:[[[NCKeychain alloc] init] getPasswordWithAccount:account] options:options completion:^(NSString *account, NKError *error) {
|
||||
if (error == NKError.success) {
|
||||
NSString *proxyServerPath = [NCBrandOptions shared].pushNotificationServerProxy;
|
||||
NSString *userAgent = [NSString stringWithFormat:@"%@ (Strict VoIP)", [[NCBrandOptions shared] getUserAgent]];
|
||||
NKRequestOptions *options = [[NKRequestOptions alloc] initWithEndpoint:nil customHeader:nil customUserAgent:userAgent contentType:nil e2eToken:nil timeout:60 queue:dispatch_get_main_queue()];
|
||||
NKRequestOptions *options = [[NKRequestOptions alloc] initWithEndpoint:nil version:nil customHeader:nil customUserAgent:userAgent contentType:nil e2eToken:nil timeout:60 queue:dispatch_get_main_queue()];
|
||||
|
||||
[[NextcloudKit shared] unsubscribingPushProxyWithProxyServerUrl:proxyServerPath deviceIdentifier:deviceIdentifier signature:signature publicKey:publicKey options:options completion:^(NKError *error) {
|
||||
if (error == NKError.success) {
|
||||
|
|
|
@ -44,12 +44,13 @@ class NCRecent: NCCollectionViewCommon {
|
|||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
navigationController?.setFileAppreance()
|
||||
reloadDataSourceNetwork()
|
||||
}
|
||||
|
||||
// MARK: - DataSource + NC Endpoint
|
||||
|
||||
override func queryDB(isForced: Bool) {
|
||||
override func queryDB() {
|
||||
super.queryDB()
|
||||
|
||||
let metadatas = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "account == %@", self.appDelegate.account), page: 1, limit: 100, sorted: "date", ascending: false)
|
||||
self.dataSource = NCDataSource(metadatas: metadatas,
|
||||
|
@ -61,20 +62,8 @@ class NCRecent: NCCollectionViewCommon {
|
|||
searchResults: self.searchResults)
|
||||
}
|
||||
|
||||
override func reloadDataSource(isForced: Bool = true) {
|
||||
super.reloadDataSource()
|
||||
|
||||
DispatchQueue.global().async {
|
||||
self.queryDB(isForced: isForced)
|
||||
DispatchQueue.main.async {
|
||||
self.refreshControl.endRefreshing()
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func reloadDataSourceNetwork(isForced: Bool = false) {
|
||||
super.reloadDataSourceNetwork(isForced: isForced)
|
||||
override func reloadDataSourceNetwork() {
|
||||
super.reloadDataSourceNetwork()
|
||||
|
||||
let requestBodyRecent =
|
||||
"""
|
||||
|
@ -144,17 +133,11 @@ class NCRecent: NCCollectionViewCommon {
|
|||
let lessDateString = dateFormatter.string(from: Date())
|
||||
let requestBody = String(format: requestBodyRecent, "/files/" + appDelegate.userId, lessDateString)
|
||||
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Reload data source network recent forced \(isForced)")
|
||||
|
||||
isReloadDataSourceNetworkInProgress = true
|
||||
collectionView?.reloadData()
|
||||
|
||||
NextcloudKit.shared.searchBodyRequest(serverUrl: appDelegate.urlBase,
|
||||
requestBody: requestBody,
|
||||
showHiddenFiles: NCKeychain().showHiddenFiles,
|
||||
options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { account, files, _, error in
|
||||
|
||||
self.isReloadDataSourceNetworkInProgress = false
|
||||
if error == .success {
|
||||
NCManageDatabase.shared.convertFilesToMetadatas(files, useMetadataFolder: false) { _, metadatasFolder, metadatas in
|
||||
// Update sub directories
|
||||
|
@ -167,7 +150,7 @@ class NCRecent: NCCollectionViewCommon {
|
|||
self.reloadDataSource()
|
||||
}
|
||||
} else {
|
||||
self.reloadDataSource()
|
||||
self.reloadDataSource(withQueryDB: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,15 +61,13 @@ import MarkdownKit
|
|||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
NCNetworking.shared.readFile(serverUrlFileName: serverUrl) { account, metadata, error in
|
||||
|
||||
if error == .success && account == self.appDelegate.account {
|
||||
guard let metadata = metadata else { return }
|
||||
NCManageDatabase.shared.setDirectory(serverUrl: self.serverUrl, richWorkspace: metadata.richWorkspace, account: account)
|
||||
if self.richWorkspaceText != metadata.richWorkspace && metadata.richWorkspace != nil {
|
||||
self.delegate?.richWorkspaceText = self.richWorkspaceText
|
||||
self.richWorkspaceText = metadata.richWorkspace!
|
||||
DispatchQueue.main.async {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
NCNetworking.shared.readFile(serverUrlFileName: self.serverUrl, queue: .main) { account, metadata, error in
|
||||
if error == .success, account == self.appDelegate.account, let metadata {
|
||||
NCManageDatabase.shared.setDirectory(serverUrl: self.serverUrl, richWorkspace: metadata.richWorkspace, account: account)
|
||||
if self.richWorkspaceText != metadata.richWorkspace, metadata.richWorkspace != nil {
|
||||
self.delegate?.richWorkspaceText = self.richWorkspaceText
|
||||
self.richWorkspaceText = metadata.richWorkspace!
|
||||
self.textView.attributedText = self.markdownParser.parse(metadata.richWorkspace!)
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +84,6 @@ import MarkdownKit
|
|||
}
|
||||
|
||||
@IBAction func editItemAction(_ sender: Any) {
|
||||
|
||||
richWorkspaceCommon.openViewerNextcloudText(serverUrl: serverUrl, viewController: self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ class NCUploadScanDocument: ObservableObject {
|
|||
url: "",
|
||||
contentType: "")
|
||||
|
||||
metadata.session = NCNetworking.shared.sessionIdentifierBackground
|
||||
metadata.session = NCNetworking.shared.sessionUploadBackground
|
||||
metadata.sessionSelector = NCGlobal.shared.selectorUploadFile
|
||||
metadata.status = NCGlobal.shared.metadataStatusWaitUpload
|
||||
|
||||
|
|
|
@ -355,10 +355,11 @@
|
|||
|
||||
- (void)clearCache:(NSString *)account
|
||||
{
|
||||
[[NCNetworking shared] cancelAllQueue];
|
||||
[[NCNetworking shared] cancelDataTask];
|
||||
[[NCNetworking shared] cancelDownloadTasks];
|
||||
[[NCNetworking shared] cancelUploadTasks];
|
||||
[[NCNetworking shared] cancelUploadBackgroundTask];
|
||||
[[NCNetworking shared] cancelUploadBackgroundTaskWithNotification:false];
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
|
||||
|
||||
|
|
|
@ -101,7 +101,9 @@ import KeychainAccess
|
|||
}
|
||||
keychainOLD["notPasscodeAtStart"] = nil
|
||||
}
|
||||
if let value = try? keychain.get("requestPasscodeAtStart"), let result = Bool(value) {
|
||||
if NCBrandOptions.shared.doNotAskPasscodeAtStartup {
|
||||
return false
|
||||
} else if let value = try? keychain.get("requestPasscodeAtStart"), let result = Bool(value) {
|
||||
return result
|
||||
}
|
||||
return true
|
||||
|
@ -124,19 +126,6 @@ import KeychainAccess
|
|||
}
|
||||
}
|
||||
|
||||
var intro: Bool {
|
||||
get {
|
||||
migrate(key: "intro")
|
||||
if let value = try? keychain.get("intro"), let result = Bool(value) {
|
||||
return result
|
||||
}
|
||||
return false
|
||||
}
|
||||
set {
|
||||
keychain["intro"] = String(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
@objc var incrementalNumber: String {
|
||||
migrate(key: "incrementalnumber")
|
||||
var incrementalString = String(format: "%04ld", 0)
|
||||
|
@ -278,16 +267,15 @@ import KeychainAccess
|
|||
}
|
||||
}
|
||||
|
||||
var mediaWidthImage: Int {
|
||||
var mediaItemForLine: Int {
|
||||
get {
|
||||
migrate(key: "mediaWidthImage")
|
||||
if let value = try? keychain.get("mediaWidthImage"), let result = Int(value) {
|
||||
if let value = try? keychain.get("itemForLine"), let result = Int(value) {
|
||||
return result
|
||||
}
|
||||
return 80
|
||||
return 3
|
||||
}
|
||||
set {
|
||||
keychain["mediaWidthImage"] = String(newValue)
|
||||
keychain["itemForLine"] = String(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -94,6 +94,9 @@
|
|||
row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor;
|
||||
[row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"];
|
||||
[row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"];
|
||||
if ([[NCBrandOptions shared] doNotAskPasscodeAtStartup]) {
|
||||
row.disabled = @YES;
|
||||
}
|
||||
[section addFormRow:row];
|
||||
// Privacy screen
|
||||
row = [XLFormRowDescriptor formRowDescriptorWithTag:@"privacyScreen" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_privacy_screen_", nil)];
|
||||
|
|
|
@ -44,12 +44,16 @@ class NCShares: NCCollectionViewCommon {
|
|||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
navigationController?.setFileAppreance()
|
||||
if dataSource.metadatas.isEmpty {
|
||||
reloadDataSource()
|
||||
}
|
||||
reloadDataSourceNetwork()
|
||||
}
|
||||
|
||||
// MARK: - DataSource + NC Endpoint
|
||||
|
||||
override func queryDB(isForced: Bool) {
|
||||
override func queryDB() {
|
||||
super.queryDB()
|
||||
|
||||
var metadatas: [tableMetadata] = []
|
||||
|
||||
|
@ -92,35 +96,21 @@ class NCShares: NCCollectionViewCommon {
|
|||
reload()
|
||||
}
|
||||
|
||||
override func reloadDataSource(isForced: Bool = true) {
|
||||
super.reloadDataSource()
|
||||
|
||||
DispatchQueue.global().async {
|
||||
self.queryDB(isForced: isForced)
|
||||
}
|
||||
}
|
||||
|
||||
override func reloadDataSourceNetwork(isForced: Bool = false) {
|
||||
super.reloadDataSourceNetwork(isForced: isForced)
|
||||
|
||||
NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Reload data source network shares forced \(isForced)")
|
||||
|
||||
isReloadDataSourceNetworkInProgress = true
|
||||
collectionView?.reloadData()
|
||||
override func reloadDataSourceNetwork() {
|
||||
super.reloadDataSourceNetwork()
|
||||
|
||||
NextcloudKit.shared.readShares(parameters: NKShareParameter()) { account, shares, _, error in
|
||||
|
||||
self.refreshControl.endRefreshing()
|
||||
self.isReloadDataSourceNetworkInProgress = false
|
||||
|
||||
if error == .success {
|
||||
NCManageDatabase.shared.deleteTableShare(account: account)
|
||||
if let shares = shares, !shares.isEmpty {
|
||||
let home = self.utilityFileSystem.getHomeServer(urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId)
|
||||
NCManageDatabase.shared.addShare(account: self.appDelegate.account, home: home, shares: shares)
|
||||
}
|
||||
self.reloadDataSource()
|
||||
} else {
|
||||
self.reloadDataSource(withQueryDB: false)
|
||||
}
|
||||
self.reloadDataSource()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Двоичные данные
iOSClient/Supporting Files/af.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/af.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/an.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/an.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/ar.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/ar.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/ast.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/ast.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/az.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/az.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/be.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/be.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/br.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/br.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/bs.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/bs.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/ca.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/ca.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/da.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/da.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/de.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/de.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/el.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/el.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/en-GB.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/en-GB.lproj/Localizable.strings
Двоичный файл не отображается.
|
@ -198,7 +198,7 @@
|
|||
"_source_code_" = "Get source code";
|
||||
"_account_select_" = "Select the account";
|
||||
"_account_select_to_add_" = "Select the account to add";
|
||||
"_host_insert_" = "Insert the host name, for example:";
|
||||
"_host_insert_" = "Insert the hostname, for example:";
|
||||
"_certificate_not_found_" = "File %@ in documents directory not found.";
|
||||
"_copy_failed_" = "Copy failed";
|
||||
"_certificate_installed_" = "Certificate installed";
|
||||
|
@ -593,6 +593,7 @@
|
|||
"_media_viewimage_show_" = "Show only images";
|
||||
"_media_viewvideo_show_" = "Show only video";
|
||||
"_media_show_all_" = "Show both";
|
||||
"_media_view_options_" = "View options";
|
||||
"_media_by_created_date_" = "Sort by created date";
|
||||
"_media_by_upload_date_" = "Sort by upload date";
|
||||
"_media_by_modified_date_" = "Sort by modified date";
|
||||
|
@ -949,6 +950,10 @@
|
|||
"_reset_wrong_passcode_" = "Reset application";
|
||||
"_reset_wrong_passcode_desc_" = "Use \"Reset application\" to remove all accounts and local data after %d failed code entry attempts.";
|
||||
"_deviceOwnerAuthentication_" = "The biometric sensor has been temporarily disabled due to multiple failed attempts. Enter the device passcode to re-enable the sensor.";
|
||||
"_virus_detect_" = "Virus detected. Upload cannot be completed!";
|
||||
"_zoom_" = "Zoom";
|
||||
"_zoom_in_" = "Zoom in";
|
||||
"_zoom_out_" = "Zoom out";
|
||||
|
||||
// Video
|
||||
"_select_trace_" = "Select the trace";
|
||||
|
|
Двоичные данные
iOSClient/Supporting Files/eo.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/eo.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/es-419.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/es-419.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/es-AR.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/es-AR.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/es-CL.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/es-CL.lproj/Localizable.strings
Двоичный файл не отображается.
Двоичные данные
iOSClient/Supporting Files/es-CO.lproj/Localizable.strings
Двоичные данные
iOSClient/Supporting Files/es-CO.lproj/Localizable.strings
Двоичный файл не отображается.
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче