V 5.0.0
This commit is contained in:
Marino Faggiana 2024-02-01 15:28:44 +01:00 коммит произвёл GitHub
Родитель 6244f78a06
Коммит e51ce11520
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
198 изменённых файлов: 3147 добавлений и 2309 удалений

Просмотреть файл

@ -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()
}
}
}

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Просмотреть файл

@ -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";

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше