diff options
author | marinofaggiana <marino@marinofaggiana.com> | 2021-12-21 12:29:59 +0300 |
---|---|---|
committer | marinofaggiana <marino@marinofaggiana.com> | 2021-12-21 12:29:59 +0300 |
commit | d33196a70f4cfe495260d7c0f56a998560f3815d (patch) | |
tree | a6ea11aa0eb3fb440bfcc7f814f2a457b5166f97 | |
parent | 142a060dccfee8db9775d9030e9372fe95b9110f (diff) | |
parent | ddb9514ebe54cdb8a759b32d1616e137b747ea95 (diff) |
Merge branch 'develop'4.2.0
230 files changed, 11130 insertions, 10340 deletions
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..e52d39172 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,24 @@ + +# Lints the project using SwiftLint + +name: SwiftLint + +on: + push: + branches: + - master + - develop + pull_request: + branches: + - master + - develop + +jobs: + Lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: GitHub Action for SwiftLint + uses: norio-nomura/action-swiftlint@3.1.0 diff --git a/.github/workflows/xcode.yml b/.github/workflows/xcode.yml new file mode 100644 index 000000000..65c3ff88d --- /dev/null +++ b/.github/workflows/xcode.yml @@ -0,0 +1,55 @@ +name: Build + +on: + push: + branches: + - master + - develop + pull_request: + branches: + - master + - develop + +jobs: + XCBuild: + runs-on: macOS-11 + env: + PROJECT: Nextcloud.xcodeproj + DESTINATION: platform=iOS Simulator,name=iPhone 11 + steps: + - name: Set env var + run: echo "DEVELOPER_DIR=$(xcode-select --print-path)" >> $GITHUB_ENV + - uses: actions/checkout@v2 + - name: Restore Carhage Cache + uses: actions/cache@v2 + id: carthage-cache + with: + path: Carthage + key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }} + restore-keys: | + ${{ runner.os }}-carthage- + - name: Carthage + if: steps.carthage-cache.outputs.cache-hit != 'true' + run: carthage bootstrap --use-xcframeworks --platform iOS + - name: Download GoogleService-Info.plist + run: wget "https://raw.githubusercontent.com/firebase/quickstart-ios/master/mock-GoogleService-Info.plist" -O GoogleService-Info.plist + - name: Build & Test Nextcloud iOS + run: | + xcodebuild clean build test -project $PROJECT -scheme "$SCHEME" -destination "$DESTINATION" + env: + SCHEME: Nextcloud + - name: Build iOS Share + run: | + xcodebuild build -project $PROJECT -scheme "$SCHEME" -destination "$DESTINATION" + env: + SCHEME: Share + - name: Build iOS File Extension + run: | + xcodebuild build -project $PROJECT -scheme "$SCHEME" -destination "$DESTINATION" + env: + SCHEME: File Provider Extension + - name: Build iOS Notification Extension + run: | + xcodebuild build -project $PROJECT -scheme "$SCHEME" -destination "$DESTINATION" + env: + SCHEME: Notification Service Extension
\ No newline at end of file diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 000000000..aa7354d20 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,145 @@ +opt_in_rules: # some rules are turned off by default, so you need to opt-in + - empty_collection_literal + - empty_count + - empty_string + - explicit_init + - unneeded_parentheses_in_closure_argument + +empty_count: + severity: warning + +line_length: + # warning: 120 + warning: 200 + +type_body_length: + # error: 350 + error: 500 + +identifier_name: + min_length: 0 + + +excluded: + - Carthage + - Pods + + # iOS Files Quarantine + - File Provider Extension/FileProviderData.swift + - File Provider Extension/FileProviderDomain.swift + - File Provider Extension/FileProviderEnumerator.swift + - File Provider Extension/FileProviderExtension+Actions.swift + - File Provider Extension/FileProviderExtension+Thumbnail.swift + - File Provider Extension/FileProviderExtension.swift + - File Provider Extension/FileProviderUtility.swift + - Notification Service Extension/NotificationService.swift + - Share/NCShareExtension.swift + - iOSClient/Activity/NCActivity.swift + - iOSClient/Activity/NCActivityTableViewCell.swift + - iOSClient/AppDelegate.swift + - iOSClient/BackgroundImageColor/NCBackgroundImageColor.swift + - iOSClient/Brand/Intro/NCIntroViewController.swift + - iOSClient/Brand/NCBrand.swift + - iOSClient/BrowserWeb/NCBrowserWeb.swift + - iOSClient/Data/NCDataSource.swift + - iOSClient/Data/NCDatabase.swift + - iOSClient/Data/NCElementsJSON.swift + - iOSClient/Data/NCManageDatabase+Account.swift + - iOSClient/Data/NCManageDatabase+Activity.swift + - iOSClient/Data/NCManageDatabase.swift + - iOSClient/Data/NCManageDatabse+Metadata.swift + - iOSClient/Diagnostics/NCCapabilitiesViewController.swift + - iOSClient/EmptyView/NCEmptyDataSet.swift + - iOSClient/Extensions/UIColor+Extensions.swift + - iOSClient/Extensions/UIImage+Extensions.swift + - iOSClient/Favorites/NCFavorite.swift + - iOSClient/FileViewInFolder/NCFileViewInFolder.swift + - iOSClient/Files/NCFiles.swift + - iOSClient/Login/NCAppConfigView.swift + - iOSClient/Login/NCLogin.swift + - iOSClient/Login/NCLoginWeb.swift + - iOSClient/Main/Account Request/NCAccountRequest.swift + - iOSClient/Main/AudioRecorder/NCAudioRecorderViewController.swift + - iOSClient/Main/Collection Common/NCCollectionViewCommon.swift + - iOSClient/Main/Collection Common/NCGridCell.swift + - iOSClient/Main/Collection Common/NCListCell.swift + - iOSClient/Main/Create cloud/NCCreateFormUploadAssets.swift + - iOSClient/Main/Create cloud/NCCreateFormUploadConflict.swift + - iOSClient/Main/Create cloud/NCCreateFormUploadConflictCell.swift + - iOSClient/Main/Create cloud/NCCreateFormUploadDocuments.swift + - iOSClient/Main/Create cloud/NCCreateFormUploadScanDocument.swift + - iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift + - iOSClient/Main/Create cloud/NCCreateMenuAdd.swift + - iOSClient/Main/NCFunctionCenter.swift + - iOSClient/Main/NCMainTabBar.swift + - iOSClient/Main/NCPickerViewController.swift + - iOSClient/Main/Section Header Footer/NCSectionHeaderFooter.swift + - iOSClient/Media/Cell/NCGridMediaCell.swift + - iOSClient/Media/NCMedia.swift + - iOSClient/Menu/AppDelegate+Menu.swift + - iOSClient/Menu/NCCollectionViewCommon+Menu.swift + - iOSClient/Menu/NCLoginWeb+Menu.swift + - iOSClient/Menu/NCMedia+Menu.swift + - iOSClient/Menu/NCSortMenu.swift + - iOSClient/Menu/NCViewer+Menu.swift + - iOSClient/More/NCMore.swift + - iOSClient/NCGlobal.swift + - iOSClient/Networking/NCAutoUpload.swift + - iOSClient/Networking/NCNetworking.swift + - iOSClient/Networking/NCNetworkingCheckRemoteUser.swift + - iOSClient/Networking/NCNetworkingChunkedUpload.swift + - iOSClient/Networking/NCNetworkingE2EE.swift + - iOSClient/Networking/NCNetworkingProcessUpload.swift + - iOSClient/Networking/NCOperationQueue.swift + - iOSClient/Networking/NCService.swift + - iOSClient/Notification/NCNotification.swift + - iOSClient/Offline/NCOffline.swift + - iOSClient/Recent/NCRecent.swift + - iOSClient/Rename file/NCRenameFile.swift + - iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift + - iOSClient/RichWorkspace/NCViewerRichWorkspace.swift + - iOSClient/ScanDocument/ScanCollectionView.swift + - iOSClient/Security/NCEndToEndMetadata.swift + - iOSClient/Security/NCViewCertificateDetails.swift + - iOSClient/Select/NCSelect.swift + - iOSClient/Settings/NCEndToEndInitialize.swift + - iOSClient/Settings/NCManageAutoUploadFileName.swift + - iOSClient/Share/NCShare.swift + - iOSClient/Share/NCShareCommentsCell.swift + - iOSClient/Share/NCShareCommon.swift + - iOSClient/Share/NCShareLinkCell.swift + - iOSClient/Share/NCShareLinkMenuView.swift + - iOSClient/Share/NCShareNetworking.swift + - iOSClient/Share/NCSharePaging.swift + - iOSClient/Share/NCShareQuickStatusMenu.swift + - iOSClient/Share/NCShareUserCell.swift + - iOSClient/Share/NCShareUserMenuView.swift + - iOSClient/Shares/NCShares.swift + - iOSClient/Transfers/NCTransferCell.swift + - iOSClient/Transfers/NCTransfers.swift + - iOSClient/Trash/Cell/NCTrashListCell.swift + - iOSClient/Trash/NCTrash.swift + - iOSClient/Trash/Section/NCTrashSectionHeaderFooter.swift + - iOSClient/UserStatus/NCUserStatus.swift + - iOSClient/Utility/NCAskAuthorization.swift + - iOSClient/Utility/NCContentPresenter.swift + - iOSClient/Utility/NCLivePhoto.swift + - iOSClient/Utility/NCPopupViewController.swift + - iOSClient/Utility/NCStoreReview.swift + - iOSClient/Utility/NCUtility.swift + - iOSClient/Utility/NCUtilityFileSystem.swift + - iOSClient/Viewer/NCViewer.swift + - iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayer.swift + - iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift + - iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift + - iOSClient/Viewer/NCViewerMedia/NCViewerMediaDetailView.swift + - iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.swift + - iOSClient/Viewer/NCViewerNextcloudText/NCViewerNextcloudText.swift + - iOSClient/Viewer/NCViewerPDF/NCViewerPDF.swift + - iOSClient/Viewer/NCViewerPDF/NCViewerPDFSearch.swift + - iOSClient/Viewer/NCViewerProviderContextMenu.swift + - iOSClient/Viewer/NCViewerQuickLook/NCViewerQuickLook.swift + - iOSClient/Viewer/NCViewerRichdocument/NCViewerRichdocument.swift + + +reporter: "xcode" diff --git a/File Provider Extension/FileProviderData.swift b/File Provider Extension/FileProviderData.swift index b968b3392..509c86d69 100644 --- a/File Provider Extension/FileProviderData.swift +++ b/File Provider Extension/FileProviderData.swift @@ -29,144 +29,144 @@ class fileProviderData: NSObject { let instance = fileProviderData() return instance }() - + var domain: NSFileProviderDomain? var fileProviderManager: NSFileProviderManager = NSFileProviderManager.default - + var account = "" var user = "" var userId = "" var accountUrlBase = "" var homeServerUrl = "" - + // Max item for page let itemForPage = 100 - + // Anchor var currentAnchor: UInt64 = 0 // Rank favorite var listFavoriteIdentifierRank: [String: NSNumber] = [:] - + // Item for signalEnumerator var fileProviderSignalDeleteContainerItemIdentifier: [NSFileProviderItemIdentifier: NSFileProviderItemIdentifier] = [:] var fileProviderSignalUpdateContainerItem: [NSFileProviderItemIdentifier: FileProviderItem] = [:] var fileProviderSignalDeleteWorkingSetItemIdentifier: [NSFileProviderItemIdentifier: NSFileProviderItemIdentifier] = [:] var fileProviderSignalUpdateWorkingSetItem: [NSFileProviderItemIdentifier: FileProviderItem] = [:] - + // Error enum FileProviderError: Error { case downloadError case uploadError } - + // MARK: - - + func setupAccount(domain: NSFileProviderDomain?, providerExtension: NSFileProviderExtension) -> tableAccount? { - + if CCUtility.getDisableFilesApp() || NCBrandOptions.shared.disable_openin_file { return nil } - + self.domain = domain if domain != nil { - if let fileProviderManager = NSFileProviderManager.init(for: domain!) { + if let fileProviderManager = NSFileProviderManager(for: domain!) { self.fileProviderManager = fileProviderManager } } - + // LOG if let pathDirectoryGroup = CCUtility.getDirectoryGroup()?.path { NCCommunicationCommon.shared.pathLog = pathDirectoryGroup let levelLog = CCUtility.getLogLevel() NCCommunicationCommon.shared.levelLog = levelLog - let version = NSString(format:NCBrandOptions.shared.textCopyrightNextcloudiOS as NSString, NCUtility.shared.getVersionApp()) as String + let version = NSString(format: NCBrandOptions.shared.textCopyrightNextcloudiOS as NSString, NCUtility.shared.getVersionApp()) as String NCCommunicationCommon.shared.writeLog("Start session with level \(levelLog) " + version + " (File Provider Extension)") } - + // NO DOMAIN -> Set default account if domain == nil { - + guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return nil } let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: activeAccount.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor) let webDav = NCUtilityFileSystem.shared.getWebDAV(account: activeAccount.account) - + account = activeAccount.account user = activeAccount.user userId = activeAccount.userId accountUrlBase = activeAccount.urlBase homeServerUrl = NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account) - + NCCommunicationCommon.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: CCUtility.getUserAgent(), webDav: webDav, nextcloudVersion: serverVersionMajor, delegate: NCNetworking.shared) NCNetworking.shared.delegate = providerExtension as? NCNetworkingDelegate - + return tableAccount.init(value: activeAccount) } - + // DOMAIN let accounts = NCManageDatabase.shared.getAllAccount() if accounts.count == 0 { return nil } - + for activeAccount in accounts { guard let url = NSURL(string: activeAccount.urlBase) else { continue } guard let host = url.host else { continue } let accountDomain = activeAccount.userId + " (" + host + ")" if accountDomain == domain!.identifier.rawValue { - + let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: activeAccount.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor) let webDav = NCUtilityFileSystem.shared.getWebDAV(account: activeAccount.account) - + account = activeAccount.account user = activeAccount.user userId = activeAccount.userId accountUrlBase = activeAccount.urlBase homeServerUrl = NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account) - - NCCommunicationCommon.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: CCUtility.getUserAgent(), webDav: webDav, nextcloudVersion: serverVersionMajor, delegate: NCNetworking.shared) + + NCCommunicationCommon.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: CCUtility.getUserAgent(), webDav: webDav, nextcloudVersion: serverVersionMajor, delegate: NCNetworking.shared) NCNetworking.shared.delegate = providerExtension as? NCNetworkingDelegate return tableAccount.init(value: activeAccount) } } - + return nil } - + // MARK: - @discardableResult func signalEnumerator(ocId: String, delete: Bool = false, update: Bool = false) -> FileProviderItem? { - + guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return nil } - + guard let parentItemIdentifier = fileProviderUtility.shared.getParentItemIdentifier(metadata: metadata) else { return nil } - + let item = FileProviderItem(metadata: metadata, parentItemIdentifier: parentItemIdentifier) - + if delete { fileProviderData.shared.fileProviderSignalDeleteContainerItemIdentifier[item.itemIdentifier] = item.itemIdentifier fileProviderData.shared.fileProviderSignalDeleteWorkingSetItemIdentifier[item.itemIdentifier] = item.itemIdentifier } - + if update { fileProviderData.shared.fileProviderSignalUpdateContainerItem[item.itemIdentifier] = item fileProviderData.shared.fileProviderSignalUpdateWorkingSetItem[item.itemIdentifier] = item } - + if !update && !delete { fileProviderData.shared.fileProviderSignalUpdateWorkingSetItem[item.itemIdentifier] = item } - + if update || delete { currentAnchor += 1 fileProviderManager.signalEnumerator(for: parentItemIdentifier) { _ in } } - + fileProviderManager.signalEnumerator(for: .workingSet) { _ in } - + return item } - + /* func updateFavoriteForWorkingSet() { diff --git a/File Provider Extension/FileProviderDomain.swift b/File Provider Extension/FileProviderDomain.swift index 3a8c79658..d2d38da47 100644 --- a/File Provider Extension/FileProviderDomain.swift +++ b/File Provider Extension/FileProviderDomain.swift @@ -24,19 +24,19 @@ import UIKit class FileProviderDomain: NSObject { - + func registerDomains() { - - NSFileProviderManager.getDomainsWithCompletionHandler { (fileProviderDomain, error) in - - var domains:[String] = [] + + NSFileProviderManager.getDomainsWithCompletionHandler { fileProviderDomain, error in + + var domains: [String] = [] let pathRelativeToDocumentStorage = NSFileProviderManager.default.documentStorageURL.absoluteString let accounts = NCManageDatabase.shared.getAllAccount() - + for domain in fileProviderDomain { domains.append(domain.identifier.rawValue) } - + // Delete for domain in domains { var domainFound = false @@ -51,14 +51,14 @@ class FileProviderDomain: NSObject { } if !domainFound { let domainRawValue = NSFileProviderDomain(identifier: NSFileProviderDomainIdentifier(rawValue: domain), displayName: domain, pathRelativeToDocumentStorage: pathRelativeToDocumentStorage) - NSFileProviderManager.remove(domainRawValue, completionHandler: { (error) in + NSFileProviderManager.remove(domainRawValue, completionHandler: { error in if error != nil { print("Error domain: \(domainRawValue) error: \(String(describing: error))") } }) } } - + // Add for account in accounts { var domainFound = false @@ -73,7 +73,7 @@ class FileProviderDomain: NSObject { } if !domainFound { let domainRawValue = NSFileProviderDomain(identifier: NSFileProviderDomainIdentifier(rawValue: accountDomain), displayName: accountDomain, pathRelativeToDocumentStorage: pathRelativeToDocumentStorage) - NSFileProviderManager.add(domainRawValue, completionHandler: { (error) in + NSFileProviderManager.add(domainRawValue, completionHandler: { error in if error != nil { print("Error domain: \(domainRawValue) error: \(String(describing: error))") } @@ -82,9 +82,9 @@ class FileProviderDomain: NSObject { } } } - + func removeAllDomains() { - - NSFileProviderManager.removeAllDomains { (_) in } + + NSFileProviderManager.removeAllDomains { _ in } } } diff --git a/File Provider Extension/FileProviderEnumerator.swift b/File Provider Extension/FileProviderEnumerator.swift index ed1cf1d80..5e06d2fca 100644 --- a/File Provider Extension/FileProviderEnumerator.swift +++ b/File Provider Extension/FileProviderEnumerator.swift @@ -26,60 +26,60 @@ import FileProvider import NCCommunication class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { - + var enumeratedItemIdentifier: NSFileProviderItemIdentifier var serverUrl: String? - + init(enumeratedItemIdentifier: NSFileProviderItemIdentifier) { - + self.enumeratedItemIdentifier = enumeratedItemIdentifier - + // Select ServerUrl - if (enumeratedItemIdentifier == .rootContainer) { + if enumeratedItemIdentifier == .rootContainer { serverUrl = fileProviderData.shared.homeServerUrl } else { - + let metadata = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(enumeratedItemIdentifier) - if metadata != nil { - if let directorySource = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata!.account, metadata!.serverUrl)) { + if metadata != nil { + if let directorySource = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata!.account, metadata!.serverUrl)) { serverUrl = directorySource.serverUrl + "/" + metadata!.fileName } } } - + super.init() } func invalidate() { - + } func enumerateItems(for observer: NSFileProviderEnumerationObserver, startingAt page: NSFileProviderPage) { - + var items: [NSFileProviderItemProtocol] = [] - + /*** WorkingSet ***/ if enumeratedItemIdentifier == .workingSet { - + var itemIdentifierMetadata: [NSFileProviderItemIdentifier: tableMetadata] = [:] - + // ***** Tags ***** let tags = NCManageDatabase.shared.getTags(predicate: NSPredicate(format: "account == %@", fileProviderData.shared.account)) for tag in tags { - + guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(tag.ocId) else { continue } fileProviderUtility.shared.createocIdentifierOnFileSystem(metadata: metadata) itemIdentifierMetadata[fileProviderUtility.shared.getItemIdentifier(metadata: metadata)] = metadata } - + // ***** Favorite ***** fileProviderData.shared.listFavoriteIdentifierRank = NCManageDatabase.shared.getTableMetadatasDirectoryFavoriteIdentifierRank(account: fileProviderData.shared.account) for (identifier, _) in fileProviderData.shared.listFavoriteIdentifierRank { - + guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(identifier) else { continue } itemIdentifierMetadata[fileProviderUtility.shared.getItemIdentifier(metadata: metadata)] = metadata } - + // create items for (_, metadata) in itemIdentifierMetadata { let parentItemIdentifier = fileProviderUtility.shared.getParentItemIdentifier(metadata: metadata) @@ -88,38 +88,38 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { items.append(item) } } - + observer.didEnumerate(items) observer.finishEnumerating(upTo: nil) - + } else { - + /*** ServerUrl ***/ - + guard let serverUrl = serverUrl else { observer.finishEnumerating(upTo: nil) return } - - if (page == NSFileProviderPage.initialPageSortedByDate as NSFileProviderPage || page == NSFileProviderPage.initialPageSortedByName as NSFileProviderPage) { - - self.readFileOrFolder(serverUrl: serverUrl) { (metadatas) in + + if page == NSFileProviderPage.initialPageSortedByDate as NSFileProviderPage || page == NSFileProviderPage.initialPageSortedByName as NSFileProviderPage { + + self.readFileOrFolder(serverUrl: serverUrl) { metadatas in self.completeObserver(observer, numPage: 1, metadatas: metadatas) } - + } else { - + let numPage = Int(String(data: page.rawValue, encoding: .utf8)!)! completeObserver(observer, numPage: numPage, metadatas: nil) } } } - + func enumerateChanges(for observer: NSFileProviderChangeObserver, from anchor: NSFileProviderSyncAnchor) { - + var itemsDelete: [NSFileProviderItemIdentifier] = [] var itemsUpdate: [FileProviderItem] = [] - + // Report the deleted items // if self.enumeratedItemIdentifier == .workingSet { @@ -133,7 +133,7 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { } fileProviderData.shared.fileProviderSignalDeleteContainerItemIdentifier.removeAll() } - + // Report the updated items // if self.enumeratedItemIdentifier == .workingSet { @@ -147,36 +147,36 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { } fileProviderData.shared.fileProviderSignalUpdateContainerItem.removeAll() } - + observer.didDeleteItems(withIdentifiers: itemsDelete) observer.didUpdate(itemsUpdate) - + let data = "\(fileProviderData.shared.currentAnchor)".data(using: .utf8) observer.finishEnumeratingChanges(upTo: NSFileProviderSyncAnchor(data!), moreComing: false) } - + func currentSyncAnchor(completionHandler: @escaping (NSFileProviderSyncAnchor?) -> Void) { let data = "\(fileProviderData.shared.currentAnchor)".data(using: .utf8) completionHandler(NSFileProviderSyncAnchor(data!)) } - + // -------------------------------------------------------------------------------------------- - // MARK: - User Function + Network + // MARK: - User Function + Network // -------------------------------------------------------------------------------------------- func completeObserver(_ observer: NSFileProviderEnumerationObserver, numPage: Int, metadatas: [tableMetadata]?) { - + var numPage = numPage var items: [NSFileProviderItemProtocol] = [] - if (metadatas != nil) { - + if metadatas != nil { + for metadata in metadatas! { - + if metadata.e2eEncrypted || (metadata.session != "" && metadata.session != NCNetworking.shared.sessionIdentifierBackgroundExtension) { continue } - + fileProviderUtility.shared.createocIdentifierOnFileSystem(metadata: metadata) - + let parentItemIdentifier = fileProviderUtility.shared.getParentItemIdentifier(metadata: metadata) if parentItemIdentifier != nil { let item = FileProviderItem(metadata: metadata, parentItemIdentifier: parentItemIdentifier!) @@ -185,8 +185,8 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { } observer.didEnumerate(items) } - - if (items.count == fileProviderData.shared.itemForPage) { + + if items.count == fileProviderData.shared.itemForPage { numPage += 1 let providerPage = NSFileProviderPage("\(numPage)".data(using: .utf8)!) observer.finishEnumerating(upTo: providerPage) @@ -194,24 +194,24 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { observer.finishEnumerating(upTo: nil) } } - + func readFileOrFolder(serverUrl: String, completionHandler: @escaping (_ metadatas: [tableMetadata]?) -> Void) { - + var directoryEtag: String? - + if let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", fileProviderData.shared.account, serverUrl)) { directoryEtag = tableDirectory.etag } - - NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles()) { (account, files, responseData, errorCode, errorDescription) in - + + NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles()) { account, files, _, errorCode, _ in + if directoryEtag != files.first?.etag { - - NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "1", showHiddenFiles: CCUtility.getShowHiddenFiles()) { (account, files, responseData, errorCode, errorDescription) in - + + NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "1", showHiddenFiles: CCUtility.getShowHiddenFiles()) { account, files, _, errorCode, _ in + if errorCode == 0 { DispatchQueue.global().async { - NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: true, account: account) { (metadataFolder, metadatasFolder, metadatas) in + NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: true, account: account) { _, metadatasFolder, metadatas in let metadatasResult = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND status == %d", account, serverUrl, NCGlobal.shared.metadataStatusNormal)) NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult) for metadata in metadatasFolder { diff --git a/File Provider Extension/FileProviderExtension+Actions.swift b/File Provider Extension/FileProviderExtension+Actions.swift index f10daabb2..b45f61009 100644 --- a/File Provider Extension/FileProviderExtension+Actions.swift +++ b/File Provider Extension/FileProviderExtension+Actions.swift @@ -28,85 +28,85 @@ import NCCommunication extension FileProviderExtension { override func createDirectory(withName directoryName: String, inParentItemIdentifier parentItemIdentifier: NSFileProviderItemIdentifier, completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) { - + guard let tableDirectory = fileProviderUtility.shared.getTableDirectoryFromParentItemIdentifier(parentItemIdentifier, account: fileProviderData.shared.account, homeServerUrl: fileProviderData.shared.homeServerUrl) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + let directoryName = NCUtilityFileSystem.shared.createFileName(directoryName, serverUrl: tableDirectory.serverUrl, account: fileProviderData.shared.account) let serverUrlFileName = tableDirectory.serverUrl + "/" + directoryName - - NCCommunication.shared.createFolder(serverUrlFileName) { (account, ocId, date, errorCode, errorDescription) in - + + NCCommunication.shared.createFolder(serverUrlFileName) { account, ocId, _, errorCode, _ in + if errorCode == 0 { - - NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles()) { (account, files, responseData, errorCode, errorDescription) in - + + NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles()) { account, files, _, errorCode, _ in + if errorCode == 0 && files.count > 0 { - + let file = files.first! let metadata = NCManageDatabase.shared.convertNCFileToMetadata(file, isEncrypted: false, account: fileProviderData.shared.account) - + NCManageDatabase.shared.addDirectory(encrypted: false, favorite: false, ocId: ocId!, fileId: metadata.fileId, etag: metadata.etag, permissions: metadata.permissions, serverUrl: serverUrlFileName, account: metadata.account) NCManageDatabase.shared.addMetadata(metadata) - + guard let metadataInsert = NCManageDatabase.shared.getMetadataFromOcId(ocId!) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + guard let parentItemIdentifier = fileProviderUtility.shared.getParentItemIdentifier(metadata: metadataInsert) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + let item = FileProviderItem(metadata: metadataInsert, parentItemIdentifier: parentItemIdentifier) completionHandler(item, nil) - + } else { completionHandler(nil, NSFileProviderError(.serverUnreachable)) } } - + } else { completionHandler(nil, NSFileProviderError(.serverUnreachable)) } } } - + override func deleteItem(withIdentifier itemIdentifier: NSFileProviderItemIdentifier, completionHandler: @escaping (Error?) -> Void) { - + guard let metadata = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(itemIdentifier) else { completionHandler(NSFileProviderError(.noSuchItem)) return } - + let ocId = metadata.ocId let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName let isDirectory = metadata.directory - let serverUrl = metadata.serverUrl; - let fileName = metadata.fileName; - - NCCommunication.shared.deleteFileOrFolder(serverUrlFileName) { (account, errorCode, errorDescription) in - - if errorCode == 0 { //|| error == kOCErrorServerPathNotFound { - + let serverUrl = metadata.serverUrl + let fileName = metadata.fileName + + NCCommunication.shared.deleteFileOrFolder(serverUrlFileName) { account, errorCode, _ in + + if errorCode == 0 { // || error == kOCErrorServerPathNotFound { + let fileNamePath = CCUtility.getDirectoryProviderStorageOcId(itemIdentifier.rawValue)! do { try fileProviderUtility.shared.fileManager.removeItem(atPath: fileNamePath) } catch let error { print("error: \(error)") } - + if isDirectory { let dirForDelete = CCUtility.stringAppendServerUrl(serverUrl, addFileName: fileName) NCManageDatabase.shared.deleteDirectoryAndSubDirectory(serverUrl: dirForDelete!, account: account) } - + NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocId)) NCManageDatabase.shared.deleteLocalFile(predicate: NSPredicate(format: "ocId == %@", ocId)) - + completionHandler(nil) } else { @@ -114,126 +114,126 @@ extension FileProviderExtension { } } } - + override func reparentItem(withIdentifier itemIdentifier: NSFileProviderItemIdentifier, toParentItemWithIdentifier parentItemIdentifier: NSFileProviderItemIdentifier, newName: String?, completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) { - + guard let itemFrom = try? item(for: itemIdentifier) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + guard let metadataFrom = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(itemIdentifier) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + let ocIdFrom = metadataFrom.ocId let serverUrlFrom = metadataFrom.serverUrl let fileNameFrom = serverUrlFrom + "/" + itemFrom.filename - + guard let tableDirectoryTo = fileProviderUtility.shared.getTableDirectoryFromParentItemIdentifier(parentItemIdentifier, account: fileProviderData.shared.account, homeServerUrl: fileProviderData.shared.homeServerUrl) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } let serverUrlTo = tableDirectoryTo.serverUrl let fileNameTo = serverUrlTo + "/" + itemFrom.filename - - NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: fileNameFrom, serverUrlFileNameDestination: fileNameTo, overwrite: false) { (account, errorCode, errorDescription) in - + + NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: fileNameFrom, serverUrlFileNameDestination: fileNameTo, overwrite: false) { account, errorCode, _ in + if errorCode == 0 { - + if metadataFrom.directory { NCManageDatabase.shared.deleteDirectoryAndSubDirectory(serverUrl: serverUrlFrom, account: account) - NCManageDatabase.shared.renameDirectory(ocId: ocIdFrom, serverUrl: serverUrlTo) + NCManageDatabase.shared.renameDirectory(ocId: ocIdFrom, serverUrl: serverUrlTo) } - + NCManageDatabase.shared.moveMetadata(ocId: ocIdFrom, serverUrlTo: serverUrlTo) - + guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocIdFrom) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + let item = FileProviderItem(metadata: metadata, parentItemIdentifier: parentItemIdentifier) completionHandler(item, nil) - + } else { completionHandler(nil, NSFileProviderError(.serverUnreachable)) } } } - + override func renameItem(withIdentifier itemIdentifier: NSFileProviderItemIdentifier, toName itemName: String, completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) { - + guard let metadata = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(itemIdentifier) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + guard let directoryTable = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + let fileNameFrom = metadata.fileNameView let fileNamePathFrom = metadata.serverUrl + "/" + fileNameFrom let fileNamePathTo = metadata.serverUrl + "/" + itemName let ocId = metadata.ocId - - NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: fileNamePathFrom, serverUrlFileNameDestination: fileNamePathTo, overwrite: false) { (account, errorCode, errorDescription) in - + + NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: fileNamePathFrom, serverUrlFileNameDestination: fileNamePathTo, overwrite: false) { account, errorCode, _ in + if errorCode == 0 { - + // Rename metadata NCManageDatabase.shared.renameMetadata(fileNameTo: itemName, ocId: ocId) - + guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + if metadata.directory { - + NCManageDatabase.shared.setDirectory(serverUrl: fileNamePathFrom, serverUrlTo: fileNamePathTo, etag: nil, ocId: nil, fileId: nil, encrypted: directoryTable.e2eEncrypted, richWorkspace: nil, account: account) - + } else { - + let itemIdentifier = fileProviderUtility.shared.getItemIdentifier(metadata: metadata) - + // rename file _ = fileProviderUtility.shared.moveFile(CCUtility.getDirectoryProviderStorageOcId(itemIdentifier.rawValue, fileNameView: fileNameFrom), toPath: CCUtility.getDirectoryProviderStorageOcId(itemIdentifier.rawValue, fileNameView: itemName)) - + _ = fileProviderUtility.shared.moveFile(CCUtility.getDirectoryProviderStoragePreviewOcId(itemIdentifier.rawValue, etag: metadata.etag), toPath: CCUtility.getDirectoryProviderStoragePreviewOcId(itemIdentifier.rawValue, etag: metadata.etag)) - + _ = fileProviderUtility.shared.moveFile(CCUtility.getDirectoryProviderStorageIconOcId(itemIdentifier.rawValue, etag: metadata.etag), toPath: CCUtility.getDirectoryProviderStorageIconOcId(itemIdentifier.rawValue, etag: metadata.etag)) - + NCManageDatabase.shared.setLocalFile(ocId: ocId, fileName: itemName, etag: nil) } - + guard let parentItemIdentifier = fileProviderUtility.shared.getParentItemIdentifier(metadata: metadata) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + let item = FileProviderItem(metadata: tableMetadata.init(value: metadata), parentItemIdentifier: parentItemIdentifier) completionHandler(item, nil) - + } else { completionHandler(nil, NSFileProviderError(.serverUnreachable)) } } } - + override func setFavoriteRank(_ favoriteRank: NSNumber?, forItemIdentifier itemIdentifier: NSFileProviderItemIdentifier, completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) { - + guard let metadata = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(itemIdentifier) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + var favorite = false let ocId = metadata.ocId - + if favoriteRank == nil { fileProviderData.shared.listFavoriteIdentifierRank.removeValue(forKey: itemIdentifier.rawValue) } else { @@ -243,72 +243,72 @@ extension FileProviderExtension { } favorite = true } - + if (favorite == true && metadata.favorite == false) || (favorite == false && metadata.favorite == true) { let fileNamePath = CCUtility.returnFileNamePath(fromFileName: metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, account: metadata.account)! - - NCCommunication.shared.setFavorite(fileName: fileNamePath, favorite: favorite) { (account, errorCode, errorDescription) in - + + NCCommunication.shared.setFavorite(fileName: fileNamePath, favorite: favorite) { _, errorCode, _ in + if errorCode == 0 { - + guard let metadataTemp = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } let metadata = tableMetadata.init(value: metadataTemp) - + // Change DB metadata.favorite = favorite NCManageDatabase.shared.addMetadata(metadata) - + let item = fileProviderData.shared.signalEnumerator(ocId: metadata.ocId) completionHandler(item, nil) - + } else { - + guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + // Errore, remove from listFavoriteIdentifierRank fileProviderData.shared.listFavoriteIdentifierRank.removeValue(forKey: itemIdentifier.rawValue) - + let item = fileProviderData.shared.signalEnumerator(ocId: metadata.ocId) completionHandler(item, NSFileProviderError(.serverUnreachable)) } } } } - + override func setTagData(_ tagData: Data?, forItemIdentifier itemIdentifier: NSFileProviderItemIdentifier, completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) { - + guard let metadataForTag = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(itemIdentifier) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } let ocId = metadataForTag.ocId let account = metadataForTag.account - + // Add, Remove (nil) NCManageDatabase.shared.addTag(ocId, tagIOS: tagData, account: account) - + let item = fileProviderData.shared.signalEnumerator(ocId: ocId) completionHandler(item, nil) } - + override func setLastUsedDate(_ lastUsedDate: Date?, forItemIdentifier itemIdentifier: NSFileProviderItemIdentifier, completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) { - + guard let metadata = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(itemIdentifier) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + guard let parentItemIdentifier = fileProviderUtility.shared.getParentItemIdentifier(metadata: metadata) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + let item = FileProviderItem(metadata: metadata, parentItemIdentifier: parentItemIdentifier) completionHandler(item, nil) } diff --git a/File Provider Extension/FileProviderExtension+Thumbnail.swift b/File Provider Extension/FileProviderExtension+Thumbnail.swift index 92596787a..2e5babea5 100644 --- a/File Provider Extension/FileProviderExtension+Thumbnail.swift +++ b/File Provider Extension/FileProviderExtension+Thumbnail.swift @@ -28,46 +28,46 @@ import NCCommunication extension FileProviderExtension { override func fetchThumbnails(for itemIdentifiers: [NSFileProviderItemIdentifier], requestedSize size: CGSize, perThumbnailCompletionHandler: @escaping (NSFileProviderItemIdentifier, Data?, Error?) -> Void, completionHandler: @escaping (Error?) -> Void) -> Progress { - + let progress = Progress(totalUnitCount: Int64(itemIdentifiers.count)) var counterProgress: Int64 = 0 - + for itemIdentifier in itemIdentifiers { - + guard let metadata = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(itemIdentifier) else { counterProgress += 1 - if (counterProgress == progress.totalUnitCount) { completionHandler(nil) } + if counterProgress == progress.totalUnitCount { completionHandler(nil) } continue } - - if (metadata.hasPreview) { - + + if metadata.hasPreview { + let fileNamePath = CCUtility.returnFileNamePath(fromFileName: metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, account: metadata.account)! let fileNameIconLocalPath = CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)! - - NCCommunication.shared.getPreview(fileNamePath: fileNamePath, widthPreview: NCGlobal.shared.sizeIcon, heightPreview: NCGlobal.shared.sizeIcon) { (account, data, errorCode, errorDescription) in + + NCCommunication.shared.getPreview(fileNamePath: fileNamePath, widthPreview: NCGlobal.shared.sizeIcon, heightPreview: NCGlobal.shared.sizeIcon) { _, data, errorCode, _ in if errorCode == 0 && data != nil { do { - try data!.write(to: URL.init(fileURLWithPath: fileNameIconLocalPath), options: .atomic) + try data!.write(to: URL(fileURLWithPath: fileNameIconLocalPath), options: .atomic) } catch { } perThumbnailCompletionHandler(itemIdentifier, data, nil) } else { perThumbnailCompletionHandler(itemIdentifier, nil, NSFileProviderError(.serverUnreachable)) } counterProgress += 1 - if (counterProgress == progress.totalUnitCount) { + if counterProgress == progress.totalUnitCount { completionHandler(nil) } } } else { counterProgress += 1 - if (counterProgress == progress.totalUnitCount) { + if counterProgress == progress.totalUnitCount { completionHandler(nil) } } } - + return progress } - + } diff --git a/File Provider Extension/FileProviderExtension.swift b/File Provider Extension/FileProviderExtension.swift index 6c9e4968a..16c91c36c 100644 --- a/File Provider Extension/FileProviderExtension.swift +++ b/File Provider Extension/FileProviderExtension.swift @@ -52,67 +52,67 @@ import Alamofire -------------------------------------------------------------------------------------------------------------------------------------------- */ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate { - + var outstandingSessionTasks: [URL: URLSessionTask] = [:] var outstandingOcIdTemp: [String: String] = [:] - + override init() { super.init() - + // Create directory File Provider Storage CCUtility.getDirectoryProviderStorage() // Configure URLSession _ = NCNetworking.shared.sessionManagerBackgroundExtension } - + deinit { print("") } - + // MARK: - Enumeration - + override func enumerator(for containerItemIdentifier: NSFileProviderItemIdentifier) throws -> NSFileProviderEnumerator { - - var maybeEnumerator: NSFileProviderEnumerator? = nil - - if (containerItemIdentifier != NSFileProviderItemIdentifier.workingSet) { + + var maybeEnumerator: NSFileProviderEnumerator? + + if containerItemIdentifier != NSFileProviderItemIdentifier.workingSet { if fileProviderData.shared.setupAccount(domain: domain, providerExtension: self) == nil { - throw NSError(domain: NSFileProviderErrorDomain, code: NSFileProviderError.notAuthenticated.rawValue, userInfo:[:]) + throw NSError(domain: NSFileProviderErrorDomain, code: NSFileProviderError.notAuthenticated.rawValue, userInfo: [:]) } } - - if (containerItemIdentifier == NSFileProviderItemIdentifier.rootContainer) { + + if containerItemIdentifier == NSFileProviderItemIdentifier.rootContainer { maybeEnumerator = FileProviderEnumerator(enumeratedItemIdentifier: containerItemIdentifier) - } else if (containerItemIdentifier == NSFileProviderItemIdentifier.workingSet) { + } else if containerItemIdentifier == NSFileProviderItemIdentifier.workingSet { maybeEnumerator = FileProviderEnumerator(enumeratedItemIdentifier: containerItemIdentifier) } else { // determine if the item is a directory or a file // - for a directory, instantiate an enumerator of its subitems // - for a file, instantiate an enumerator that observes changes to the file let item = try self.item(for: containerItemIdentifier) - + if item.typeIdentifier == kUTTypeFolder as String { maybeEnumerator = FileProviderEnumerator(enumeratedItemIdentifier: containerItemIdentifier) } else { maybeEnumerator = FileProviderEnumerator(enumeratedItemIdentifier: containerItemIdentifier) } } - + guard let enumerator = maybeEnumerator else { - throw NSError(domain: NSCocoaErrorDomain, code: NSFeatureUnsupportedError, userInfo:[:]) + throw NSError(domain: NSCocoaErrorDomain, code: NSFeatureUnsupportedError, userInfo: [:]) } - + return enumerator } - + // MARK: - Item override func item(for identifier: NSFileProviderItemIdentifier) throws -> NSFileProviderItem { - + if identifier == .rootContainer { - + let metadata = tableMetadata() - + metadata.account = fileProviderData.shared.account metadata.directory = true metadata.ocId = NSFileProviderItemIdentifier.rootContainer.rawValue @@ -120,11 +120,11 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate { metadata.fileNameView = "root" metadata.serverUrl = fileProviderData.shared.homeServerUrl metadata.classFile = NCCommunicationCommon.typeClassFile.directory.rawValue - + return FileProviderItem(metadata: metadata, parentItemIdentifier: NSFileProviderItemIdentifier(NSFileProviderItemIdentifier.rootContainer.rawValue)) - + } else { - + guard let metadata = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(identifier) else { throw NSFileProviderError(.noSuchItem) } @@ -135,46 +135,46 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate { return item } } - + override func urlForItem(withPersistentIdentifier identifier: NSFileProviderItemIdentifier) -> URL? { - + // resolve the given identifier to a file on disk guard let item = try? item(for: identifier) else { return nil } - + var url = fileProviderData.shared.fileProviderManager.documentStorageURL.appendingPathComponent(identifier.rawValue, isDirectory: true) - + // (fix copy/paste directory -> isDirectory = false) - url = url.appendingPathComponent(item.filename, isDirectory:false) - + url = url.appendingPathComponent(item.filename, isDirectory: false) + return url } - + override func persistentIdentifierForItem(at url: URL) -> NSFileProviderItemIdentifier? { - + // resolve the given URL to a persistent identifier using a database let pathComponents = url.pathComponents - + // exploit the fact that the path structure has been defined as // <base storage directory>/<item identifier>/<item file name> above assert(pathComponents.count > 2) - + let itemIdentifier = NSFileProviderItemIdentifier(pathComponents[pathComponents.count - 2]) return itemIdentifier } - + override func providePlaceholder(at url: URL, completionHandler: @escaping (Error?) -> Void) { - + guard let identifier = persistentIdentifierForItem(at: url) else { completionHandler(NSFileProviderError(.noSuchItem)) return } - + do { let fileProviderItem = try item(for: identifier) let placeholderURL = NSFileProviderManager.placeholderURL(for: url) - try NSFileProviderManager.writePlaceholder(at: placeholderURL,withMetadata: fileProviderItem) + try NSFileProviderManager.writePlaceholder(at: placeholderURL, withMetadata: fileProviderItem) completionHandler(nil) } catch { completionHandler(error) @@ -182,89 +182,89 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate { } override func startProvidingItem(at url: URL, completionHandler: @escaping ((_ error: Error?) -> Void)) { - + let pathComponents = url.pathComponents let identifier = NSFileProviderItemIdentifier(pathComponents[pathComponents.count - 2]) - + if let _ = outstandingSessionTasks[url] { completionHandler(nil) return } - + guard let metadata = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(identifier) else { completionHandler(NSFileProviderError(.noSuchItem)) return } - + let tableLocalFile = NCManageDatabase.shared.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) - if tableLocalFile != nil && CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) && tableLocalFile?.etag == metadata.etag { + if tableLocalFile != nil && CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) && tableLocalFile?.etag == metadata.etag { completionHandler(nil) return } - + let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileName)! - + // Update status NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusDownloading) fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, update: true) - - NCCommunication.shared.download(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, requestHandler: { (request) in - - }, taskHandler: { (task) in - + + NCCommunication.shared.download(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, requestHandler: { _ in + + }, taskHandler: { task in + self.outstandingSessionTasks[url] = task - fileProviderData.shared.fileProviderManager.register(task, forItemWithIdentifier: NSFileProviderItemIdentifier(identifier.rawValue)) { (error) in } - - }, progressHandler: { (_) in - - }) { (account, etag, date, length, allHeaderFields, error, errorCode, errorDescription) in - + fileProviderData.shared.fileProviderManager.register(task, forItemWithIdentifier: NSFileProviderItemIdentifier(identifier.rawValue)) { _ in } + + }, progressHandler: { _ in + + }) { _, etag, date, _, _, _, errorCode, errorDescription in + self.outstandingSessionTasks.removeValue(forKey: url) guard var metadata = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(identifier) else { completionHandler(NSFileProviderError(.noSuchItem)) return } metadata = tableMetadata.init(value: metadata) - - if errorCode == 0 { - + + if errorCode == 0 { + metadata.status = NCGlobal.shared.metadataStatusNormal metadata.date = date ?? NSDate() metadata.etag = etag ?? "" - + NCManageDatabase.shared.addLocalFile(metadata: metadata) NCManageDatabase.shared.addMetadata(metadata) - + completionHandler(nil) - + } else if errorCode == 200 { - + NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusNormal) - + completionHandler(nil) } else { - + metadata.status = NCGlobal.shared.metadataStatusDownloadError metadata.sessionError = errorDescription NCManageDatabase.shared.addMetadata(metadata) completionHandler(NSFileProviderError(.noSuchItem)) } - + fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, update: true) } } - + override func itemChanged(at url: URL) { - + let pathComponents = url.pathComponents assert(pathComponents.count > 2) let itemIdentifier = NSFileProviderItemIdentifier(pathComponents[pathComponents.count - 2]) let fileName = pathComponents[pathComponents.count - 1] var ocId = itemIdentifier.rawValue - + // Temp ocId ? if outstandingOcIdTemp[ocId] != nil && outstandingOcIdTemp[ocId] != ocId { ocId = outstandingOcIdTemp[ocId]! @@ -276,17 +276,17 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate { let serverUrlFileName = metadata.serverUrl + "/" + fileName let fileNameLocalPath = url.path - + if let task = NCCommunicationBackground.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: nil, dateModificationFile: nil, description: metadata.ocId, session: NCNetworking.shared.sessionManagerBackgroundExtension) { - - fileProviderData.shared.fileProviderManager.register(task, forItemWithIdentifier: NSFileProviderItemIdentifier(metadata.fileId)) { (error) in } + + fileProviderData.shared.fileProviderManager.register(task, forItemWithIdentifier: NSFileProviderItemIdentifier(metadata.fileId)) { _ in } } } - + override func stopProvidingItem(at url: URL) { - + let fileHasLocalChanges = false - + if !fileHasLocalChanges { // remove the existing file to free up space do { @@ -294,36 +294,36 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate { } catch let error { print("error: \(error)") } - + // write out a placeholder to facilitate future property lookups - self.providePlaceholder(at: url, completionHandler: { error in + self.providePlaceholder(at: url, completionHandler: { _ in // handle any error, do any necessary cleanup }) } - + // Download task if let downloadTask = outstandingSessionTasks[url] { downloadTask.cancel() outstandingSessionTasks.removeValue(forKey: url) } } - + override func importDocument(at fileURL: URL, toParentItemIdentifier parentItemIdentifier: NSFileProviderItemIdentifier, completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) { - + DispatchQueue.main.async { - + autoreleasepool { - + var size = 0 as Int64 var error: NSError? - + guard let tableDirectory = fileProviderUtility.shared.getTableDirectoryFromParentItemIdentifier(parentItemIdentifier, account: fileProviderData.shared.account, homeServerUrl: fileProviderData.shared.homeServerUrl) else { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + _ = fileURL.startAccessingSecurityScopedResource() - + // typefile directory ? (NOT PERMITTED) do { let attributes = try fileProviderUtility.shared.fileManager.attributesOfItem(atPath: fileURL.path) @@ -337,60 +337,60 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate { completionHandler(nil, NSFileProviderError(.noSuchItem)) return } - + let fileName = NCUtilityFileSystem.shared.createFileName(fileURL.lastPathComponent, serverUrl: tableDirectory.serverUrl, account: fileProviderData.shared.account) let ocIdTemp = NSUUID().uuidString.lowercased() - - NSFileCoordinator().coordinate(readingItemAt: fileURL, options: .withoutChanges, error: &error) { (url) in + + NSFileCoordinator().coordinate(readingItemAt: fileURL, options: .withoutChanges, error: &error) { url in _ = fileProviderUtility.shared.copyFile(url.path, toPath: CCUtility.getDirectoryProviderStorageOcId(ocIdTemp, fileNameView: fileName)) } - + 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: "", livePhoto: false) metadata.session = NCNetworking.shared.sessionIdentifierBackgroundExtension metadata.size = size metadata.status = NCGlobal.shared.metadataStatusUploading - + NCManageDatabase.shared.addMetadata(metadata) - + let serverUrlFileName = tableDirectory.serverUrl + "/" + fileName let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(ocIdTemp, fileNameView: fileName)! - + if let task = NCCommunicationBackground.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: nil, dateModificationFile: nil, description: ocIdTemp, session: NCNetworking.shared.sessionManagerBackgroundExtension) { - + self.outstandingSessionTasks[URL(fileURLWithPath: fileNameLocalPath)] = task as URLSessionTask - - fileProviderData.shared.fileProviderManager.register(task, forItemWithIdentifier: NSFileProviderItemIdentifier(ocIdTemp)) { (error) in } + + fileProviderData.shared.fileProviderManager.register(task, forItemWithIdentifier: NSFileProviderItemIdentifier(ocIdTemp)) { _ in } } - + let item = FileProviderItem(metadata: tableMetadata.init(value: metadata), parentItemIdentifier: parentItemIdentifier) - + completionHandler(item, nil) } } } - + func uploadComplete(fileName: String, serverUrl: String, ocId: String?, etag: String?, date: NSDate?, size: Int64, description: String?, task: URLSessionTask, errorCode: Int, errorDescription: String) { - + guard let ocIdTemp = description else { return } guard let metadataTemp = NCManageDatabase.shared.getMetadataFromOcId(ocIdTemp) else { return } let metadata = tableMetadata.init(value: metadataTemp) - + let url = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(ocIdTemp, fileNameView: fileName)) DispatchQueue.main.asyncAfter(deadline: .now() + 1) { self.outstandingSessionTasks.removeValue(forKey: url) } outstandingOcIdTemp[ocIdTemp] = ocId - + if errorCode == 0 { - + // New file if ocId != ocIdTemp { // Signal update fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, delete: true) } - + metadata.fileName = fileName metadata.serverUrl = serverUrl if let etag = etag { metadata.etag = etag } @@ -400,32 +400,29 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate { metadata.session = "" metadata.size = size metadata.status = NCGlobal.shared.metadataStatusNormal - + NCManageDatabase.shared.addMetadata(metadata) NCManageDatabase.shared.addLocalFile(metadata: metadata) - + // New file if ocId != ocIdTemp { - + NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp)) - + // File system let atPath = CCUtility.getDirectoryProviderStorageOcId(ocIdTemp) let toPath = CCUtility.getDirectoryProviderStorageOcId(ocId) CCUtility.copyFile(atPath: atPath, toPath: toPath) } - + fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, update: true) - + } else { - + NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp)) - + fileProviderData.shared.signalEnumerator(ocId: ocIdTemp, delete: true) } } } - - - diff --git a/File Provider Extension/FileProviderItem.swift b/File Provider Extension/FileProviderItem.swift index 7522aa2aa..6b872dc2f 100644 --- a/File Provider Extension/FileProviderItem.swift +++ b/File Provider Extension/FileProviderItem.swift @@ -33,44 +33,44 @@ class FileProviderItem: NSObject, NSFileProviderItem { var itemIdentifier: NSFileProviderItemIdentifier { return fileProviderUtility.shared.getItemIdentifier(metadata: metadata) } - + var filename: String { return metadata.fileNameView } - + var documentSize: NSNumber? { return NSNumber(value: metadata.size) } - + var typeIdentifier: String { let results = NCCommunicationCommon.shared.getInternalType(fileName: metadata.fileNameView, mimeType: "", directory: metadata.directory) return results.typeIdentifier } - + var contentModificationDate: Date? { return metadata.date as Date } - + var creationDate: Date? { return metadata.creationDate as Date } - + var lastUsedDate: Date? { return metadata.date as Date } var capabilities: NSFileProviderItemCapabilities { - if (metadata.directory) { + if metadata.directory { return [ .allowsAddingSubItems, .allowsContentEnumerating, .allowsReading, .allowsDeleting, .allowsRenaming ] } else { return [ .allowsWriting, .allowsReading, .allowsDeleting, .allowsRenaming, .allowsReparenting ] } } - + var isTrashed: Bool { return false } - + var childItemCount: NSNumber? { return nil } @@ -78,7 +78,7 @@ class FileProviderItem: NSObject, NSFileProviderItem { var versionIdentifier: Data? { return metadata.etag.data(using: .utf8) } - + var tagData: Data? { if let tableTag = NCManageDatabase.shared.getTag(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) { return tableTag.tagIOS @@ -86,7 +86,7 @@ class FileProviderItem: NSObject, NSFileProviderItem { return nil } } - + var favoriteRank: NSNumber? { if let rank = fileProviderData.shared.listFavoriteIdentifierRank[metadata.ocId] { return rank @@ -98,7 +98,7 @@ class FileProviderItem: NSObject, NSFileProviderItem { var isMostRecentVersionDownloaded: Bool { return true } - + var isDownloaded: Bool { if metadata.directory { return true @@ -109,7 +109,7 @@ class FileProviderItem: NSObject, NSFileProviderItem { return false } } - + var isDownloading: Bool { if metadata.status == NCGlobal.shared.metadataStatusDownloading { return true @@ -117,7 +117,7 @@ class FileProviderItem: NSObject, NSFileProviderItem { return false } } - + var downloadingError: Error? { if metadata.status == NCGlobal.shared.metadataStatusDownloadError { return fileProviderData.FileProviderError.downloadError @@ -133,7 +133,7 @@ class FileProviderItem: NSObject, NSFileProviderItem { return false } } - + var isUploading: Bool { if metadata.status == NCGlobal.shared.metadataStatusUploading { return true @@ -141,7 +141,7 @@ class FileProviderItem: NSObject, NSFileProviderItem { return false } } - + var uploadingError: Error? { if metadata.status == NCGlobal.shared.metadataStatusUploadError { return fileProviderData.FileProviderError.uploadError diff --git a/File Provider Extension/FileProviderUtility.swift b/File Provider Extension/FileProviderUtility.swift index f9bd5077b..bfa113b26 100644 --- a/File Provider Extension/FileProviderUtility.swift +++ b/File Provider Extension/FileProviderUtility.swift @@ -28,41 +28,41 @@ class fileProviderUtility: NSObject { let instance = fileProviderUtility() return instance }() - + var fileManager = FileManager() - + func getAccountFromItemIdentifier(_ itemIdentifier: NSFileProviderItemIdentifier) -> String? { - + let ocId = itemIdentifier.rawValue return NCManageDatabase.shared.getMetadataFromOcId(ocId)?.account } - + func getTableMetadataFromItemIdentifier(_ itemIdentifier: NSFileProviderItemIdentifier) -> tableMetadata? { - + let ocId = itemIdentifier.rawValue return NCManageDatabase.shared.getMetadataFromOcId(ocId) } func getItemIdentifier(metadata: tableMetadata) -> NSFileProviderItemIdentifier { - + return NSFileProviderItemIdentifier(metadata.ocId) } - + func createocIdentifierOnFileSystem(metadata: tableMetadata) { - + let itemIdentifier = getItemIdentifier(metadata: metadata) - + if metadata.directory { CCUtility.getDirectoryProviderStorageOcId(itemIdentifier.rawValue) } else { CCUtility.getDirectoryProviderStorageOcId(itemIdentifier.rawValue, fileNameView: metadata.fileNameView) } } - + func getParentItemIdentifier(metadata: tableMetadata) -> NSFileProviderItemIdentifier? { - + let homeServerUrl = NCUtilityFileSystem.shared.getHomeServer(account: metadata.account) - if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)) { + if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)) { if directory.serverUrl == homeServerUrl { return NSFileProviderItemIdentifier(NSFileProviderItemIdentifier.rootContainer.rawValue) } else { @@ -73,37 +73,37 @@ class fileProviderUtility: NSObject { } } } - + return nil } - + func getTableDirectoryFromParentItemIdentifier(_ parentItemIdentifier: NSFileProviderItemIdentifier, account: String, homeServerUrl: String) -> tableDirectory? { - + var predicate: NSPredicate - + if parentItemIdentifier == .rootContainer { - + predicate = NSPredicate(format: "account == %@ AND serverUrl == %@", account, homeServerUrl) - + } else { - + guard let metadata = getTableMetadataFromItemIdentifier(parentItemIdentifier) else { return nil } predicate = NSPredicate(format: "ocId == %@", metadata.ocId) } - + guard let directory = NCManageDatabase.shared.getTableDirectory(predicate: predicate) else { return nil } - + return directory } - + // MARK: - - + func copyFile(_ atPath: String, toPath: String) -> Error? { - + var errorResult: Error? - - if !fileManager.fileExists(atPath: atPath) { return NSError(domain: NSCocoaErrorDomain, code: NSFileNoSuchFileError, userInfo:[:]) } - + + if !fileManager.fileExists(atPath: atPath) { return NSError(domain: NSCocoaErrorDomain, code: NSFileNoSuchFileError, userInfo: [:]) } + do { try fileManager.removeItem(atPath: toPath) } catch let error { @@ -114,17 +114,17 @@ class fileProviderUtility: NSObject { } catch let error { errorResult = error } - + return errorResult } - + func moveFile(_ atPath: String, toPath: String) -> Error? { - + var errorResult: Error? - + if atPath == toPath { return nil } - if !fileManager.fileExists(atPath: atPath) { return NSError(domain: NSCocoaErrorDomain, code: NSFileNoSuchFileError, userInfo:[:]) } - + if !fileManager.fileExists(atPath: atPath) { return NSError(domain: NSCocoaErrorDomain, code: NSFileNoSuchFileError, userInfo: [:]) } + do { try fileManager.removeItem(atPath: toPath) } catch let error { @@ -135,23 +135,23 @@ class fileProviderUtility: NSObject { } catch let error { errorResult = error } - + return errorResult } - + func deleteFile(_ atPath: String) -> Error? { - + var errorResult: Error? - + do { try fileManager.removeItem(atPath: atPath) } catch let error { errorResult = error } - + return errorResult } - + func fileExists(atPath: String) -> Bool { return fileManager.fileExists(atPath: atPath) } diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index d80ff7ee0..4c766e440 100755..100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -20,10 +20,26 @@ 8491B1CD273BBA82001C8C5B /* UIViewController+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */; }; AF2D7C7C2742556F00ADF566 /* NCShareLinkCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2D7C7B2742556F00ADF566 /* NCShareLinkCell.swift */; }; AF2D7C7E2742559100ADF566 /* NCShareUserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2D7C7D2742559100ADF566 /* NCShareUserCell.swift */; }; + AF4BF614275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; }; + AF4BF615275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; }; + AF4BF616275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; }; + AF4BF617275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; }; + AF4BF61927562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabse+Metadata.swift */; }; + AF4BF61A27562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabse+Metadata.swift */; }; + AF4BF61B27562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabse+Metadata.swift */; }; + AF4BF61C27562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabse+Metadata.swift */; }; + AF4BF61E27562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */; }; + AF4BF61F27562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */; }; + AF4BF62027562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */; }; + AF4BF62127562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */; }; AF817EF1274BC781009ED85B /* NCUserBaseUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */; }; AF817EF2274BC781009ED85B /* NCUserBaseUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */; }; AF817EF3274BC781009ED85B /* NCUserBaseUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */; }; AF817EF4274BC781009ED85B /* NCUserBaseUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */; }; + AF8ED1FC2757821000B8DBC4 /* NextcloudTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF8ED1FB2757821000B8DBC4 /* NextcloudTests.swift */; }; + AF8ED2032757822700B8DBC4 /* NCGlobalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF8ED2022757822700B8DBC4 /* NCGlobalTests.swift */; }; + AF935067276B84E700BD078F /* NCMenu+FloatingPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF935066276B84E700BD078F /* NCMenu+FloatingPanel.swift */; }; + AFD33240276A02C100F5AE02 /* UIApplication+Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */; }; D575039F27146F93008DC9DC /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extensions.swift */; }; D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */; }; F700222C1EC479840080073F /* Custom.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F700222B1EC479840080073F /* Custom.xcassets */; }; @@ -128,6 +144,7 @@ F7362A1F220C853A005101B5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7362A1E220C853A005101B5 /* LaunchScreen.storyboard */; }; F7381EE1218218C9000B1560 /* NCOffline.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7381EDA218218C9000B1560 /* NCOffline.swift */; }; F7381EE5218218C9000B1560 /* NCOffline.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7381EDE218218C9000B1560 /* NCOffline.storyboard */; }; + F738D4902756740100CD1D38 /* NCLoginNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738D48F2756740100CD1D38 /* NCLoginNavigationController.swift */; }; F738E8421F90FFD100F95C8E /* NCManageEndToEndEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = F738E8411F90FFD100F95C8E /* NCManageEndToEndEncryption.m */; }; F73ADD1C265546890069EA0D /* SwiftEntryKit in Frameworks */ = {isa = PBXBuildFile; productRef = F73ADD1B265546890069EA0D /* SwiftEntryKit */; }; F73ADD2126554F8E0069EA0D /* SwiftEntryKit in Frameworks */ = {isa = PBXBuildFile; productRef = F73ADD2026554F8E0069EA0D /* SwiftEntryKit */; }; @@ -365,6 +382,13 @@ remoteGlobalIDString = 2C33C47E23E2C475005F963B; remoteInfo = "Notification Service Extension"; }; + AF8ED1FD2757821000B8DBC4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F7F67BA01A24D27800EE80DA /* Project object */; + proxyType = 1; + remoteGlobalIDString = F77B0DEB1D118A16002130FE; + remoteInfo = Nextcloud; + }; F7145A311D12E65F00CAFEEC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = F7F67BA01A24D27800EE80DA /* Project object */; @@ -435,7 +459,15 @@ 8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Menu.swift"; sourceTree = "<group>"; }; AF2D7C7B2742556F00ADF566 /* NCShareLinkCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareLinkCell.swift; sourceTree = "<group>"; }; AF2D7C7D2742559100ADF566 /* NCShareUserCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareUserCell.swift; sourceTree = "<group>"; }; + AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Account.swift"; sourceTree = "<group>"; }; + AF4BF61827562A4B0081CEEF /* NCManageDatabse+Metadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabse+Metadata.swift"; sourceTree = "<group>"; }; + AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Activity.swift"; sourceTree = "<group>"; }; AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCUserBaseUrl.swift; sourceTree = "<group>"; }; + AF8ED1F92757821000B8DBC4 /* NextcloudTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + AF8ED1FB2757821000B8DBC4 /* NextcloudTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudTests.swift; sourceTree = "<group>"; }; + AF8ED2022757822700B8DBC4 /* NCGlobalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCGlobalTests.swift; sourceTree = "<group>"; }; + AF935066276B84E700BD078F /* NCMenu+FloatingPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCMenu+FloatingPanel.swift"; sourceTree = "<group>"; }; + AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Orientation.swift"; sourceTree = "<group>"; }; D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityTableViewCell.swift; sourceTree = "<group>"; }; F700222B1EC479840080073F /* Custom.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Custom.xcassets; sourceTree = "<group>"; }; F700510022DF63AC003A3356 /* NCShare.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCShare.storyboard; sourceTree = "<group>"; }; @@ -550,6 +582,7 @@ F736B551234DCF57008A5C9F /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/iOS/Alamofire.framework; sourceTree = "<group>"; }; F7381EDA218218C9000B1560 /* NCOffline.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCOffline.swift; sourceTree = "<group>"; }; F7381EDE218218C9000B1560 /* NCOffline.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCOffline.storyboard; sourceTree = "<group>"; }; + F738D48F2756740100CD1D38 /* NCLoginNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCLoginNavigationController.swift; sourceTree = "<group>"; }; F738E8401F90FFD100F95C8E /* NCManageEndToEndEncryption.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NCManageEndToEndEncryption.h; sourceTree = "<group>"; }; F738E8411F90FFD100F95C8E /* NCManageEndToEndEncryption.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NCManageEndToEndEncryption.m; sourceTree = "<group>"; }; F73B42292476764F00A30FD3 /* NCNotification.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = NCNotification.storyboard; path = Notification/NCNotification.storyboard; sourceTree = "<group>"; }; @@ -798,6 +831,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AF8ED1F62757821000B8DBC4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; F7145A141D12E3B700CAFEEC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -874,6 +914,7 @@ children = ( 3704EB2923D5A58400455C5B /* NCMenu.storyboard */, 371B5A2D23D0B04500FAFAE9 /* NCMenu.swift */, + AF935066276B84E700BD078F /* NCMenu+FloatingPanel.swift */, 3781B9AF23DB2B7E006B4B1D /* AppDelegate+Menu.swift */, 8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */, F77A697C250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift */, @@ -886,6 +927,15 @@ path = Menu; sourceTree = "<group>"; }; + AF8ED1FA2757821000B8DBC4 /* NextcloudTests */ = { + isa = PBXGroup; + children = ( + AF8ED2022757822700B8DBC4 /* NCGlobalTests.swift */, + AF8ED1FB2757821000B8DBC4 /* NextcloudTests.swift */, + ); + path = NextcloudTests; + sourceTree = "<group>"; + }; F70211F31BAC56E9003FC03E /* Main */ = { isa = PBXGroup; children = ( @@ -1257,6 +1307,7 @@ F70CEF5523E9C7E50007035B /* UIColor+Extensions.swift */, F79B645F26CA661600838ACA /* UIControl+Extensions.swift */, F713FEFE2472764000214AF6 /* UIImage+animatedGIF.h */, + AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */, F713FEFF2472764100214AF6 /* UIImage+animatedGIF.m */, F7B7504A2397D38E004E13EC /* UIImage+Extensions.swift */, ); @@ -1331,6 +1382,9 @@ F7C1EEA425053A9C00866ACC /* NCDataSource.swift */, F7BAADB41ED5A87C00B7EAD4 /* NCDatabase.swift */, F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */, + AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */, + AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */, + AF4BF61827562A4B0081CEEF /* NCManageDatabse+Metadata.swift */, F73D5E46246DE09200DF6467 /* NCElementsJSON.swift */, ); path = Data; @@ -1342,6 +1396,7 @@ F7DBC37B23325E01001A85BA /* NCAppConfigView.swift */, F702F2F025EE5CDA008F8E80 /* NCLogin.storyboard */, F702F2F625EE5CEC008F8E80 /* NCLogin.swift */, + F738D48F2756740100CD1D38 /* NCLoginNavigationController.swift */, F745B252222D88AE00346520 /* NCLoginQRCode.swift */, F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */, ); @@ -1501,10 +1556,12 @@ F771E3D120E2392D00AFB62D /* File Provider Extension */, F7C0F46D1C8880540059EC54 /* Share */, 2C33C48023E2C475005F963B /* Notification Service Extension */, + AF8ED1FA2757821000B8DBC4 /* NextcloudTests */, F7FC7D651DC1F98700BB2C6A /* Products */, F7FC7D541DC1F93700BB2C6A /* Frameworks */, F771E3D020E2392D00AFB62D /* File Provider Extension.appex */, 2C33C47F23E2C475005F963B /* Notification Service Extension.appex */, + AF8ED1F92757821000B8DBC4 /* NextcloudTests.xctest */, ); sourceTree = "<group>"; }; @@ -1696,6 +1753,24 @@ productReference = 2C33C47F23E2C475005F963B /* Notification Service Extension.appex */; productType = "com.apple.product-type.app-extension"; }; + AF8ED1F82757821000B8DBC4 /* NextcloudTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = AF8ED2012757821000B8DBC4 /* Build configuration list for PBXNativeTarget "NextcloudTests" */; + buildPhases = ( + AF8ED1F52757821000B8DBC4 /* Sources */, + AF8ED1F62757821000B8DBC4 /* Frameworks */, + AF8ED1F72757821000B8DBC4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + AF8ED1FE2757821000B8DBC4 /* PBXTargetDependency */, + ); + name = NextcloudTests; + productName = NextcloudTests; + productReference = AF8ED1F92757821000B8DBC4 /* NextcloudTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; F71459B41D12E3B700CAFEEC /* Share */ = { isa = PBXNativeTarget; buildConfigurationList = F7145A251D12E3B700CAFEEC /* Build configuration list for PBXNativeTarget "Share" */; @@ -1755,7 +1830,8 @@ F77B0EE91D118A16002130FE /* Resources */, F77B0F981D118A16002130FE /* Embed App Extensions */, F70B86782642CF5300ED5349 /* Embed Frameworks */, - F7439BF8265669E800406313 /* ShellScript */, + F7439BF8265669E800406313 /* Run Script */, + AFBFD01327551A54002244BC /* ShellScript */, ); buildRules = ( ); @@ -1790,7 +1866,7 @@ F7F67BA01A24D27800EE80DA /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1130; + LastSwiftUpdateCheck = 1310; LastUpgradeCheck = 1250; ORGANIZATIONNAME = "Marino Faggiana"; TargetAttributes = { @@ -1799,6 +1875,10 @@ DevelopmentTeam = 6JLRKY9ZV7; ProvisioningStyle = Automatic; }; + AF8ED1F82757821000B8DBC4 = { + CreatedOnToolsVersion = 13.1; + TestTargetID = F77B0DEB1D118A16002130FE; + }; F71459B41D12E3B700CAFEEC = { DevelopmentTeam = 6JLRKY9ZV7; LastSwiftMigration = 1020; @@ -1904,6 +1984,7 @@ F71459B41D12E3B700CAFEEC /* Share */, F771E3CF20E2392D00AFB62D /* File Provider Extension */, 2C33C47E23E2C475005F963B /* Notification Service Extension */, + AF8ED1F82757821000B8DBC4 /* NextcloudTests */, ); }; /* End PBXProject section */ @@ -1917,6 +1998,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AF8ED1F72757821000B8DBC4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; F7145A181D12E3B700CAFEEC /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -2027,7 +2115,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - F7439BF8265669E800406313 /* ShellScript */ = { + AFBFD01327551A54002244BC /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -2042,6 +2130,24 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; + shellScript = "if test -d \"/opt/homebrew/bin/\"; then\n PATH=\"/opt/homebrew/bin/:${PATH}\"\nfi\n\nexport PATH\n\nif which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; + }; + F7439BF8265669E800406313 /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nTAGS=\"TODO:|FIXME:\"\nERRORTAG=\"ERROR:\"\nfind \"${SRCROOT}\" \\( -name \"*.h\" -or -name \"*.m\" -or -name \"*.swift\" \\) -print0 | xargs -0 egrep --with-filename --line-number --only-matching \"($TAGS).*\\$|($ERRORTAG).*\\$\" | perl -p -e \"s/($TAGS)/ warning: \\$1/\" | perl -p -e \"s/($ERRORTAG)/ error: \\$1/\"\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -2055,14 +2161,17 @@ 2C1D5D7923E2DE9100334ABB /* NCBrand.swift in Sources */, F770768A263A8A2500A1BA94 /* NCUtilityFileSystem.swift in Sources */, F746EC50273906BA0052598D /* NCViewCertificateDetails.swift in Sources */, + AF4BF62127562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */, F702F2D225EE5B5C008F8E80 /* NCGlobal.swift in Sources */, F7707689263A896A00A1BA94 /* UIImage+Extensions.swift in Sources */, 2C1D5D7523E2DE3300334ABB /* NCDatabase.swift in Sources */, 2C1D5D7623E2DE3300334ABB /* NCManageDatabase.swift in Sources */, 2C33C48223E2C475005F963B /* NotificationService.swift in Sources */, + AF4BF617275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */, D575039F27146F93008DC9DC /* String+Extensions.swift in Sources */, F73D5E4A246DE09200DF6467 /* NCElementsJSON.swift in Sources */, F79B646326CA661600838ACA /* UIControl+Extensions.swift in Sources */, + AF4BF61C27562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */, AF817EF4274BC781009ED85B /* NCUserBaseUrl.swift in Sources */, F798F0EC2588060A000DAFFD /* UIColor+Extensions.swift in Sources */, 2CB7D1CA23E2EDCB00376EF9 /* NCPushNotificationEncryption.m in Sources */, @@ -2070,6 +2179,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AF8ED1F52757821000B8DBC4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AF8ED1FC2757821000B8DBC4 /* NextcloudTests.swift in Sources */, + AF8ED2032757822700B8DBC4 /* NCGlobalTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F71459B51D12E3B700CAFEEC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2078,6 +2196,7 @@ F73D5E48246DE09200DF6467 /* NCElementsJSON.swift in Sources */, F7EDE4E5262D7BBE00414FE6 /* NCSectionHeaderFooter.swift in Sources */, F79EC78926316AC4004E59D6 /* NCPopupViewController.swift in Sources */, + AF4BF61F27562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */, F7A0D1362591FBC5008F8A13 /* String+Extensions.swift in Sources */, F7EDE4D6262D7B9600414FE6 /* NCListCell.swift in Sources */, F7707687263A853700A1BA94 /* NCContentPresenter.swift in Sources */, @@ -2085,6 +2204,8 @@ F70BFC7520E0FA7D00C67599 /* NCUtility.swift in Sources */, F79B646126CA661600838ACA /* UIControl+Extensions.swift in Sources */, F7EDE4CC262D7B6F00414FE6 /* NCEmptyDataSet.swift in Sources */, + AF4BF61A27562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */, + AF4BF615275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */, F798F0E225880608000DAFFD /* UIColor+Extensions.swift in Sources */, AF817EF2274BC781009ED85B /* NCUserBaseUrl.swift in Sources */, F78295311F962EFA00A572F5 /* NCEndToEndEncryption.m in Sources */, @@ -2123,8 +2244,10 @@ F771E3D320E2392D00AFB62D /* FileProviderExtension.swift in Sources */, F73D5E49246DE09200DF6467 /* NCElementsJSON.swift in Sources */, F771E3D520E2392D00AFB62D /* FileProviderItem.swift in Sources */, + AF4BF616275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */, F7434B3620E23FE000417916 /* NCManageDatabase.swift in Sources */, F798F0E725880609000DAFFD /* UIColor+Extensions.swift in Sources */, + AF4BF61B27562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */, F70460542499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */, F785EEA42461A4A600B3F945 /* NCUtility.swift in Sources */, F79B646226CA661600838ACA /* UIControl+Extensions.swift in Sources */, @@ -2136,6 +2259,7 @@ F74AF3A6247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */, F7A76DCD256A71CE00119AB3 /* UIImage+Extensions.swift in Sources */, F771E3F820E239B500AFB62D /* FileProviderExtension+Thumbnail.swift in Sources */, + AF4BF62027562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */, F785EEA62461A4FB00B3F945 /* CCUtility.m in Sources */, F73ADD2226554FD10069EA0D /* NCContentPresenter.swift in Sources */, ); @@ -2157,6 +2281,7 @@ F70B866E2642A21300ED5349 /* NCBackgroundImageColor.swift in Sources */, F78ACD4021903CC20088454D /* NCGridCell.swift in Sources */, F75B0ABD244C4DBB00E58DCA /* NCFunctionCenter.swift in Sources */, + AF935067276B84E700BD078F /* NCMenu+FloatingPanel.swift in Sources */, F702F2CD25EE5B4F008F8E80 /* AppDelegate.swift in Sources */, F769454022E9F077000A798A /* NCSharePaging.swift in Sources */, F78ACD4221903CE00088454D /* NCListCell.swift in Sources */, @@ -2176,6 +2301,7 @@ F7A80BCB252624C100C7CD01 /* NCFileViewInFolder.swift in Sources */, F78A18B823CDE2B300F681F3 /* NCViewerRichWorkspace.swift in Sources */, F77910AB25DD53C700CEDB9E /* NCSettingsBundleHelper.swift in Sources */, + AF4BF61927562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */, F78A18B623CDD07D00F681F3 /* NCViewerRichWorkspaceWebView.swift in Sources */, F716B75F26F09DF600D37EFC /* NCKTVHTTPCache.swift in Sources */, F75A9EE623796C6F0044CFCE /* NCNetworking.swift in Sources */, @@ -2233,11 +2359,13 @@ F76B3CCE1EAE01BD00921AC9 /* NCBrand.swift in Sources */, F769454422E9F142000A798A /* NCShareUserMenuView.swift in Sources */, F7581D2425EFDDDF004DC699 /* NCMedia+Menu.swift in Sources */, + F738D4902756740100CD1D38 /* NCLoginNavigationController.swift in Sources */, F77B0E981D118A16002130FE /* CCManageAccount.m in Sources */, F77EFC0C26D6751F00806ED6 /* NCShareQuickStatusMenu.swift in Sources */, F702F30125EE5D2C008F8E80 /* NYMnemonic.m in Sources */, F7EFA47825ADBA500083159A /* NCViewerProviderContextMenu.swift in Sources */, F755BD9B20594AC7008C5FBB /* NCService.swift in Sources */, + AFD33240276A02C100F5AE02 /* UIApplication+Orientation.swift in Sources */, F79B869B265E19D40085C0E0 /* NSMutableAttributedString+Extensions.swift in Sources */, F7B7504B2397D38F004E13EC /* UIImage+Extensions.swift in Sources */, F7EFC0CD256BF8DD00461AAD /* NCUserStatus.swift in Sources */, @@ -2277,6 +2405,8 @@ F717402E24F699A5000C87D5 /* NCFavorite.swift in Sources */, AF2D7C7E2742559100ADF566 /* NCShareUserCell.swift in Sources */, F74DE14325135B6800917068 /* NCTransfers.swift in Sources */, + AF4BF614275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */, + AF4BF61E27562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2288,6 +2418,11 @@ target = 2C33C47E23E2C475005F963B /* Notification Service Extension */; targetProxy = 2C33C48423E2C475005F963B /* PBXContainerItemProxy */; }; + AF8ED1FE2757821000B8DBC4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F77B0DEB1D118A16002130FE /* Nextcloud */; + targetProxy = AF8ED1FD2757821000B8DBC4 /* PBXContainerItemProxy */; + }; F7145A321D12E65F00CAFEEC /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = F71459B41D12E3B700CAFEEC /* Share */; @@ -2373,7 +2508,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 5; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6JLRKY9ZV7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -2393,7 +2528,7 @@ "@executable_path/../../Frameworks", ); LIBRARY_SEARCH_PATHS = ""; - MARKETING_VERSION = 4.1.0; + MARKETING_VERSION = 4.2.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_LDFLAGS = "-ObjC"; @@ -2403,6 +2538,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) EXTENSION EXTENSION_NOTIFICATION_SERVICE"; SWIFT_OBJC_BRIDGING_HEADER = "Notification Service Extension/Notification_Service_Extension-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -2426,7 +2562,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 5; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6JLRKY9ZV7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -2446,7 +2582,7 @@ "@executable_path/../../Frameworks", ); LIBRARY_SEARCH_PATHS = ""; - MARKETING_VERSION = 4.1.0; + MARKETING_VERSION = 4.2.0; MTL_FAST_MATH = YES; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = "it.twsweb.Nextcloud.Notification-Service-Extension"; @@ -2454,11 +2590,89 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) EXTENSION EXTENSION_NOTIFICATION_SERVICE"; SWIFT_OBJC_BRIDGING_HEADER = "Notification Service Extension/Notification_Service_Extension-Bridging-Header.h"; + SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; + AF8ED1FF2757821000B8DBC4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 6JLRKY9ZV7; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = it.twsweb.NextcloudTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Nextcloud.app/Nextcloud"; + }; + name = Debug; + }; + AF8ED2002757821000B8DBC4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = 6JLRKY9ZV7; + GCC_C_LANGUAGE_STANDARD = gnu11; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = it.twsweb.NextcloudTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Nextcloud.app/Nextcloud"; + }; + name = Release; + }; F7145A261D12E3B700CAFEEC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2470,7 +2684,7 @@ CODE_SIGN_ENTITLEMENTS = iOSClient/Brand/Share.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 5; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6JLRKY9ZV7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -2490,7 +2704,7 @@ "@executable_path/../../Frameworks", ); LIBRARY_SEARCH_PATHS = ""; - MARKETING_VERSION = 4.1.0; + MARKETING_VERSION = 4.2.0; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = it.twsweb.Nextcloud.Share; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2498,6 +2712,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) EXTENSION EXTENSION_SHARE"; SWIFT_OBJC_BRIDGING_HEADER = "Share/Share-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; USE_HEADERMAP = YES; @@ -2515,7 +2730,7 @@ CODE_SIGN_ENTITLEMENTS = iOSClient/Brand/Share.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 5; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6JLRKY9ZV7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -2535,13 +2750,14 @@ "@executable_path/../../Frameworks", ); LIBRARY_SEARCH_PATHS = ""; - MARKETING_VERSION = 4.1.0; + MARKETING_VERSION = 4.2.0; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = it.twsweb.Nextcloud.Share; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) EXTENSION EXTENSION_SHARE"; SWIFT_OBJC_BRIDGING_HEADER = "Share/Share-Bridging-Header.h"; + SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; USE_HEADERMAP = YES; @@ -2567,7 +2783,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 5; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6JLRKY9ZV7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -2587,7 +2803,7 @@ "@executable_path/../../Frameworks", ); LIBRARY_SEARCH_PATHS = ""; - MARKETING_VERSION = 4.1.0; + MARKETING_VERSION = 4.2.0; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = "it.twsweb.Nextcloud.File-Provider-Extension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2595,6 +2811,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) EXTENSION EXTENSION_FILE_PROVIDER_EXTENSION"; SWIFT_OBJC_BRIDGING_HEADER = "File Provider Extension/FileProviderExtension-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -2619,7 +2836,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 5; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6JLRKY9ZV7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -2639,13 +2856,14 @@ "@executable_path/../../Frameworks", ); LIBRARY_SEARCH_PATHS = ""; - MARKETING_VERSION = 4.1.0; + MARKETING_VERSION = 4.2.0; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = "it.twsweb.Nextcloud.File-Provider-Extension"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) EXTENSION EXTENSION_FILE_PROVIDER_EXTENSION"; SWIFT_OBJC_BRIDGING_HEADER = "File Provider Extension/FileProviderExtension-Bridging-Header.h"; + SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -2663,7 +2881,7 @@ CODE_SIGN_ENTITLEMENTS = iOSClient/Brand/iOSClient.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = 6JLRKY9ZV7; ENABLE_BITCODE = YES; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -2680,7 +2898,7 @@ "@executable_path/../../Frameworks", ); LIBRARY_SEARCH_PATHS = ""; - MARKETING_VERSION = 4.1.0; + MARKETING_VERSION = 4.2.0; OTHER_LDFLAGS = "-ObjC"; OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "it.twsweb.$(PRODUCT_NAME:rfc1034identifier)"; @@ -2690,6 +2908,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; SWIFT_OBJC_BRIDGING_HEADER = "iOSClient/Nextcloud-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; USE_HEADERMAP = YES; @@ -2710,7 +2929,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 17; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = 6JLRKY9ZV7; ENABLE_BITCODE = YES; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -2726,7 +2945,7 @@ "@executable_path/../../Frameworks", ); LIBRARY_SEARCH_PATHS = ""; - MARKETING_VERSION = 4.1.0; + MARKETING_VERSION = 4.2.0; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = "it.twsweb.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2734,6 +2953,7 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; SWIFT_OBJC_BRIDGING_HEADER = "iOSClient/Nextcloud-Bridging-Header.h"; + SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; USE_HEADERMAP = YES; @@ -2879,6 +3099,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + AF8ED2012757821000B8DBC4 /* Build configuration list for PBXNativeTarget "NextcloudTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AF8ED1FF2757821000B8DBC4 /* Debug */, + AF8ED2002757821000B8DBC4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; F7145A251D12E3B700CAFEEC /* Build configuration list for PBXNativeTarget "Share" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -2971,15 +3200,15 @@ repositoryURL = "https://github.com/scenee/FloatingPanel"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 1.7.6; + minimumVersion = 2.0.0; }; }; F782A57925123694007BBABD /* XCRemoteSwiftPackageReference "realm-cocoa" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/realm/realm-cocoa"; requirement = { - kind = exactVersion; - version = 10.18.0; + kind = upToNextMajorVersion; + minimumVersion = 10.20.1; }; }; F786D58B253454BF00E3DD7B /* XCRemoteSwiftPackageReference "ios-communication-library" */ = { diff --git a/Nextcloud.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Nextcloud.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 8ab7fae44..93020ee70 100644 --- a/Nextcloud.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Nextcloud.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -42,8 +42,8 @@ "repositoryURL": "https://github.com/firebase/firebase-ios-sdk", "state": { "branch": null, - "revision": "839cc6b0cd80b0b8bf81fe9bd82b743b25dc6446", - "version": "8.9.1" + "revision": "08686f04881483d2bc098b2696e674c0ba135e47", + "version": "8.10.0" } }, { @@ -51,8 +51,8 @@ "repositoryURL": "https://github.com/scenee/FloatingPanel", "state": { "branch": null, - "revision": "ca7596e1cae161415f54059a8c44b82c95724160", - "version": "1.7.6" + "revision": "0fbbbc8d99b4dfe58bb1dd704d14b45f35b46584", + "version": "2.5.1" } }, { @@ -168,8 +168,8 @@ "repositoryURL": "https://github.com/google/promises.git", "state": { "branch": null, - "revision": "afa9a1ace74e116848d4f743599ab83e584ff8cb", - "version": "1.2.12" + "revision": "611337c330350c9c1823ad6d671e7f936af5ee13", + "version": "2.0.0" } }, { @@ -195,8 +195,8 @@ "repositoryURL": "https://github.com/realm/realm-cocoa", "state": { "branch": null, - "revision": "9f43d0da902c55b493d6c8bb63203764caa8acbe", - "version": "10.18.0" + "revision": "f483fa0a52f6d49897d133a827510a35e21183c1", + "version": "10.20.1" } }, { @@ -204,8 +204,8 @@ "repositoryURL": "https://github.com/realm/realm-core", "state": { "branch": null, - "revision": "23f60515a00f076a9e3f2dc672fe1ae07601ee90", - "version": "11.4.1" + "revision": "c3c11a841642ac93c27bd1edd61f989fc0bfb809", + "version": "11.6.1" } }, { @@ -267,8 +267,8 @@ "repositoryURL": "https://github.com/yahoojapan/SwiftyXMLParser", "state": { "branch": null, - "revision": "ad5eeeaf7797f69e26943aaa53c81c6a9fdaa516", - "version": "5.5.0" + "revision": "d7a1d23f04c86c1cd2e8f19247dd15d74e0ea8be", + "version": "5.6.0" } } ] diff --git a/Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme b/Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme index 54e42b9a6..315a8ea7d 100755 --- a/Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme +++ b/Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme @@ -52,6 +52,16 @@ </BuildableReference> </MacroExpansion> <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "AF8ED1F82757821000B8DBC4" + BuildableName = "NextcloudTests.xctest" + BlueprintName = "NextcloudTests" + ReferencedContainer = "container:Nextcloud.xcodeproj"> + </BuildableReference> + </TestableReference> </Testables> </TestAction> <LaunchAction @@ -83,6 +93,7 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES" + askForAppToLaunch = "Yes" launchAutomaticallySubstyle = "2"> <BuildableProductRunnable runnableDebuggingMode = "0"> diff --git a/Nextcloud.xcodeproj/xcshareddata/xcschemes/Nextcloud.xcscheme b/Nextcloud.xcodeproj/xcshareddata/xcschemes/Nextcloud.xcscheme index 295bf5b50..0de72cffc 100755 --- a/Nextcloud.xcodeproj/xcshareddata/xcschemes/Nextcloud.xcscheme +++ b/Nextcloud.xcodeproj/xcshareddata/xcschemes/Nextcloud.xcscheme @@ -26,7 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> <MacroExpansion> <BuildableReference BuildableIdentifier = "primary" @@ -37,6 +38,16 @@ </BuildableReference> </MacroExpansion> <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "AF8ED1F82757821000B8DBC4" + BuildableName = "NextcloudTests.xctest" + BlueprintName = "NextcloudTests" + ReferencedContainer = "container:Nextcloud.xcodeproj"> + </BuildableReference> + </TestableReference> </Testables> </TestAction> <LaunchAction diff --git a/Nextcloud.xcodeproj/xcshareddata/xcschemes/Share.xcscheme b/Nextcloud.xcodeproj/xcshareddata/xcschemes/Share.xcscheme index d4dc7c8c1..279a69ad5 100755 --- a/Nextcloud.xcodeproj/xcshareddata/xcschemes/Share.xcscheme +++ b/Nextcloud.xcodeproj/xcshareddata/xcschemes/Share.xcscheme @@ -52,6 +52,16 @@ </BuildableReference> </MacroExpansion> <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "AF8ED1F82757821000B8DBC4" + BuildableName = "NextcloudTests.xctest" + BlueprintName = "NextcloudTests" + ReferencedContainer = "container:Nextcloud.xcodeproj"> + </BuildableReference> + </TestableReference> </Testables> </TestAction> <LaunchAction @@ -87,6 +97,7 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES" + askForAppToLaunch = "Yes" launchAutomaticallySubstyle = "2"> <BuildableProductRunnable runnableDebuggingMode = "0"> diff --git a/NextcloudTests/NCGlobalTests.swift b/NextcloudTests/NCGlobalTests.swift new file mode 100644 index 000000000..8e9016e2b --- /dev/null +++ b/NextcloudTests/NCGlobalTests.swift @@ -0,0 +1,54 @@ +// +// NCGlobalTests.swift +// Nextcloud +// +// Created by Henrik Storch on 01.12.21. +// Copyright © 2021 Henrik Storch. All rights reserved. +// +// Author Henrik Storch <henrik.storch@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/>. +// + +@testable import Nextcloud +import XCTest + +class NCGlobalTests: XCTestCase { + + func testSharedInatance() throws { + XCTAssertNotNil(NCGlobal.shared, "Shared instance should be initialized") + } + + func testHashToInt() { + let emptyHash10 = NCGlobal.hashToInt(hash: "", maximum: 10) + let emptyHash2 = NCGlobal.hashToInt(hash: "", maximum: 2) + XCTAssertEqual(emptyHash10, 0, "Empty hash should be zero") + XCTAssertEqual(emptyHash10, emptyHash2, "Empty hashes should be the same") + let emptyHashA = NCGlobal.hashToInt(hash: "a", maximum: 10) + XCTAssertEqual(emptyHashA, 0, "Hash of 'a' mod 10 should be zero") + let emptyHash22 = NCGlobal.hashToInt(hash: "1ab", maximum: 100) + XCTAssertEqual(emptyHash22, 22, "Hash of '1ab' mod 100 should be 22") + let nonHexHash = NCGlobal.hashToInt(hash: "1qw&(*}", maximum: 10) + XCTAssertEqual(nonHexHash, 1, "Non hex characters should be ignored") + } + + func testUsernameToColor() { + let color = NCGlobal.shared.usernameToColor("00000000") + let userColor = NCBrandColor.shared.userColors[0] + XCTAssertEqual(color, userColor, "Zero usercolor doesn't match") + let emptyColor = NCGlobal.shared.usernameToColor("") + let emptyUserColor = NCBrandColor.shared.userColors[12] + XCTAssertEqual(emptyColor, emptyUserColor, "Empty usercolor doesn't match") + } +} diff --git a/NextcloudTests/NextcloudTests.swift b/NextcloudTests/NextcloudTests.swift new file mode 100644 index 000000000..a82c340dc --- /dev/null +++ b/NextcloudTests/NextcloudTests.swift @@ -0,0 +1,33 @@ +// +// NextcloudTests.swift +// NextcloudTests +// +// Created by Henrik Storch on 01.12.21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import XCTest + +class NextcloudTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/Notification Service Extension/NotificationService.swift b/Notification Service Extension/NotificationService.swift index 7e080aaf1..8024bfbbd 100644 --- a/Notification Service Extension/NotificationService.swift +++ b/Notification Service Extension/NotificationService.swift @@ -30,7 +30,7 @@ class NotificationService: UNNotificationServiceExtension { override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) - + if let bestAttemptContent = bestAttemptContent { bestAttemptContent.title = "" bestAttemptContent.body = "Nextcloud notification" @@ -55,11 +55,11 @@ class NotificationService: UNNotificationServiceExtension { } catch let error as NSError { print("Failed : \(error.localizedDescription)") } - + contentHandler(bestAttemptContent) } } - + override func serviceExtensionTimeWillExpire() { // Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. @@ -1,10 +1,14 @@ -# [Nextcloud](https://nextcloud.com) iOS app [![Releases](https://img.shields.io/github/release/nextcloud/ios.svg)](https://github.com/nextcloud/ios/releases/latest) +# [Nextcloud](https://nextcloud.com) iOS app +[![Releases](https://img.shields.io/github/release/nextcloud/ios.svg)](https://github.com/nextcloud/ios/releases/latest) [![Build](https://github.com/nextcloud/ios/actions/workflows/xcode.yml/badge.svg)](https://github.com/nextcloud/ios/actions/workflows/xcode.yml) [![SwiftLint](https://github.com/nextcloud/ios/actions/workflows/lint.yml/badge.svg)](https://github.com/nextcloud/ios/actions/workflows/lint.yml) +[![irc](https://img.shields.io/badge/IRC-%23nextcloud--mobile%20on%20freenode-blue.svg)](https://webchat.freenode.net/?channels=nextcloud-mobile) -[<img src="Animation.gif" -alt="Download from App Store" -height="400">](https://itunes.apple.com/us/app/nextcloud/id1125420102?mt=8) +<img src="Animation.gif" +alt="Demo of the Nextcloud iOS files app" +height="400"> -[![irc](https://img.shields.io/badge/IRC-%23nextcloud--mobile%20on%20freenode-blue.svg)](https://webchat.freenode.net/?channels=nextcloud-mobile) +[<img src="https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg" +alt="Demo of the Nextcloud iOS files app" +height="40">](https://itunes.apple.com/us/app/nextcloud/id1125420102) Check out https://nextcloud.com and follow us on [twitter.com/nextclouders](https://twitter.com/nextclouders) or [twitter.com/NextcloudiOS](https://twitter.com/NextcloudiOS) @@ -33,11 +37,11 @@ More information how to contribute: [https://nextcloud.com/contribute/](https:// ## Start contributing You can start by forking this repository and creating pull requests on the develop -branch. Maybe start working on [starter issues](https://github.com/nextcloud/ios/issues?q=is%3Aopen+is%3Aissue+label%3A%22starter+issue%22). +branch. Maybe start working on [starter issues](https://github.com/nextcloud/ios/labels/good%20first%20issue). Easy starting points are also reviewing [pull requests](https://github.com/nextcloud/ios/pulls) -### Xcode V 13 Project Setup +### Xcode 13 Project Setup #### Dependencies diff --git a/Share/NCShareExtension.swift b/Share/NCShareExtension.swift index 6c3f7715f..dda59037e 100644 --- a/Share/NCShareExtension.swift +++ b/Share/NCShareExtension.swift @@ -26,7 +26,7 @@ import NCCommunication import IHProgressHUD class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDelegate, NCRenameFileDelegate, NCAccountRequestDelegate { - + @IBOutlet weak var collectionView: UICollectionView! @IBOutlet weak var tableView: UITableView! @IBOutlet weak var cancelButton: UIBarButtonItem! @@ -34,7 +34,7 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele @IBOutlet weak var commandView: UIView! @IBOutlet weak var separatorHeightConstraint: NSLayoutConstraint! @IBOutlet weak var commandViewHeightConstraint: NSLayoutConstraint! - + @IBOutlet weak var createFolderView: UIView! @IBOutlet weak var createFolderImage: UIImageView! @IBOutlet weak var createFolderLabel: UILabel! @@ -42,12 +42,12 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele @IBOutlet weak var uploadView: UIView! @IBOutlet weak var uploadImage: UIImageView! @IBOutlet weak var uploadLabel: UILabel! - + // ------------------------------------------------------------- var serverUrl = "" var filesName: [String] = [] // ------------------------------------------------------------- - + private var emptyDataSet: NCEmptyDataSet? private let keyLayout = NCGlobal.shared.layoutViewShareExtension private var metadataFolder: tableMetadata? @@ -55,29 +55,29 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele private var dataSource = NCDataSource() private var layoutForView: NCGlobal.layoutForViewType? - + private var heightRowTableView: CGFloat = 50 private var heightCommandView: CGFloat = 170 - + private var autoUploadFileName = "" private var autoUploadDirectory = "" - + private let refreshControl = UIRefreshControl() private var activeAccount: tableAccount! private let chunckSize = CCUtility.getChunkSize() * 1000000 - + private var numberFilesName: Int = 0 private var counterUpload: Int = 0 - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + self.navigationController?.navigationBar.prefersLargeTitles = false - + // Cell - collectionView.register(UINib.init(nibName: "NCListCell", bundle: nil), forCellWithReuseIdentifier: "listCell") + collectionView.register(UINib(nibName: "NCListCell", bundle: nil), forCellWithReuseIdentifier: "listCell") collectionView.collectionViewLayout = NCListLayout() // Add Refresh Control @@ -85,38 +85,38 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele refreshControl.tintColor = NCBrandColor.shared.brandText refreshControl.backgroundColor = NCBrandColor.shared.systemBackground refreshControl.addTarget(self, action: #selector(reloadDatasource), for: .valueChanged) - + // Command view commandView.backgroundColor = NCBrandColor.shared.secondarySystemBackground separatorView.backgroundColor = NCBrandColor.shared.separator separatorHeightConstraint.constant = 0.5 - + // Table view tableView.separatorColor = NCBrandColor.shared.separator tableView.layer.cornerRadius = 10 tableView.tableFooterView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 0, height: 1))) commandViewHeightConstraint.constant = heightCommandView - + // Create folder createFolderView.layer.cornerRadius = 10 createFolderImage.image = NCUtility.shared.loadImage(named: "folder.badge.plus", color: NCBrandColor.shared.label) createFolderLabel.text = NSLocalizedString("_create_folder_", comment: "") - let createFolderGesture = UITapGestureRecognizer(target: self, action: #selector(actionCreateFolder)) + let createFolderGesture = UITapGestureRecognizer(target: self, action: #selector(actionCreateFolder)) createFolderView.addGestureRecognizer(createFolderGesture) - + // Upload uploadView.layer.cornerRadius = 10 - //uploadImage.image = NCUtility.shared.loadImage(named: "square.and.arrow.up", color: NCBrandColor.shared.label) + // uploadImage.image = NCUtility.shared.loadImage(named: "square.and.arrow.up", color: NCBrandColor.shared.label) uploadLabel.text = NSLocalizedString("_upload_", comment: "") uploadLabel.textColor = .systemBlue - let uploadGesture = UITapGestureRecognizer(target: self, action: #selector(actionUpload)) + let uploadGesture = UITapGestureRecognizer(target: self, action: #selector(actionUpload)) uploadView.addGestureRecognizer(uploadGesture) - + // LOG let levelLog = CCUtility.getLogLevel() let isSimulatorOrTestFlight = NCUtility.shared.isSimulatorOrTestFlight() let versionNextcloudiOS = String(format: NCBrandOptions.shared.textCopyrightNextcloudiOS, NCUtility.shared.getVersionApp()) - + NCCommunicationCommon.shared.levelLog = levelLog if let pathDirectoryGroup = CCUtility.getDirectoryGroup()?.path { NCCommunicationCommon.shared.pathLog = pathDirectoryGroup @@ -126,31 +126,31 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele } else { NCCommunicationCommon.shared.writeLog("Start session with level \(levelLog) " + versionNextcloudiOS) } - + // HUD IHProgressHUD.set(viewForExtension: self.view) IHProgressHUD.set(defaultMaskType: .clear) IHProgressHUD.set(minimumDismiss: 0) - - NotificationCenter.default.addObserver(self, selector: #selector(triggerProgressTask(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask), object:nil) + + NotificationCenter.default.addObserver(self, selector: #selector(triggerProgressTask(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask), object: nil) } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + if serverUrl == "" { - + if let activeAccount = NCManageDatabase.shared.getActiveAccount() { - + setAccount(account: activeAccount.account) - getFilesExtensionContext { (filesName) in - + getFilesExtensionContext { filesName in + self.filesName = filesName DispatchQueue.main.async { - + var saveHtml: [String] = [] var saveOther: [String] = [] - + for fileName in self.filesName { if (fileName as NSString).pathExtension.lowercased() == "html" { saveHtml.append(fileName) @@ -158,19 +158,19 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele saveOther.append(fileName) } } - + if saveOther.count > 0 && saveHtml.count > 0 { for file in saveHtml { - self.filesName = self.filesName.filter(){$0 != file} + self.filesName = self.filesName.filter {$0 != file} } } - + self.setCommandView() } } - + } else { - + let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_no_active_account_", comment: ""), preferredStyle: .alert) alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil) @@ -179,61 +179,61 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele } } } - + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) - + coordinator.animate(alongsideTransition: nil) { _ in self.collectionView?.collectionViewLayout.invalidateLayout() } } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - + collectionView.reloadData() tableView.reloadData() } - + // MARK: - @objc func triggerProgressTask(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let progressNumber = userInfo["progress"] as? NSNumber { - + let progress = CGFloat(progressNumber.floatValue) let status = NSLocalizedString("_upload_file_", comment: "") + " \(self.counterUpload) " + NSLocalizedString("_of_", comment: "") + " \(self.numberFilesName)" IHProgressHUD.show(progress: progress, status: status) } } - + // MARK: - func setAccount(account: String) { - + guard let activeAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) else { extensionContext?.completeRequest(returningItems: extensionContext?.inputItems, completionHandler: nil) return } self.activeAccount = activeAccount - + // NETWORKING NCCommunicationCommon.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: CCUtility.getUserAgent(), webDav: NCUtilityFileSystem.shared.getWebDAV(account: activeAccount.account), nextcloudVersion: 0, delegate: NCNetworking.shared) - + // get auto upload folder autoUploadFileName = NCManageDatabase.shared.getAccountAutoUploadFileName() autoUploadDirectory = NCManageDatabase.shared.getAccountAutoUploadDirectory(urlBase: activeAccount.urlBase, account: activeAccount.account) - + serverUrl = NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account) - - layoutForView = NCUtility.shared.getLayoutForView(key: keyLayout,serverUrl: serverUrl) - + + layoutForView = NCUtility.shared.getLayoutForView(key: keyLayout, serverUrl: serverUrl) + reloadDatasource(withLoadFolder: true) setNavigationBar(navigationTitle: NCBrandOptions.shared.brand) } - + func setNavigationBar(navigationTitle: String) { - + navigationItem.title = navigationTitle cancelButton.title = NSLocalizedString("_cancel_", comment: "") @@ -246,14 +246,14 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele backButton.setTitle(" "+NSLocalizedString("_back_", comment: ""), for: .normal) backButton.setTitleColor(.systemBlue, for: .normal) backButton.action(for: .touchUpInside) { _ in - + while self.serverUrl.last != "/" { self.serverUrl.removeLast() } self.serverUrl.removeLast() self.reloadDatasource(withLoadFolder: true) - + var navigationTitle = (self.serverUrl as NSString).lastPathComponent if NCUtilityFileSystem.shared.getHomeServer(account: self.activeAccount.account) == self.serverUrl { navigationTitle = NCBrandOptions.shared.brand @@ -283,16 +283,16 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele profileButton.setTitle(title, for: .normal) profileButton.setTitleColor(.systemBlue, for: .normal) } - + profileButton.semanticContentAttribute = .forceLeftToRight profileButton.sizeToFit() profileButton.action(for: .touchUpInside) { _ in - + let accounts = NCManageDatabase.shared.getAllAccountOrderAlias() if accounts.count > 1 { - + if let vcAccountRequest = UIStoryboard(name: "NCAccountRequest", bundle: nil).instantiateInitialViewController() as? NCAccountRequest { - + // Only here change the active account for account in accounts { if account.account == self.activeAccount.account { @@ -301,9 +301,9 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele account.active = false } } - + vcAccountRequest.activeAccount = self.activeAccount - vcAccountRequest.accounts = accounts.sorted { (sorg, dest) -> Bool in + vcAccountRequest.accounts = accounts.sorted { sorg, dest -> Bool in return sorg.active && !dest.active } vcAccountRequest.enableTimerProgress = false @@ -314,31 +314,31 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele let screenHeighMax = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/5) let numberCell = accounts.count let height = min(CGFloat(numberCell * Int(vcAccountRequest.heightCell) + 45), screenHeighMax) - + let popup = NCPopupViewController(contentController: vcAccountRequest, popupWidth: 300, popupHeight: height+20) - + self.present(popup, animated: true) } } } - + if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account) { navigationItem.setLeftBarButtonItems([UIBarButtonItem(customView: profileButton)], animated: true) - + } else { let space = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil) space.width = 20 - + navigationItem.setLeftBarButtonItems([UIBarButtonItem(customView: backButton), space, UIBarButtonItem(customView: profileButton)], animated: true) } } - + func setCommandView() { - + var counter: CGFloat = 0 - + if filesName.count == 0 { self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil) return @@ -346,7 +346,7 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele if filesName.count < 3 { counter = CGFloat(filesName.count) self.commandViewHeightConstraint.constant = heightCommandView + (self.heightRowTableView * counter) - } else { + } else { counter = 3 self.commandViewHeightConstraint.constant = heightCommandView + (self.heightRowTableView * counter) } @@ -357,99 +357,99 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele numberFilesName = filesName.count uploadLabel.text = NSLocalizedString("_upload_", comment: "") + " \(numberFilesName) " + NSLocalizedString("_files_", comment: "") // Empty - emptyDataSet = NCEmptyDataSet.init(view: collectionView, offset: -50*counter, delegate: self) + emptyDataSet = NCEmptyDataSet(view: collectionView, offset: -50*counter, delegate: self) self.tableView.reloadData() } } - + // MARK: - Empty - + func emptyDataSetView(_ view: NCEmptyView) { - + if networkInProgress { - view.emptyImage.image = UIImage.init(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width) + view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width) view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "") view.emptyDescription.text = "" } else { - view.emptyImage.image = UIImage.init(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width) + view.emptyImage.image = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width) view.emptyTitle.text = NSLocalizedString("_files_no_folders_", comment: "") view.emptyDescription.text = "" } } - + // MARK: ACTION - + @IBAction func actionCancel(_ sender: UIBarButtonItem) { extensionContext?.completeRequest(returningItems: extensionContext?.inputItems, completionHandler: nil) } - + @objc func actionCreateFolder() { - - let alertController = UIAlertController(title: NSLocalizedString("_create_folder_", comment: ""), message:"", preferredStyle: .alert) - - alertController.addTextField { (textField) in + + let alertController = UIAlertController(title: NSLocalizedString("_create_folder_", comment: ""), message: "", preferredStyle: .alert) + + alertController.addTextField { textField in textField.autocapitalizationType = UITextAutocapitalizationType.words } - - let actionSave = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default) { (action:UIAlertAction) in - if let fileName = alertController.textFields?.first?.text { + + let actionSave = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default) { (_: UIAlertAction) in + if let fileName = alertController.textFields?.first?.text { self.createFolder(with: fileName) } } - - let actionCancel = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { (action:UIAlertAction) in + + let actionCancel = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { (_: UIAlertAction) in print("You've pressed cancel button") } - + alertController.addAction(actionSave) alertController.addAction(actionCancel) - - self.present(alertController, animated: true, completion:nil) + + self.present(alertController, animated: true, completion: nil) } - + @objc func actionUpload() { - + if let fileName = filesName.first { - + counterUpload += 1 filesName.removeFirst() let ocId = NSUUID().uuidString let filePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)! - + if NCUtilityFileSystem.shared.moveFile(atPath: (NSTemporaryDirectory() + fileName), toPath: filePath) { - + let metadata = NCManageDatabase.shared.createMetadata(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, fileName: fileName, fileNameView: fileName, ocId: ocId, serverUrl: serverUrl, urlBase: activeAccount.urlBase, url: "", contentType: "", livePhoto: false) - + metadata.session = NCCommunicationCommon.shared.sessionIdentifierUpload metadata.sessionSelector = NCGlobal.shared.selectorUploadFile metadata.size = NCUtilityFileSystem.shared.getFileSize(filePath: filePath) metadata.status = NCGlobal.shared.metadataStatusWaitUpload - + // E2EE if CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase) { metadata.e2eEncrypted = true } - + // CHUNCK if chunckSize != 0 && metadata.size > chunckSize { metadata.chunk = true } - + NCNetworking.shared.upload(metadata: metadata) { - - } completion: { (errorCode, errorDescription) in - + + } completion: { errorCode, errorDescription in + if errorCode == 0 { - + self.actionUpload() - + } else { - + IHProgressHUD.dismiss() NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocId)) NCManageDatabase.shared.deleteChunks(account: self.activeAccount.account, ocId: ocId) - + let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: errorDescription, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil) @@ -459,7 +459,7 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele } } } else { - + IHProgressHUD.showSuccesswithStatus(NSLocalizedString("_success_", comment: "")) DispatchQueue.main.asyncAfter(deadline: .now() + 1) { @@ -467,18 +467,18 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele } } } - + func rename(fileName: String, fileNameNew: String) { - + if let row = self.filesName.firstIndex(where: {$0 == fileName}) { - + if NCUtilityFileSystem.shared.moveFile(atPath: (NSTemporaryDirectory() + fileName), toPath: (NSTemporaryDirectory() + fileNameNew)) { filesName[row] = fileNameNew tableView.reloadData() } } } - + func accountRequestChangeAccount(account: String) { setAccount(account: account) } @@ -489,17 +489,17 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele extension NCShareExtension: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - + if let metadata = dataSource.cellForItemAt(indexPath: indexPath) { - if let serverUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName) { - + if let serverUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName) { + if metadata.e2eEncrypted && !CCUtility.isEnd(toEndEnabled: activeAccount.account) { let alertController = UIAlertController(title: NSLocalizedString("_info_", comment: ""), message: NSLocalizedString("_e2e_goto_settings_for_enable_", comment: ""), preferredStyle: .alert) alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) self.present(alertController, animated: true) return } - + self.serverUrl = serverUrl reloadDatasource(withLoadFolder: true) setNavigationBar(navigationTitle: metadata.fileNameView) @@ -513,61 +513,61 @@ extension NCShareExtension: UICollectionViewDataSource { func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } - + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { let numberOfItems = dataSource.numberOfItems() - emptyDataSet?.numberOfItemsInSection(numberOfItems, section:section) + emptyDataSet?.numberOfItemsInSection(numberOfItems, section: section) return numberOfItems } - + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - + guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else { return collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! NCListCell } - + var tableShare: tableShare? var isShare = false var isMounted = false - + if let metadataFolder = metadataFolder { isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !metadataFolder.permissions.contains(NCGlobal.shared.permissionShared) isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !metadataFolder.permissions.contains(NCGlobal.shared.permissionMounted) } - + if dataSource.metadataShare[metadata.ocId] != nil { tableShare = dataSource.metadataShare[metadata.ocId] } - + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! NCListCell cell.delegate = self - + cell.fileObjectId = metadata.ocId cell.fileUser = metadata.ownerId cell.labelTitle.text = metadata.fileNameView cell.labelTitle.textColor = NCBrandColor.shared.label - + cell.imageSelect.image = nil cell.imageStatus.image = nil cell.imageLocal.image = nil cell.imageFavorite.image = nil cell.imageShared.image = nil cell.imageMore.image = nil - + cell.imageItem.image = nil cell.imageItem.backgroundColor = nil - + cell.progressView.progress = 0.0 - + if metadata.directory { - + if metadata.e2eEncrypted { cell.imageItem.image = NCBrandColor.cacheImages.folderEncrypted } else if isShare { cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe - } else if (tableShare != nil && tableShare?.shareType != 3) { + } else if tableShare != nil && tableShare?.shareType != 3 { cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe - } else if (tableShare != nil && tableShare?.shareType == 3) { + } else if tableShare != nil && tableShare?.shareType == 3 { cell.imageItem.image = NCBrandColor.cacheImages.folderPublic } else if metadata.mountType == "group" { cell.imageItem.image = NCBrandColor.cacheImages.folderGroup @@ -578,24 +578,24 @@ extension NCShareExtension: UICollectionViewDataSource { } else { cell.imageItem.image = NCBrandColor.cacheImages.folder } - + cell.labelInfo.text = CCUtility.dateDiff(metadata.date as Date) - + let lockServerUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName)! let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", activeAccount.account, lockServerUrl)) - + // Local image: offline if tableDirectory != nil && tableDirectory!.offline { cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag } - + } - + // image Favorite if metadata.favorite { cell.imageFavorite.image = NCBrandColor.cacheImages.favorite } - + cell.imageSelect.isHidden = true cell.backgroundView = nil cell.hideButtonMore(true) @@ -606,14 +606,14 @@ extension NCShareExtension: UICollectionViewDataSource { if metadata.livePhoto { cell.imageStatus.image = NCBrandColor.cacheImages.livePhoto } - + // Remove last separator if collectionView.numberOfItems(inSection: indexPath.section) == indexPath.row + 1 { cell.separator.isHidden = true } else { cell.separator.isHidden = false } - + return cell } } @@ -621,64 +621,64 @@ extension NCShareExtension: UICollectionViewDataSource { // MARK: - Table View extension NCShareExtension: UITableViewDelegate { - + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return heightRowTableView } - + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { } } extension NCShareExtension: UITableViewDataSource { - + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { filesName.count } - + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.backgroundColor = NCBrandColor.shared.systemBackground - + let imageCell = cell.viewWithTag(10) as? UIImageView let fileNameCell = cell.viewWithTag(20) as? UILabel let moreButton = cell.viewWithTag(30) as? NCShareExtensionButtonWithIndexPath let sizeCell = cell.viewWithTag(40) as? UILabel - + imageCell?.layer.cornerRadius = 6 imageCell?.layer.masksToBounds = true let fileName = filesName[indexPath.row] let resultInternalType = NCCommunicationCommon.shared.getInternalType(fileName: fileName, mimeType: "", directory: false) - + if let image = UIImage(contentsOfFile: (NSTemporaryDirectory() + fileName)) { imageCell?.image = image.resizeImage(size: CGSize(width: 80, height: 80), isAspectRation: true) } else { if resultInternalType.iconName.count > 0 { - imageCell?.image = UIImage.init(named: resultInternalType.iconName) + imageCell?.image = UIImage(named: resultInternalType.iconName) } else { imageCell?.image = NCBrandColor.cacheImages.file } } - + fileNameCell?.text = fileName - + let fileSize = NCUtilityFileSystem.shared.getFileSize(filePath: (NSTemporaryDirectory() + fileName)) sizeCell?.text = CCUtility.transformedSize(fileSize) - + moreButton?.setImage(NCUtility.shared.loadImage(named: "more").image(color: NCBrandColor.shared.label, size: 15), for: .normal) moreButton?.indexPath = indexPath moreButton?.fileName = fileName moreButton?.image = imageCell?.image moreButton?.action(for: .touchUpInside, { sender in - + if let fileName = (sender as! NCShareExtensionButtonWithIndexPath).fileName { let alertController = UIAlertController(title: "", message: fileName, preferredStyle: .alert) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_delete_file_", comment: ""), style: .default) { (action:UIAlertAction) in + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_delete_file_", comment: ""), style: .default) { (_: UIAlertAction) in if let index = self.filesName.firstIndex(of: fileName) { - + self.filesName.remove(at: index) if self.filesName.count == 0 { self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil) @@ -687,27 +687,27 @@ extension NCShareExtension: UITableViewDataSource { } } }) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_rename_file_", comment: ""), style: .default) { (action:UIAlertAction) in - + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_rename_file_", comment: ""), style: .default) { (_: UIAlertAction) in + if let vcRename = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile { - + vcRename.delegate = self vcRename.fileName = fileName vcRename.imagePreview = (sender as! NCShareExtensionButtonWithIndexPath).image let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height) - + self.present(popup, animated: true) } }) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { (action:UIAlertAction) in }) - - self.present(alertController, animated: true, completion:nil) + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { (_: UIAlertAction) in }) + + self.present(alertController, animated: true, completion: nil) } }) - + return cell } } @@ -717,34 +717,34 @@ extension NCShareExtension: UITableViewDataSource { extension NCShareExtension { @objc func reloadDatasource(withLoadFolder: Bool) { - + layoutForView = NCUtility.shared.getLayoutForView(key: keyLayout, serverUrl: serverUrl) - + let metadatasSource = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND directory == true", activeAccount.account, serverUrl)) - self.dataSource = NCDataSource.init(metadatasSource: metadatasSource, sort: layoutForView?.sort, ascending: layoutForView?.ascending, directoryOnTop: layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) - + self.dataSource = NCDataSource(metadatasSource: metadatasSource, sort: layoutForView?.sort, ascending: layoutForView?.ascending, directoryOnTop: layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) + if withLoadFolder { loadFolder() } else { self.refreshControl.endRefreshing() } - + collectionView.reloadData() } - + func createFolder(with fileName: String) { - - NCNetworking.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: activeAccount.account, urlBase: activeAccount.urlBase) { (errorCode, errorDescription) in - + + NCNetworking.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: activeAccount.account, urlBase: activeAccount.urlBase) { errorCode, errorDescription in + DispatchQueue.main.async { if errorCode == 0 { - - self.serverUrl = self.serverUrl + "/" + fileName + + self.serverUrl += "/" + fileName self.reloadDatasource(withLoadFolder: true) self.setNavigationBar(navigationTitle: fileName) - - } else { - + + } else { + let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: errorDescription, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) self.present(alertController, animated: true) @@ -752,14 +752,14 @@ extension NCShareExtension { } } } - + func loadFolder() { - + networkInProgress = true collectionView.reloadData() - - NCNetworking.shared.readFolder(serverUrl: serverUrl, account: activeAccount.account) { (_, metadataFolder, _, _, _, _, errorCode, errorDescription) in - + + NCNetworking.shared.readFolder(serverUrl: serverUrl, account: activeAccount.account) { _, metadataFolder, _, _, _, _, errorCode, errorDescription in + DispatchQueue.main.async { if errorCode != 0 { let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: errorDescription, preferredStyle: .alert) @@ -772,42 +772,42 @@ extension NCShareExtension { } } } - - func getFilesExtensionContext(completion: @escaping (_ filesName: [String])->()) { - + + func getFilesExtensionContext(completion: @escaping (_ filesName: [String]) -> Void) { + var itemsProvider: [NSItemProvider] = [] var filesName: [String] = [] var conuter = 0 let dateFormatter = DateFormatter() - + // ---------------------------------------------------------------------------------------- // Image func getItem(image: UIImage, fileNameOriginal: String?) { - + var fileName: String = "" - + if let pngImageData = image.pngData() { - + if fileNameOriginal != nil { fileName = fileNameOriginal! } else { fileName = "\(dateFormatter.string(from: Date()))\(conuter).png" } - + let filenamePath = NSTemporaryDirectory() + fileName - + if (try? pngImageData.write(to: URL(fileURLWithPath: filenamePath), options: [.atomic])) != nil { filesName.append(fileName) } } } - + // URL func getItem(url: NSURL, fileNameOriginal: String?) { - + guard let path = url.path else { return } - + var fileName: String = "" if fileNameOriginal != nil { @@ -817,37 +817,36 @@ extension NCShareExtension { fileName = "\(dateFormatter.string(from: Date()))\(conuter)." + ext } } - + let filenamePath = NSTemporaryDirectory() + fileName - + do { try FileManager.default.removeItem(atPath: filenamePath) - } - catch { } - + } catch { } + do { - try FileManager.default.copyItem(atPath: path, toPath:filenamePath) - + try FileManager.default.copyItem(atPath: path, toPath: filenamePath) + do { - let attr : NSDictionary? = try FileManager.default.attributesOfItem(atPath: filenamePath) as NSDictionary? - + let attr: NSDictionary? = try FileManager.default.attributesOfItem(atPath: filenamePath) as NSDictionary? + if let _attr = attr { if _attr.fileSize() > 0 { filesName.append(fileName) } } - + } catch { } } catch { } } - + // Data func getItem(data: Data, fileNameOriginal: String?, description: String) { - + var fileName: String = "" if data.count > 0 { - + if fileNameOriginal != nil { fileName = fileNameOriginal! } else { @@ -856,34 +855,34 @@ extension NCShareExtension { let pathExtention = (fileExtArr[fileExtArr.count-1]).uppercased() fileName = "\(dateFormatter.string(from: Date()))\(conuter).\(pathExtention)" } - + let filenamePath = NSTemporaryDirectory() + fileName - FileManager.default.createFile(atPath: filenamePath, contents:data, attributes:nil) + FileManager.default.createFile(atPath: filenamePath, contents: data, attributes: nil) filesName.append(fileName) } } - + // String func getItem(string: NSString, fileNameOriginal: String?) { - + var fileName: String = "" - + if string.length > 0 { - + fileName = "\(dateFormatter.string(from: Date()))\(conuter).txt" let filenamePath = NSTemporaryDirectory() + "\(dateFormatter.string(from: Date()))\(conuter).txt" - FileManager.default.createFile(atPath: filenamePath, contents:string.data(using: String.Encoding.utf8.rawValue), attributes:nil) + FileManager.default.createFile(atPath: filenamePath, contents: string.data(using: String.Encoding.utf8.rawValue), attributes: nil) filesName.append(fileName) } } - + // ---------------------------------------------------------------------------------------- - - guard let inputItems : [NSExtensionItem] = extensionContext?.inputItems as? [NSExtensionItem] else { + + guard let inputItems: [NSExtensionItem] = extensionContext?.inputItems as? [NSExtensionItem] else { return completion(filesName) } - - for item : NSExtensionItem in inputItems { + + for item: NSExtensionItem in inputItems { if let attachments = item.attachments { if attachments.isEmpty { continue } for (_, itemProvider) in (attachments.enumerated()) { @@ -893,18 +892,18 @@ extension NCShareExtension { } } } - + CCUtility.emptyTemporaryDirectory() dateFormatter.dateFormat = "yyyy-MM-dd HH-mm-ss-" - + for itemProvider in itemsProvider { - + var typeIdentifier = "" if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeItem as String) { typeIdentifier = kUTTypeItem as String } if itemProvider.hasItemConformingToTypeIdentifier("public.url") { typeIdentifier = "public.url" } - itemProvider.loadItem(forTypeIdentifier: typeIdentifier, options: nil, completionHandler: {(item, error) -> Void in - + itemProvider.loadItem(forTypeIdentifier: typeIdentifier, options: nil, completionHandler: {item, error -> Void in + if error == nil { var fileNameOriginal: String? @@ -918,24 +917,24 @@ extension NCShareExtension { fileNameOriginal = "\(dateFormatter.string(from: Date()))\(conuter)" } } - + if let image = item as? UIImage { getItem(image: image, fileNameOriginal: fileNameOriginal) } - + if let url = item as? URL { getItem(url: url as NSURL, fileNameOriginal: fileNameOriginal) } - + if let data = item as? Data { getItem(data: data, fileNameOriginal: fileNameOriginal, description: itemProvider.description) } - + if let string = item as? NSString { getItem(string: string, fileNameOriginal: fileNameOriginal) } } - + conuter += 1 if conuter == itemsProvider.count { completion(filesName) @@ -994,7 +993,7 @@ task.resume() */ class NCShareExtensionButtonWithIndexPath: UIButton { - var indexPath:IndexPath? + var indexPath: IndexPath? var fileName: String? var image: UIImage? } diff --git a/iOSClient/Activity/NCActivity.swift b/iOSClient/Activity/NCActivity.swift index c71b07cc5..ab6354cfd 100644 --- a/iOSClient/Activity/NCActivity.swift +++ b/iOSClient/Activity/NCActivity.swift @@ -54,7 +54,7 @@ class NCActivity: UIViewController { var hasActivityToLoad = true { didSet { tableView.tableFooterView?.isHidden = hasActivityToLoad } } - var dateAutomaticFetch : Date? + var dateAutomaticFetch: Date? // MARK: - View Life Cycle @@ -82,7 +82,7 @@ class NCActivity: UIViewController { } func setupComments() { - tableView.register(UINib.init(nibName: "NCShareCommentsCell", bundle: nil), forCellReuseIdentifier: "cell") + tableView.register(UINib(nibName: "NCShareCommentsCell", bundle: nil), forCellReuseIdentifier: "cell") newCommentField.placeholder = NSLocalizedString("_new_comment_", comment: "") viewContainerConstraint.constant = height @@ -92,7 +92,7 @@ class NCActivity: UIViewController { commentView.isHidden = true return } - + let fileName = appDelegate.userBaseUrl + "-" + appDelegate.user + ".png" let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName if let image = UIImage(contentsOfFile: fileNameLocalPath) { @@ -100,7 +100,7 @@ class NCActivity: UIViewController { } else { imageItem.image = UIImage(named: "avatar") } - + if activeAccount.displayName.isEmpty { labelUser.text = activeAccount.user } else { @@ -108,14 +108,14 @@ class NCActivity: UIViewController { } labelUser.textColor = NCBrandColor.shared.label } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + appDelegate.activeViewController = self NotificationCenter.default.addObserver(self, selector: #selector(initialize), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil) - + initialize() } @@ -139,7 +139,7 @@ class NCActivity: UIViewController { @objc func changeTheming() { tableView.reloadData() } - + @IBAction func newCommentFieldDidEndOnExit(textField: UITextField) { guard let message = textField.text, @@ -147,7 +147,7 @@ class NCActivity: UIViewController { let metadata = self.metadata else { return } - NCCommunication.shared.putComments(fileId: metadata.fileId, message: message) { (account, errorCode, errorDescription) in + NCCommunication.shared.putComments(fileId: metadata.fileId, message: message) { _, errorCode, errorDescription in if errorCode == 0 { self.newCommentField.text = "" self.loadComments() @@ -177,19 +177,19 @@ class NCActivity: UIViewController { // MARK: - Table View extension NCActivity: UITableViewDelegate { - + func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { return 120 } - + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 60 } - + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return UITableView.automaticDimension } - + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 60)) @@ -237,16 +237,16 @@ extension NCActivity: UITableViewDataSource { return UITableViewCell() } } - + func makeCommentCell(_ comment: tableComments, for indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? NCShareCommentsCell else { return UITableViewCell() } - + cell.tableComments = comment cell.delegate = self cell.sizeToFit() - + // Image let fileName = appDelegate.userBaseUrl + "-" + comment.actorId + ".png" NCOperationQueue.shared.downloadAvatar(user: comment.actorId, dispalyName: comment.actorDisplayName, fileName: fileName, cell: cell, view: tableView) @@ -265,37 +265,37 @@ extension NCActivity: UITableViewDataSource { } else { cell.buttonMenu.isHidden = true } - + return cell } - + func makeActivityCell(_ activity: tableActivity, for indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as? NCActivityTableViewCell else { return UITableViewCell() } - + var orderKeysId: [String] = [] - + cell.idActivity = activity.idActivity - + cell.avatar.image = nil cell.avatar.isHidden = true cell.subjectTrailingConstraint.constant = 10 cell.didSelectItemEnable = self.didSelectItemEnable cell.subject.textColor = NCBrandColor.shared.label cell.viewController = self - + // icon if activity.icon.count > 0 { - + let fileNameIcon = (activity.icon as NSString).lastPathComponent let fileNameLocalPath = CCUtility.getDirectoryUserData() + "/" + fileNameIcon - + if FileManager.default.fileExists(atPath: fileNameLocalPath) { let image = NCUtility.shared.loadImage(named: fileNameIcon, color: NCBrandColor.shared.gray) cell.icon.image = image } else { - NCCommunication.shared.downloadContent(serverUrl: activity.icon) { (account, data, errorCode, errorMessage) in + NCCommunication.shared.downloadContent(serverUrl: activity.icon) { _, data, errorCode, _ in if errorCode == 0 { do { try data!.write(to: NSURL(fileURLWithPath: fileNameLocalPath) as URL, options: .atomic) @@ -305,39 +305,39 @@ extension NCActivity: UITableViewDataSource { } } } - + // avatar if activity.user.count > 0 && activity.user != appDelegate.userId { - + cell.subjectTrailingConstraint.constant = 50 cell.avatar.isHidden = false cell.fileUser = activity.user - + let fileName = appDelegate.userBaseUrl + "-" + activity.user + ".png" - + NCOperationQueue.shared.downloadAvatar(user: activity.user, dispalyName: nil, fileName: fileName, cell: cell, view: tableView) } - + // subject if activity.subjectRich.count > 0 { - + var subject = activity.subjectRich var keys: [String] = [] - + if let regex = try? NSRegularExpression(pattern: "\\{[a-z0-9]+\\}", options: .caseInsensitive) { let string = subject as NSString keys = regex.matches(in: subject, options: [], range: NSRange(location: 0, length: string.length)).map { string.substring(with: $0.range).replacingOccurrences(of: "[\\{\\}]", with: "", options: .regularExpression) } } - + for key in keys { if let result = NCManageDatabase.shared.getActivitySubjectRich(account: appDelegate.account, idActivity: activity.idActivity, key: key) { orderKeysId.append(result.id) subject = subject.replacingOccurrences(of: "{\(key)}", with: "<bold>" + result.name + "</bold>") } } - + let normal = Style { $0.font = UIFont.systemFont(ofSize: cell.subject.font.pointSize) $0.lineSpacing = 1.5 @@ -346,11 +346,11 @@ extension NCActivity: UITableViewDataSource { let date = Style { $0.font = UIFont.systemFont(ofSize: cell.subject.font.pointSize - 3) $0.color = UIColor.lightGray } - - subject = subject + "\n" + "<date>" + CCUtility.dateDiff(activity.date as Date) + "</date>" + + subject += "\n" + "<date>" + CCUtility.dateDiff(activity.date as Date) + "</date>" cell.subject.attributedText = subject.set(style: StyleGroup(base: normal, ["bold": bold, "date": date])) } - + // CollectionView cell.activityPreviews = NCManageDatabase.shared.getActivityPreview(account: activity.account, idActivity: activity.idActivity, orderKeysId: orderKeysId) if cell.activityPreviews.count == 0 { @@ -359,7 +359,7 @@ extension NCActivity: UITableViewDataSource { cell.collectionViewHeightConstraint.constant = 60 } cell.collectionView.reloadData() - + return cell } } @@ -406,7 +406,7 @@ extension NCActivity { } } } - + func loadDataSource() { var newItems = [DateCompareable]() @@ -427,12 +427,12 @@ extension NCActivity { }.sorted(by: >) self.tableView.reloadData() } - + func loadComments(disptachGroup: DispatchGroup? = nil) { guard showComments, let metadata = metadata else { return } disptachGroup?.enter() - NCCommunication.shared.getComments(fileId: metadata.fileId) { (account, comments, errorCode, errorDescription) in + NCCommunication.shared.getComments(fileId: metadata.fileId) { account, comments, errorCode, errorDescription in if errorCode == 0, let comments = comments { NCManageDatabase.shared.addComments(comments, account: metadata.account, objectId: metadata.fileId) } else if errorCode != NCGlobal.shared.errorResourceNotFound { @@ -462,7 +462,7 @@ extension NCActivity { limit: 1, objectId: nil, objectType: objectType, - previews: true) { (account, activities, errorCode, errorDescription) in + previews: true) { account, activities, errorCode, _ in defer { disptachGroup.leave() } guard errorCode == 0, @@ -488,7 +488,7 @@ extension NCActivity { limit: min(limit, 200), objectId: metadata?.fileId, objectType: objectType, - previews: true) { (account, activities, errorCode, errorDescription) in + previews: true) { account, activities, errorCode, _ in defer { disptachGroup.leave() } guard errorCode == 0, account == self.appDelegate.account, @@ -526,20 +526,20 @@ extension NCActivity: NCShareCommentsCellDelegate { NCMenuAction( title: NSLocalizedString("_edit_comment_", comment: ""), icon: UIImage(named: "edit")!.image(color: NCBrandColor.shared.gray, size: 50), - action: { menuAction in + action: { _ in guard let metadata = self.metadata, let tableComments = tableComments else { return } - + let alert = UIAlertController(title: NSLocalizedString("_edit_comment_", comment: ""), message: nil, preferredStyle: .alert) alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil)) - + alert.addTextField(configurationHandler: { textField in textField.placeholder = NSLocalizedString("_new_comment_", comment: "") }) - - alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { action in + + alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in guard let message = alert.textFields?.first?.text, message != "" else { return } - NCCommunication.shared.updateComments(fileId: metadata.fileId, messageId: tableComments.messageId, message: message) { (account, errorCode, errorDescription) in + NCCommunication.shared.updateComments(fileId: metadata.fileId, messageId: tableComments.messageId, message: message) { _, errorCode, errorDescription in if errorCode == 0 { self.loadComments() } else { @@ -552,15 +552,15 @@ extension NCActivity: NCShareCommentsCellDelegate { } ) ) - + actions.append( NCMenuAction( title: NSLocalizedString("_delete_comment_", comment: ""), icon: NCUtility.shared.loadImage(named: "trash"), - action: { menuAction in + action: { _ in guard let metadata = self.metadata, let tableComments = tableComments else { return } - NCCommunication.shared.deleteComments(fileId: metadata.fileId, messageId: tableComments.messageId) { (account, errorCode, errorDescription) in + NCCommunication.shared.deleteComments(fileId: metadata.fileId, messageId: tableComments.messageId) { _, errorCode, errorDescription in if errorCode == 0 { self.loadComments() } else { @@ -574,4 +574,3 @@ extension NCActivity: NCShareCommentsCellDelegate { presentMenu(with: actions) } } - diff --git a/iOSClient/Activity/NCActivityTableViewCell.swift b/iOSClient/Activity/NCActivityTableViewCell.swift index 77e1cd155..0136e195a 100644 --- a/iOSClient/Activity/NCActivityTableViewCell.swift +++ b/iOSClient/Activity/NCActivityTableViewCell.swift @@ -25,16 +25,16 @@ import Foundation import NCCommunication class NCActivityCollectionViewCell: UICollectionViewCell { - + @IBOutlet weak var imageView: UIImageView! - + override func awakeFromNib() { super.awakeFromNib() } } class NCActivityTableViewCell: UITableViewCell, NCCellProtocol { - + private let appDelegate = UIApplication.shared.delegate as! AppDelegate @IBOutlet weak var collectionView: UICollectionView! @@ -50,8 +50,8 @@ class NCActivityTableViewCell: UITableViewCell, NCCellProtocol { var account: String = "" var activityPreviews: [tableActivityPreview] = [] var didSelectItemEnable: Bool = true - var viewController: UIViewController? = nil - + var viewController: UIViewController? + var fileAvatarImageView: UIImageView? { get { return avatar @@ -94,20 +94,20 @@ class NCActivityTableViewCell: UITableViewCell, NCCellProtocol { // MARK: - Collection View extension NCActivityTableViewCell: UICollectionViewDelegate { - + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - + // Select not permitted if !didSelectItemEnable { return } - + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath) as? NCActivityCollectionViewCell - + let activityPreview = activityPreviews[indexPath.row] - + if activityPreview.view == "trashbin" { - + var responder: UIResponder? = collectionView while !(responder is UIViewController) { responder = responder?.next @@ -116,7 +116,7 @@ extension NCActivityTableViewCell: UICollectionViewDelegate { } } if (responder as? UIViewController)!.navigationController != nil { - if let viewController = UIStoryboard.init(name: "NCTrash", bundle: nil).instantiateInitialViewController() as? NCTrash { + if let viewController = UIStoryboard(name: "NCTrash", bundle: nil).instantiateInitialViewController() as? NCTrash { if let result = NCManageDatabase.shared.getTrashItem(fileId: String(activityPreview.fileId), account: activityPreview.account) { viewController.blinkFileId = result.fileId viewController.trashPath = result.filePath @@ -126,16 +126,16 @@ extension NCActivityTableViewCell: UICollectionViewDelegate { } } } - + return } - + if activityPreview.view == "files" && activityPreview.mimeType != "dir" { - + guard let activitySubjectRich = NCManageDatabase.shared.getActivitySubjectRich(account: activityPreview.account, idActivity: activityPreview.idActivity, id: String(activityPreview.fileId)) else { return } - + if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "fileId == %@", activitySubjectRich.id)) { if let filePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView) { do { @@ -152,51 +152,51 @@ extension NCActivityTableViewCell: UICollectionViewDelegate { } } } - + var pathComponents = activityPreview.link.components(separatedBy: "?") pathComponents = pathComponents[1].components(separatedBy: "&") var serverUrlFileName = pathComponents[0].replacingOccurrences(of: "dir=", with: "").removingPercentEncoding! serverUrlFileName = appDelegate.urlBase + "/" + NCUtilityFileSystem.shared.getWebDAV(account: activityPreview.account) + serverUrlFileName + "/" + activitySubjectRich.name - + let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(activitySubjectRich.id, fileNameView: activitySubjectRich.name)! - + NCUtility.shared.startActivityIndicator(backgroundView: (appDelegate.window?.rootViewController?.view)!, blurEffect: true) - - NCCommunication.shared.download(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, requestHandler: { (_) in - - }, taskHandler: { (_) in - - }, progressHandler: { (_) in - - }) { (account, etag, date, lenght, allHeaderFields, error, errorCode, errorDescription) in - + + NCCommunication.shared.download(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, requestHandler: { _ in + + }, taskHandler: { _ in + + }, progressHandler: { _ in + + }) { account, _, _, _, _, _, errorCode, _ in + if account == self.appDelegate.account && errorCode == 0 { - + let serverUrl = (serverUrlFileName as NSString).deletingLastPathComponent let fileName = (serverUrlFileName as NSString).lastPathComponent let serverUrlFileName = serverUrl + "/" + fileName - - NCNetworking.shared.readFile(serverUrlFileName: serverUrlFileName, account: activityPreview.account) { (account, metadata, errorCode, errorDescription) in - + + NCNetworking.shared.readFile(serverUrlFileName: serverUrlFileName, account: activityPreview.account) { account, metadata, errorCode, _ in + NCUtility.shared.stopActivityIndicator() - - if account == self.appDelegate.account && errorCode == 0 { - + + if account == self.appDelegate.account && errorCode == 0 { + // move from id to oc:id + instanceid (ocId) let atPath = CCUtility.getDirectoryProviderStorage()! + "/" + activitySubjectRich.id let toPath = CCUtility.getDirectoryProviderStorage()! + "/" + metadata!.ocId - + CCUtility.moveFile(atPath: atPath, toPath: toPath) - + NCManageDatabase.shared.addMetadata(metadata!) if let viewController = self.viewController { NCViewer.shared.view(viewController: viewController, metadata: metadata!, metadatas: [metadata!], imageIcon: cell?.imageView.image) } } } - + } else { - + NCUtility.shared.stopActivityIndicator() } } @@ -205,70 +205,70 @@ extension NCActivityTableViewCell: UICollectionViewDelegate { } extension NCActivityTableViewCell: UICollectionViewDataSource { - + func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } - + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return activityPreviews.count } - + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - + let cell: NCActivityCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath) as! NCActivityCollectionViewCell - + cell.imageView.image = nil - + let activityPreview = activityPreviews[indexPath.row] let fileId = String(activityPreview.fileId) - + // Trashbin if activityPreview.view == "trashbin" { - + let source = activityPreview.source - - NCUtility.shared.convertSVGtoPNGWriteToUserData(svgUrlString: source, fileName: nil, width: 100, rewrite: false, account: appDelegate.account) { (imageNamePath) in + + NCUtility.shared.convertSVGtoPNGWriteToUserData(svgUrlString: source, fileName: nil, width: 100, rewrite: false, account: appDelegate.account) { imageNamePath in if imageNamePath != nil { if let image = UIImage(contentsOfFile: imageNamePath!) { cell.imageView.image = image } } else { - cell.imageView.image = UIImage.init(named: "file") + cell.imageView.image = UIImage(named: "file") } } - + } else { - + if activityPreview.isMimeTypeIcon { - + let source = activityPreview.source - - NCUtility.shared.convertSVGtoPNGWriteToUserData(svgUrlString: source, fileName: nil, width: 100, rewrite: false, account: appDelegate.account) { (imageNamePath) in + + NCUtility.shared.convertSVGtoPNGWriteToUserData(svgUrlString: source, fileName: nil, width: 100, rewrite: false, account: appDelegate.account) { imageNamePath in if imageNamePath != nil { if let image = UIImage(contentsOfFile: imageNamePath!) { cell.imageView.image = image } } else { - cell.imageView.image = UIImage.init(named: "file") + cell.imageView.image = UIImage(named: "file") } } - + } else { - + if let activitySubjectRich = NCManageDatabase.shared.getActivitySubjectRich(account: account, idActivity: idActivity, id: fileId) { - + let fileNamePath = CCUtility.getDirectoryUserData() + "/" + activitySubjectRich.name - + if FileManager.default.fileExists(atPath: fileNamePath) { - + if let image = UIImage(contentsOfFile: fileNamePath) { cell.imageView.image = image } - + } else { - - NCCommunication.shared.downloadPreview(fileNamePathOrFileId: activityPreview.source, fileNamePreviewLocalPath: fileNamePath, widthPreview: 0, heightPreview: 0, etag: nil, useInternalEndpoint: false) { (account, imagePreview, imageIcon, imageOriginal, etag, errorCode, errorDescription) in + + NCCommunication.shared.downloadPreview(fileNamePathOrFileId: activityPreview.source, fileNamePreviewLocalPath: fileNamePath, widthPreview: 0, heightPreview: 0, etag: nil, useInternalEndpoint: false) { _, imagePreview, _, _, _, errorCode, _ in if errorCode == 0 && imagePreview != nil { self.collectionView.reloadData() } @@ -277,22 +277,22 @@ extension NCActivityTableViewCell: UICollectionViewDataSource { } } } - + return cell } - + } extension NCActivityTableViewCell: UICollectionViewDelegateFlowLayout { - + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: 50, height: 50) } - + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return 20 } - + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { return UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0) } diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index eb3351d95..452f63e46 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -51,54 +51,55 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD @objc var activeViewController: UIViewController? var mainTabBar: NCMainTabBar? var activeMetadata: tableMetadata? - - var listFilesVC: [String:NCFiles] = [:] - var listFavoriteVC: [String:NCFavorite] = [:] - var listOfflineVC: [String:NCOffline] = [:] - var listProgress: [String:NCGlobal.progressType] = [:] - + + var listFilesVC: [String: NCFiles] = [:] + var listFavoriteVC: [String: NCFavorite] = [:] + var listOfflineVC: [String: NCOffline] = [:] + var listProgress: [String: NCGlobal.progressType] = [:] + var disableSharesView: Bool = false var documentPickerViewController: NCDocumentPickerViewController? var networkingProcessUpload: NCNetworkingProcessUpload? - var passcodeViewController: TOPasscodeViewController? var pasteboardOcIds: [String] = [] var shares: [tableShare] = [] var timerErrorNetworking: Timer? + private var privacyProtectionWindow: UIWindow? + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - + let userAgent = CCUtility.getUserAgent() as String let isSimulatorOrTestFlight = NCUtility.shared.isSimulatorOrTestFlight() let versionNextcloudiOS = String(format: NCBrandOptions.shared.textCopyrightNextcloudiOS, NCUtility.shared.getVersionApp()) - UserDefaults.standard.register(defaults: ["UserAgent" : userAgent]) + UserDefaults.standard.register(defaults: ["UserAgent": userAgent]) if !CCUtility.getDisableCrashservice() && !NCBrandOptions.shared.disable_crash_service { FirebaseApp.configure() } - + CCUtility.createDirectoryStandard() CCUtility.emptyTemporaryDirectory() - + NCCommunicationCommon.shared.setup(delegate: NCNetworking.shared) NCCommunicationCommon.shared.setup(userAgent: userAgent) - + startTimerErrorNetworking() - + // LOG var levelLog = 0 if let pathDirectoryGroup = CCUtility.getDirectoryGroup()?.path { NCCommunicationCommon.shared.pathLog = pathDirectoryGroup } - + if NCBrandOptions.shared.disable_log { - + NCUtilityFileSystem.shared.deleteFile(filePath: NCCommunicationCommon.shared.filenamePathLog) NCUtilityFileSystem.shared.deleteFile(filePath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/" + NCCommunicationCommon.shared.filenameLog) - + } else { - + levelLog = CCUtility.getLogLevel() - NCCommunicationCommon.shared.levelLog = levelLog + NCCommunicationCommon.shared.levelLog = levelLog NCCommunicationCommon.shared.copyLogToDocumentDirectory = true if isSimulatorOrTestFlight { NCCommunicationCommon.shared.writeLog("Start session with level \(levelLog) " + versionNextcloudiOS + " (Simulator / TestFlight)") @@ -106,10 +107,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD NCCommunicationCommon.shared.writeLog("Start session with level \(levelLog) " + versionNextcloudiOS) } } - + // Activate user account if let activeAccount = NCManageDatabase.shared.getActiveAccount() { - + // FIX 3.0.5 lost urlbase if activeAccount.urlBase.count == 0 { let user = activeAccount.user + " " @@ -117,28 +118,28 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD activeAccount.urlBase = urlBase NCManageDatabase.shared.updateAccount(activeAccount) } - + settingAccount(activeAccount.account, urlBase: activeAccount.urlBase, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account)) - + } else { - + CCUtility.deleteAllChainStore() if let bundleID = Bundle.main.bundleIdentifier { UserDefaults.standard.removePersistentDomain(forName: bundleID) } } - + // initialize NotificationCenter.default.addObserver(self, selector: #selector(initialize), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil) NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterInitialize) - + // Process upload - networkingProcessUpload = NCNetworkingProcessUpload.init() - + networkingProcessUpload = NCNetworkingProcessUpload() + // Push Notification & display notification application.registerForRemoteNotifications() UNUserNotificationCenter.current().delegate = self - UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (_, _) in } + UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { _, _ in } // Store review if !NCUtility.shared.isSimulatorOrTestFlight() { @@ -146,7 +147,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD review.incrementAppRuns() review.showStoreReview() } - + // Background task: register if #available(iOS 13.0, *) { BGTaskScheduler.shared.register(forTaskWithIdentifier: NCGlobal.shared.refreshTask, using: nil) { task in @@ -158,7 +159,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } else { application.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum) } - + // Intro if NCBrandOptions.shared.disable_intro { CCUtility.setIntro(true) @@ -168,70 +169,77 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } else { if !CCUtility.getIntro() { if let viewController = UIStoryboard(name: "NCIntro", bundle: nil).instantiateInitialViewController() { - let navigationController = UINavigationController(rootViewController: viewController) + let navigationController = NCLoginNavigationController.init(rootViewController: viewController) window?.rootViewController = navigationController window?.makeKeyAndVisible() } } } - + // Passcode DispatchQueue.main.async { - self.passcodeWithAutomaticallyPromptForBiometricValidation(true) + self.presentPasscode { + self.enableTouchFaceID() + } } - + return true } - + // MARK: - Life Cycle // L' applicazione entrerà in primo piano (attivo sempre) func applicationDidBecomeActive(_ application: UIApplication) { + // Privacy + hidePrivacyProtectionWindow() + NCSettingsBundleHelper.setVersionAndBuildNumber() + NCSettingsBundleHelper.setVersionAndBuildNumber() + if account == "" { return } networkingProcessUpload?.verifyUploadZombie() - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterApplicationDidBecomeActive) } - + // L' applicazione entrerà in primo piano (attivo solo dopo il background) func applicationWillEnterForeground(_ application: UIApplication) { - + if account == "" { return } guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return } - + // close HUD IHProgressHUD.dismiss() - + // Account changed ?? if activeAccount.account != account { settingAccount(activeAccount.account, urlBase: activeAccount.urlBase, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account)) - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterInitialize) } - + NCCommunicationCommon.shared.writeLog("Application will enter in foreground") - + // START TIMER UPLOAD PROCESS if NCUtility.shared.isSimulator() { networkingProcessUpload?.startTimer() } - // Request Passcode - passcodeWithAutomaticallyPromptForBiometricValidation(true) - // Initialize Auto upload - NCAutoUpload.shared.initAutoUpload(viewController: nil) { (_) in } - + NCAutoUpload.shared.initAutoUpload(viewController: nil) { _ in } + // Required unsubscribing / subscribing NCPushNotification.shared().pushNotification() - + // Request Service Server Nextcloud NCService.shared.startRequestServicesServer() + // Request TouchID, FaceID + enableTouchFaceID() + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterApplicationWillEnterForeground) NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterRichdocumentGrabFocus) NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced) @@ -239,16 +247,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // L' applicazione si dimetterà dallo stato di attivo func applicationWillResignActive(_ application: UIApplication) { - + if account == "" { return } - - // Dismiss FileViewInFolder - if activeFileViewInFolder != nil { - activeFileViewInFolder?.dismiss(animated: false, completion: { - self.activeFileViewInFolder = nil - }) - } - + + // Privacy + showPrivacyProtectionWindow() + // Clear operation queue NCOperationQueue.shared.cancelAllQueue() // Clear download @@ -259,77 +263,73 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD if let directory = CCUtility.getDirectoryProviderStorage() { NCUtilityFileSystem.shared.cleanUp(directory: directory, days: TimeInterval(days)) } - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterApplicationWillResignActive) } - + // L' applicazione è entrata nello sfondo func applicationDidEnterBackground(_ application: UIApplication) { - + if account == "" { return } // STOP TIMER UPLOAD PROCESS if NCUtility.shared.isSimulator() { networkingProcessUpload?.stopTimer() } - - NCCommunicationCommon.shared.writeLog("Application did enter in background") - - passcodeWithAutomaticallyPromptForBiometricValidation(false) - + if #available(iOS 13.0, *) { scheduleAppRefresh() scheduleBackgroundProcessing() } + // Passcode + presentPasscode { } + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterApplicationDidEnterBackground) } - + // L'applicazione terminerà func applicationWillTerminate(_ application: UIApplication) { - + NCNetworking.shared.cancelAllDownloadTransfer() NCCommunicationCommon.shared.writeLog("bye bye") } - + // MARK: - @objc private func initialize() { - + if account == "" { return } NCCommunicationCommon.shared.writeLog("initialize Main") - - // Clear error certificate - NCNetworking.shared.certificatesError = nil - + // Registeration push notification NCPushNotification.shared().pushNotification() - + // Setting Theming NCBrandColor.shared.settingThemingColor(account: account) - + // Start Auto Upload - NCAutoUpload.shared.initAutoUpload(viewController: nil) { (_) in } - + NCAutoUpload.shared.initAutoUpload(viewController: nil) { _ in } + // Start services NCService.shared.startRequestServicesServer() - + // close detail NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterMenuDetailClose) - + // Registeration domain File Provider - //FileProviderDomain *fileProviderDomain = [FileProviderDomain new]; - //[fileProviderDomain removeAllDomains]; - //[fileProviderDomain registerDomains]; + // FileProviderDomain *fileProviderDomain = [FileProviderDomain new]; + // [fileProviderDomain removeAllDomains]; + // [fileProviderDomain registerDomains]; } - + // MARK: - Background Task - + @available(iOS 13.0, *) func scheduleAppRefresh() { - - let request = BGAppRefreshTaskRequest.init(identifier: NCGlobal.shared.refreshTask) + + let request = BGAppRefreshTaskRequest(identifier: NCGlobal.shared.refreshTask) request.earliestBeginDate = Date(timeIntervalSinceNow: 5 * 60) // Refresh after 5 minutes. do { try BGTaskScheduler.shared.submit(request) @@ -338,11 +338,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD NCCommunicationCommon.shared.writeLog("Refresh task failed to submit request: \(error)") } } - + @available(iOS 13.0, *) func scheduleBackgroundProcessing() { - - let request = BGProcessingTaskRequest.init(identifier: NCGlobal.shared.processingTask) + + let request = BGProcessingTaskRequest(identifier: NCGlobal.shared.processingTask) request.earliestBeginDate = Date(timeIntervalSinceNow: 5 * 60) // Refresh after 5 minutes. request.requiresNetworkConnectivity = true request.requiresExternalPower = false @@ -353,18 +353,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD NCCommunicationCommon.shared.writeLog("Background Processing task failed to submit request: \(error)") } } - + @available(iOS 13.0, *) func handleRefreshTask(_ task: BGTask) { - + if account == "" { task.setTaskCompleted(success: true) return } - + NCCommunicationCommon.shared.writeLog("Start handler refresh task [Auto upload]") - - NCAutoUpload.shared.initAutoUpload(viewController: nil) { (items) in + + NCAutoUpload.shared.initAutoUpload(viewController: nil) { _ in DispatchQueue.main.asyncAfter(deadline: .now() + 5) { NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUpdateBadgeNumber) NCCommunicationCommon.shared.writeLog("Completition handler refresh task with %lu uploads [Auto upload]") @@ -372,42 +372,42 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } } - + @available(iOS 13.0, *) func handleProcessingTask(_ task: BGTask) { - + if account == "" { task.setTaskCompleted(success: true) return } - + NCCommunicationCommon.shared.writeLog("Start handler processing task [Synchronize Favorite & Offline]") - - NCNetworking.shared.listingFavoritescompletion(selector: NCGlobal.shared.selectorReadFile) { (account, metadatas, errorCode, errorDescription) in + + NCNetworking.shared.listingFavoritescompletion(selector: NCGlobal.shared.selectorReadFile) { _, _, errorCode, _ in NCCommunicationCommon.shared.writeLog("Completition listing favorite with error: \(errorCode)") } - + NCService.shared.synchronizeOffline(account: account) - + DispatchQueue.main.asyncAfter(deadline: .now() + 25) { NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUpdateBadgeNumber) NCCommunicationCommon.shared.writeLog("Completition handler processing task [Synchronize Favorite & Offline]") task.setTaskCompleted(success: true) } } - + // MARK: - Fetch func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { - + if account == "" { completionHandler(UIBackgroundFetchResult.noData) return } - + NCCommunicationCommon.shared.writeLog("Start perform Fetch [Auto upload]") - - NCAutoUpload.shared.initAutoUpload(viewController: nil) { (items) in + + NCAutoUpload.shared.initAutoUpload(viewController: nil) { items in NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUpdateBadgeNumber) NCCommunicationCommon.shared.writeLog("Completition perform Fetch with \(items) uploads [Auto upload]") if items == 0 { @@ -417,25 +417,25 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } } - + // MARK: - Background Networking Session func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { - + NCCommunicationCommon.shared.writeLog("Start handle Events For Background URLSession: \(identifier)") backgroundSessionCompletionHandler = completionHandler } - + // MARK: - Push Notifications - + func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler(UNNotificationPresentationOptions.alert) } - + func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { completionHandler() } - + func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { NCNetworking.shared.checkPushNotificationServerProxyCertificateUntrusted(viewController: self.window?.rootViewController) { errorCode in if errorCode == 0 { @@ -443,30 +443,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } } - - func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { - NCPushNotification.shared().applicationdidReceiveRemoteNotification(userInfo) { (result) in + + func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { + NCPushNotification.shared().applicationdidReceiveRemoteNotification(userInfo) { result in completionHandler(result) } } - + // MARK: - Login & checkErrorNetworking @objc func openLogin(viewController: UIViewController?, selector: Int, openLoginWeb: Bool) { - + // use appConfig [MDM] if NCBrandOptions.shared.use_configuration { - + if activeAppConfigView?.view.window == nil { activeAppConfigView = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCAppConfigView") as? NCAppConfigView showLoginViewController(activeAppConfigView, contextViewController: viewController) } return } - + // only for personalized LoginWeb [customer] if NCBrandOptions.shared.use_login_web_personalized { - + if activeLoginWeb?.view.window == nil { activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb activeLoginWeb?.urlBase = NCBrandOptions.shared.loginBaseUrl @@ -474,10 +474,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } return } - + // Nextcloud standard login if selector == NCGlobal.shared.introSignup { - + if activeLoginWeb?.view.window == nil { activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb if selector == NCGlobal.shared.introSignup { @@ -487,25 +487,25 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } showLoginViewController(activeLoginWeb, contextViewController: viewController) } - + } else if NCBrandOptions.shared.disable_intro && NCBrandOptions.shared.disable_request_login_url { - + if activeLoginWeb?.view.window == nil { activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb activeLoginWeb?.urlBase = NCBrandOptions.shared.loginBaseUrl showLoginViewController(activeLoginWeb, contextViewController: viewController) } - + } else if openLoginWeb { - + if activeLoginWeb?.view.window == nil { activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb activeLoginWeb?.urlBase = urlBase showLoginViewController(activeLoginWeb, contextViewController: viewController) } - + } else { - + if activeLogin?.view.window == nil { activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin showLoginViewController(activeLogin, contextViewController: viewController) @@ -513,11 +513,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } - func showLoginViewController(_ viewController:UIViewController?, contextViewController: UIViewController?) { - + func showLoginViewController(_ viewController: UIViewController?, contextViewController: UIViewController?) { + if contextViewController == nil { if let viewController = viewController { - let navigationController = UINavigationController.init(rootViewController: viewController) + let navigationController = NCLoginNavigationController.init(rootViewController: viewController) navigationController.navigationBar.barStyle = .black navigationController.navigationBar.tintColor = NCBrandColor.shared.customerText navigationController.navigationBar.barTintColor = NCBrandColor.shared.customer @@ -531,7 +531,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } else { if let viewController = viewController, let contextViewController = contextViewController { - let navigationController = UINavigationController.init(rootViewController: viewController) + let navigationController = NCLoginNavigationController.init(rootViewController: viewController) navigationController.modalPresentationStyle = .fullScreen navigationController.navigationBar.barStyle = .black navigationController.navigationBar.tintColor = NCBrandColor.shared.customerText @@ -542,76 +542,69 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } - func viewCertificateDetailsDismiss() { - self.startTimerErrorNetworking() - } - @objc func startTimerErrorNetworking() { timerErrorNetworking = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(checkErrorNetworking), userInfo: nil, repeats: true) } - + @objc private func checkErrorNetworking() { - - if account == "" { return } - guard let currentHost = URL(string: self.urlBase)?.host else { return } - + // check unauthorized server (401/403) - if CCUtility.getPassword(account)!.count == 0 { + if account != "" && CCUtility.getPassword(account)!.count == 0 { openLogin(viewController: window?.rootViewController, selector: NCGlobal.shared.introLogin, openLoginWeb: true) } + } + + func trustCertificateError(host: String) { + + guard let currentHost = URL(string: self.urlBase)?.host, + let pushNotificationServerProxyHost = URL(string: NCBrandOptions.shared.pushNotificationServerProxy)?.host, + host != pushNotificationServerProxyHost, + host == currentHost + else { return } + + let certificateHostSavedPath = CCUtility.getDirectoryCerificates()! + "/" + host + ".der" + var title = NSLocalizedString("_ssl_certificate_changed_", comment: "") - // check certificate untrusted (-1202) - if NCNetworking.shared.certificatesError == currentHost { - - let certificateHostSavedPath = CCUtility.getDirectoryCerificates()! + "/" + currentHost + ".der" - var title = NSLocalizedString("_ssl_certificate_changed_", comment: "") - - if !FileManager.default.fileExists(atPath: certificateHostSavedPath) { - title = NSLocalizedString("_connect_server_anyway_", comment: "") - } - - let alertController = UIAlertController(title: title, message: NSLocalizedString("_server_is_trusted_", comment: ""), preferredStyle: .alert) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { action in - - NCNetworking.shared.writeCertificate(host: currentHost) - NCNetworking.shared.certificatesError = nil - self.startTimerErrorNetworking() - })) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in - - NCNetworking.shared.certificatesError = nil - self.startTimerErrorNetworking() - })) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { action in - if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() as? UINavigationController { - let viewController = navigationController.topViewController as! NCViewCertificateDetails - viewController.delegate = self - viewController.host = currentHost - self.window?.rootViewController?.present(navigationController, animated: true) - } - })) - - window?.rootViewController?.present(alertController, animated: true, completion: { - self.timerErrorNetworking?.invalidate() - }) + if !FileManager.default.fileExists(atPath: certificateHostSavedPath) { + title = NSLocalizedString("_connect_server_anyway_", comment: "") } + + let alertController = UIAlertController(title: title, message: NSLocalizedString("_server_is_trusted_", comment: ""), preferredStyle: .alert) + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { action in + NCNetworking.shared.writeCertificate(host: host) + })) + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in })) + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { action in + if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() as? UINavigationController { + let viewController = navigationController.topViewController as! NCViewCertificateDetails + viewController.delegate = self + viewController.host = host + self.window?.rootViewController?.present(navigationController, animated: true) + } + })) + + window?.rootViewController?.present(alertController, animated: true) } - + + func viewCertificateDetailsDismiss(host: String) { + trustCertificateError(host: host) + } + // MARK: - Account - + @objc func settingAccount(_ account: String, urlBase: String, user: String, userId: String, password: String) { - + self.account = account self.urlBase = urlBase self.user = user self.userId = userId self.password = password - + _ = NCFunctionCenter.shared - + NCCommunicationCommon.shared.setup(account: account, user: user, userId: userId, password: password, urlBase: urlBase) NCCommunicationCommon.shared.setup(webDav: NCUtilityFileSystem.shared.getWebDAV(account: account)) let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesVersionMajor) @@ -619,12 +612,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD NCCommunicationCommon.shared.setup(nextcloudVersion: serverVersionMajor) } } - + @objc func deleteAccount(_ account: String, wipe: Bool) { - + if let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) { NCPushNotification.shared().unsubscribingNextcloudServerPushNotification(account.account, urlBase: account.urlBase, user: account.user, withSubscribing: false) - } + } let results = NCManageDatabase.shared.getTableLocalFiles(predicate: NSPredicate(format: "account == %@", account), sorted: "ocId", ascending: false) for result in results { @@ -632,11 +625,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } NCManageDatabase.shared.clearDatabase(account: account, removeAccount: true) - NCNetworking.shared.certificatesError = nil CCUtility.clearAllKeysEnd(toEnd: account) CCUtility.clearAllKeysPushNotification(account) CCUtility.setPassword(account, password: nil) - + if wipe { settingAccount("", urlBase: "", user: "", userId: "", password: "") let accounts = NCManageDatabase.shared.getAccounts() @@ -649,149 +641,168 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } } - + @objc func changeAccount(_ account: String) { - + NCManageDatabase.shared.setAccountActive(account) if let tableAccount = NCManageDatabase.shared.getActiveAccount() { - + NCOperationQueue.shared.cancelAllQueue() NCNetworking.shared.cancelAllTask() - + settingAccount(tableAccount.account, urlBase: tableAccount.urlBase, user: tableAccount.user, userId: tableAccount.userId, password: CCUtility.getPassword(tableAccount.account)) - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterInitialize) } } - + // MARK: - Account Request - + func accountRequestChangeAccount(account: String) { - + changeAccount(account) } - func requestAccount(startTimer: Bool) { + func requestAccount() { + if isPasscodePresented() { return } + if !CCUtility.getAccountRequest() { return } + let accounts = NCManageDatabase.shared.getAllAccount() - if CCUtility.getAccountRequest() && accounts.count > 1 { + if accounts.count > 1 { if let vcAccountRequest = UIStoryboard(name: "NCAccountRequest", bundle: nil).instantiateInitialViewController() as? NCAccountRequest { - + vcAccountRequest.activeAccount = NCManageDatabase.shared.getActiveAccount() vcAccountRequest.accounts = accounts vcAccountRequest.enableTimerProgress = true vcAccountRequest.enableAddAccount = false vcAccountRequest.dismissDidEnterBackground = false vcAccountRequest.delegate = self - + let screenHeighMax = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/5) let numberCell = accounts.count let height = min(CGFloat(numberCell * Int(vcAccountRequest.heightCell) + 45), screenHeighMax) - + let popup = NCPopupViewController(contentController: vcAccountRequest, popupWidth: 300, popupHeight: height+20) popup.backgroundAlpha = 0.8 - + UIApplication.shared.keyWindow?.rootViewController?.present(popup, animated: true) - if startTimer { - vcAccountRequest.startTimer() - } + vcAccountRequest.startTimer() } } } - + // MARK: - Passcode - func passcodeWithAutomaticallyPromptForBiometricValidation(_ automaticallyPromptForBiometricValidation: Bool) { - + func presentPasscode(completion: @escaping ()->()) { + let laContext = LAContext() var error: NSError? - - if account == "" { return } - - guard let passcode = CCUtility.getPasscode() else { - requestAccount(startTimer: false) - return + + defer { + self.requestAccount() } - if passcode.count == 0 || CCUtility.getNotPasscodeAtStart() { - requestAccount(startTimer: false) + + guard !account.isEmpty, CCUtility.isPasscodeAtStartEnabled() else { return } + + // If activated hide the privacy protection + hidePrivacyProtectionWindow() + + // Dismiss present window?.rootViewController? [ONLY PASSCODE] + let presentedViewController = window?.rootViewController?.presentedViewController + if presentedViewController is NCLoginNavigationController { return + } else { + presentedViewController?.dismiss(animated: false) } - - if passcodeViewController == nil { - passcodeViewController = TOPasscodeViewController.init(passcodeType: .sixDigits, allowCancel: false) - passcodeViewController?.delegate = self - passcodeViewController?.keypadButtonShowLettering = false - if CCUtility.getEnableTouchFaceID() && laContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { - if error == nil { - if laContext.biometryType == .faceID { - passcodeViewController?.biometryType = .faceID - passcodeViewController?.allowBiometricValidation = true - } else if laContext.biometryType == .touchID { - passcodeViewController?.biometryType = .touchID - passcodeViewController?.allowBiometricValidation = true - } + + let passcodeViewController = TOPasscodeViewController.init(passcodeType: .sixDigits, allowCancel: false) + passcodeViewController.delegate = self + passcodeViewController.keypadButtonShowLettering = false + if CCUtility.getEnableTouchFaceID() && laContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { + if error == nil { + if laContext.biometryType == .faceID { + passcodeViewController.biometryType = .faceID + } else if laContext.biometryType == .touchID { + passcodeViewController.biometryType = .touchID } - } - if let passcodeViewController = self.passcodeViewController { - window?.rootViewController?.present(passcodeViewController, animated: true, completion: { - self.enableTouchFaceID(automaticallyPromptForBiometricValidation) - }) - } - } else { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - self.enableTouchFaceID(automaticallyPromptForBiometricValidation) + passcodeViewController.allowBiometricValidation = true + passcodeViewController.automaticallyPromptForBiometricValidation = false } } - } - func didInputCorrectPasscode(in passcodeViewController: TOPasscodeViewController) { - passcodeViewController.dismiss(animated: true) { - self.passcodeViewController = nil - self.requestAccount(startTimer: true) - } + window?.rootViewController?.present(passcodeViewController, animated: true, completion: { + completion() + }) } - func passcodeViewController(_ passcodeViewController: TOPasscodeViewController, isCorrectCode code: String) -> Bool { - return code == CCUtility.getPasscode() + func isPasscodePresented() -> Bool { + return window?.rootViewController?.presentedViewController is TOPasscodeViewController } - func didPerformBiometricValidationRequest(in passcodeViewController: TOPasscodeViewController) { + func enableTouchFaceID() { + + guard !account.isEmpty, + CCUtility.getEnableTouchFaceID(), + CCUtility.isPasscodeAtStartEnabled(), + let passcodeViewController = window?.rootViewController?.presentedViewController as? TOPasscodeViewController + else { return } + LAContext().evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: NCBrandOptions.shared.brand) { (success, error) in if success { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + DispatchQueue.main.async { passcodeViewController.dismiss(animated: true) { - self.passcodeViewController = nil - self.requestAccount(startTimer: true) + self.requestAccount() } } } } } - func enableTouchFaceID(_ automaticallyPromptForBiometricValidation: Bool) { - if CCUtility.getEnableTouchFaceID() && automaticallyPromptForBiometricValidation && passcodeViewController?.view.window != nil { - LAContext().evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: NCBrandOptions.shared.brand) { (success, error) in - if success { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - self.passcodeViewController?.dismiss(animated: true) { - self.passcodeViewController = nil - self.requestAccount(startTimer: true) - } - } - } + func didInputCorrectPasscode(in passcodeViewController: TOPasscodeViewController) { + DispatchQueue.main.async { + passcodeViewController.dismiss(animated: true) { + self.requestAccount() } } } + + func passcodeViewController(_ passcodeViewController: TOPasscodeViewController, isCorrectCode code: String) -> Bool { + return code == CCUtility.getPasscode() + } + + // MARK: - Privacy Protection + + private func showPrivacyProtectionWindow() { + + guard CCUtility.getPrivacyScreenEnabled() else { return } + + privacyProtectionWindow = UIWindow(frame: UIScreen.main.bounds) + + let storyboard = UIStoryboard(name: "LaunchScreen", bundle: nil) + let initialViewController = storyboard.instantiateInitialViewController() + + self.privacyProtectionWindow?.rootViewController = initialViewController + + privacyProtectionWindow?.windowLevel = .alert + 1 + privacyProtectionWindow?.makeKeyAndVisible() + } + + private func hidePrivacyProtectionWindow() { + + privacyProtectionWindow?.isHidden = true + privacyProtectionWindow = nil + } // MARK: - Open URL - func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { - + func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { + if account == "" { return false } - + let scheme = url.scheme let action = url.host var fileName: String = "" @@ -799,16 +810,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD var matchedAccount: tableAccount? if scheme == "nextcloud" && action == "open-file" { - - if let urlComponents = URLComponents.init(url: url, resolvingAgainstBaseURL: false) { - + + if let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) { + let queryItems = urlComponents.queryItems guard let userScheme = CCUtility.value(forKey: "user", fromQueryItems: queryItems) else { return false } guard let pathScheme = CCUtility.value(forKey: "path", fromQueryItems: queryItems) else { return false } guard let linkScheme = CCUtility.value(forKey: "link", fromQueryItems: queryItems) else { return false } - + if let activeAccount = NCManageDatabase.shared.getActiveAccount() { - + let urlBase = URL(string: activeAccount.urlBase) let user = activeAccount.user if linkScheme.contains(urlBase?.host ?? "") && userScheme == user { @@ -824,9 +835,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } } - + if matchedAccount != nil { - + let webDAV = NCUtilityFileSystem.shared.getWebDAV(account: self.account) + "/files/" + self.userId if pathScheme.contains("/") { fileName = (pathScheme as NSString).lastPathComponent @@ -835,28 +846,28 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD fileName = pathScheme serverUrl = matchedAccount!.urlBase + "/" + webDAV } - + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { NCFunctionCenter.shared.openFileViewInFolder(serverUrl: serverUrl, fileName: fileName) } - + } else { - + guard let domain = URL(string: linkScheme)?.host else { return true } fileName = (pathScheme as NSString).lastPathComponent let message = String(format: NSLocalizedString("_account_not_available_", comment: ""), userScheme, domain, fileName) - + let alertController = UIAlertController(title: NSLocalizedString("_info_", comment: ""), message: message, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) - + window?.rootViewController?.present(alertController, animated: true, completion: { }) - + return false } } } } - + return true } } @@ -866,16 +877,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD extension AppDelegate: NCAudioRecorderViewControllerDelegate { func didFinishRecording(_ viewController: NCAudioRecorderViewController, fileName: String) { - + guard let navigationController = UIStoryboard(name: "NCCreateFormUploadVoiceNote", bundle: nil).instantiateInitialViewController() else { return } navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet let appDelegate = UIApplication.shared.delegate as! AppDelegate - + let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadVoiceNote viewController.setup(serverUrl: appDelegate.activeServerUrl, fileNamePath: NSTemporaryDirectory() + fileName, fileName: fileName) appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil) } - + func didFinishWithoutRecording(_ viewController: NCAudioRecorderViewController, fileName: String) { } } diff --git a/iOSClient/BackgroundImageColor/NCBackgroundImageColor.swift b/iOSClient/BackgroundImageColor/NCBackgroundImageColor.swift index 96f62d2c4..e41e5a218 100644 --- a/iOSClient/BackgroundImageColor/NCBackgroundImageColor.swift +++ b/iOSClient/BackgroundImageColor/NCBackgroundImageColor.swift @@ -24,7 +24,7 @@ import UIKit import ChromaColorPicker -public protocol NCBackgroundImageColorDelegate { +public protocol NCBackgroundImageColorDelegate: AnyObject { func colorPickerCancel() func colorPickerWillChange(color: UIColor) func colorPickerDidChange(lightColor: String, darkColor: String) @@ -41,7 +41,7 @@ class NCBackgroundImageColor: UIViewController { @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var chromaColorPickerView: UIView! - + @IBOutlet weak var whiteButton: UIButton! @IBOutlet weak var orangeButton: UIButton! @IBOutlet weak var redButton: UIButton! @@ -50,34 +50,34 @@ class NCBackgroundImageColor: UIViewController { @IBOutlet weak var darkmodeLabel: UILabel! @IBOutlet weak var darkmodeSwitch: UISwitch! - + @IBOutlet weak var defaultButton: UIButton! @IBOutlet weak var cancelButton: UIButton! @IBOutlet weak var okButton: UIButton! - + private let colorPicker = ChromaColorPicker() private let brightnessSlider = ChromaBrightnessSlider() private var colorHandle: ChromaColorHandle? private let defaultColorPickerSize = CGSize(width: 200, height: 200) private let brightnessSliderWidthHeightRatio: CGFloat = 0.1 - - var delegate: NCBackgroundImageColorDelegate? + + weak var delegate: NCBackgroundImageColorDelegate? var setupColor: UIColor? var darkColor = "#000000" var lightColor = "#FFFFFF" - + let width: CGFloat = 300 let height: CGFloat = 450 - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + setupColorPicker() setupBrightnessSlider() setupColorPickerHandles() - + titleLabel.text = NSLocalizedString("_background_", comment: "") darkmodeLabel.text = NSLocalizedString("_dark_mode_", comment: "") @@ -85,7 +85,7 @@ class NCBackgroundImageColor: UIViewController { cancelButton.setTitle(NSLocalizedString("_cancel_", comment: ""), for: .normal) okButton.setTitle(NSLocalizedString("_ok_", comment: ""), for: .normal) - + whiteButton.backgroundColor = .white whiteButton.layer.cornerRadius = 5 whiteButton.layer.borderWidth = 0.5 @@ -97,34 +97,34 @@ class NCBackgroundImageColor: UIViewController { orangeButton.layer.borderWidth = 0.5 orangeButton.layer.borderColor = NCBrandColor.shared.label.cgColor orangeButton.layer.masksToBounds = true - + redButton.backgroundColor = .red redButton.layer.cornerRadius = 5 redButton.layer.borderWidth = 0.5 redButton.layer.borderColor = NCBrandColor.shared.label.cgColor redButton.layer.masksToBounds = true - + greenButton.backgroundColor = .green greenButton.layer.cornerRadius = 5 greenButton.layer.borderWidth = 0.5 greenButton.layer.borderColor = NCBrandColor.shared.label.cgColor greenButton.layer.masksToBounds = true - + blackButton.backgroundColor = .black blackButton.layer.cornerRadius = 5 blackButton.layer.borderWidth = 0.5 blackButton.layer.borderColor = NCBrandColor.shared.label.cgColor blackButton.layer.masksToBounds = true - + defaultButton.layer.cornerRadius = 15 defaultButton.layer.borderWidth = 0.5 defaultButton.layer.borderColor = UIColor.gray.cgColor defaultButton.layer.masksToBounds = true } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + if traitCollection.userInterfaceStyle == .dark { darkmodeSwitch.isOn = true } else { @@ -140,52 +140,52 @@ class NCBackgroundImageColor: UIViewController { lightColor = activeAccount.lightColorBackground } } - + // set color if darkmodeSwitch.isOn { - if let color = UIColor.init(hex: darkColor) { + if let color = UIColor(hex: darkColor) { changeColor(color) } else { changeColor(.black) } } else { - if let color = UIColor.init(hex: lightColor) { + if let color = UIColor(hex: lightColor) { changeColor(color) } else { changeColor(.white) } } } - + // MARK: - Action - + @IBAction func whiteButtonAction(_ sender: UIButton) { changeColor(.white) } - + @IBAction func orangeButtonAction(_ sender: UIButton) { changeColor(.orange) } - + @IBAction func redButtonAction(_ sender: UIButton) { changeColor(.red) } - + @IBAction func greenButtonAction(_ sender: UIButton) { changeColor(.green) } - + @IBAction func blackButtonAction(_ sender: UIButton) { changeColor(.black) } - + @IBAction func darkmodeAction(_ sender: UISwitch) { - + if sender.isOn { if darkColor == "" { changeColor(.black) } else { - if let color = UIColor.init(hex: darkColor) { + if let color = UIColor(hex: darkColor) { changeColor(color) } } @@ -193,15 +193,15 @@ class NCBackgroundImageColor: UIViewController { if lightColor == "" { changeColor(.white) } else { - if let color = UIColor.init(hex: lightColor) { + if let color = UIColor(hex: lightColor) { changeColor(color) } } } } - + @IBAction func defaultAction(_ sender: Any) { - + if darkmodeSwitch.isOn { darkColor = "#000000" changeColor(.black) @@ -210,28 +210,28 @@ class NCBackgroundImageColor: UIViewController { changeColor(.white) } } - + @IBAction func cancelAction(_ sender: Any) { self.delegate?.colorPickerCancel() dismiss(animated: true) } - + @IBAction func okAction(_ sender: Any) { - + var lightColor = self.lightColor var darkColor = self.darkColor - + if lightColor == "#FFFFFF" { lightColor = "" } if darkColor == "#000000" { darkColor = "" } - + self.delegate?.colorPickerDidChange(lightColor: lightColor, darkColor: darkColor) - + dismiss(animated: true) } - + // MARK: - ChromaColorPicker - + private func setupColorPicker() { colorPicker.delegate = self colorPicker.translatesAutoresizingMaskIntoConstraints = false @@ -244,18 +244,18 @@ class NCBackgroundImageColor: UIViewController { colorPicker.heightAnchor.constraint(equalToConstant: defaultColorPickerSize.height) ]) } - + private func setupBrightnessSlider() { brightnessSlider.connect(to: colorPicker) - + // Style brightnessSlider.trackColor = UIColor.blue brightnessSlider.handle.borderWidth = 3.0 // Example of customizing the handle's properties. - + // Layout brightnessSlider.translatesAutoresizingMaskIntoConstraints = false view.addSubview(brightnessSlider) - + NSLayoutConstraint.activate([ brightnessSlider.centerXAnchor.constraint(equalTo: colorPicker.centerXAnchor), brightnessSlider.topAnchor.constraint(equalTo: colorPicker.bottomAnchor, constant: 20), @@ -263,36 +263,36 @@ class NCBackgroundImageColor: UIViewController { brightnessSlider.heightAnchor.constraint(equalTo: brightnessSlider.widthAnchor, multiplier: brightnessSliderWidthHeightRatio) ]) } - + private func setupColorPickerHandles() { colorHandle = colorPicker.addHandle(at: setupColor) } - + private func changeColor(_ color: UIColor) { - + colorHandle?.color = color colorPicker.setNeedsLayout() brightnessSlider.trackColor = color - + if darkmodeSwitch.isOn { darkColor = color.hexString } else { lightColor = color.hexString } - + self.delegate?.colorPickerWillChange(color: color) } } extension NCBackgroundImageColor: ChromaColorPickerDelegate { func colorPickerHandleDidChange(_ colorPicker: ChromaColorPicker, handle: ChromaColorHandle, to color: UIColor) { - + if darkmodeSwitch.isOn { darkColor = color.hexString } else { lightColor = color.hexString } - + self.delegate?.colorPickerWillChange(color: color) } } diff --git a/iOSClient/Brand/Intro/NCIntroCollectionViewCell.swift b/iOSClient/Brand/Intro/NCIntroCollectionViewCell.swift index 86871b25a..20234cb30 100644 --- a/iOSClient/Brand/Intro/NCIntroCollectionViewCell.swift +++ b/iOSClient/Brand/Intro/NCIntroCollectionViewCell.swift @@ -29,7 +29,7 @@ class NCIntroCollectionViewCell: UICollectionViewCell { @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var imageView: UIImageView! - + override func awakeFromNib() { super.awakeFromNib() } diff --git a/iOSClient/Brand/Intro/NCIntroViewController.swift b/iOSClient/Brand/Intro/NCIntroViewController.swift index 0cbe24aa4..f9e725dc8 100644 --- a/iOSClient/Brand/Intro/NCIntroViewController.swift +++ b/iOSClient/Brand/Intro/NCIntroViewController.swift @@ -33,22 +33,22 @@ class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICol @IBOutlet weak var introCollectionView: UICollectionView! @IBOutlet weak var pageControl: UIPageControl! - @objc var delegate: NCIntroViewController? + @objc weak var delegate: NCIntroViewController? private let appDelegate = UIApplication.shared.delegate as! AppDelegate private let titles = [NSLocalizedString("_intro_1_title_", comment: ""), NSLocalizedString("_intro_2_title_", comment: ""), NSLocalizedString("_intro_3_title_", comment: ""), NSLocalizedString("_intro_4_title_", comment: "")] private let images = [UIImage(named: "intro1"), UIImage(named: "intro2"), UIImage(named: "intro3"), UIImage(named: "intro4")] private var timerAutoScroll: Timer? private var textColor: UIColor = .white private var textColorOpponent: UIColor = .black - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + let isTooLight = NCBrandColor.shared.customer.isTooLight() let isTooDark = NCBrandColor.shared.customer.isTooDark() - + if isTooLight { textColor = .black textColorOpponent = .white @@ -59,7 +59,7 @@ class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICol textColor = .white textColorOpponent = .black } - + if #available(iOS 13.0, *) { let navBarAppearance = UINavigationBarAppearance() navBarAppearance.configureWithTransparentBackground() @@ -76,7 +76,6 @@ class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICol } self.navigationController?.navigationBar.tintColor = textColor - pageControl.currentPageIndicatorTintColor = textColor pageControl.pageIndicatorTintColor = .lightGray @@ -101,11 +100,11 @@ class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICol introCollectionView.delegate = self introCollectionView.backgroundColor = NCBrandColor.shared.customer pageControl.numberOfPages = self.titles.count - + view.backgroundColor = NCBrandColor.shared.customer timerAutoScroll = Timer.scheduledTimer(timeInterval: 5, target: self, selector: (#selector(NCIntroViewController.autoScroll)), userInfo: nil, repeats: true) } - + override var preferredStatusBarStyle: UIStatusBarStyle { if #available(iOS 13.0, *) { if traitCollection.userInterfaceStyle == .light { @@ -129,10 +128,9 @@ class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICol } @objc func autoScroll() { - if(pageControl.currentPage + 1 >= titles.count) { + if pageControl.currentPage + 1 >= titles.count { pageControl.currentPage = 0 - } - else { + } else { pageControl.currentPage += 1 } introCollectionView.scrollToItem(at: IndexPath(row: pageControl.currentPage, section: 0), at: .centeredHorizontally, animated: true) diff --git a/iOSClient/Brand/NCBrand.swift b/iOSClient/Brand/NCBrand.swift index f80685ca1..08d1d23a6 100755 --- a/iOSClient/Brand/NCBrand.swift +++ b/iOSClient/Brand/NCBrand.swift @@ -23,53 +23,53 @@ import UIKit -//MARK: - Configuration +// MARK: - Configuration @objc class NCBrandConfiguration: NSObject { @objc static let shared: NCBrandConfiguration = { let instance = NCBrandConfiguration() return instance }() - - @objc public let configuration_bundleId: String = "it.twsweb.Nextcloud" - @objc public let configuration_serverUrl: String = "serverUrl" - @objc public let configuration_username: String = "username" - @objc public let configuration_password: String = "password" + + @objc public let configuration_bundleId: String = "it.twsweb.Nextcloud" + @objc public let configuration_serverUrl: String = "serverUrl" + @objc public let configuration_username: String = "username" + @objc public let configuration_password: String = "password" } -//MARK: - Options +// MARK: - Options @objc class NCBrandOptions: NSObject { @objc static let shared: NCBrandOptions = { let instance = NCBrandOptions() return instance }() - - @objc public var brand: String = "Nextcloud" - //@objc public var mailMe: String = "ios@nextcloud.com" // Deprecated - @objc public var textCopyrightNextcloudiOS: String = "Nextcloud Liquid for iOS %@ © 2021" - @objc public var textCopyrightNextcloudServer: String = "Nextcloud Server %@" - @objc public var loginBaseUrl: String = "https://cloud.nextcloud.com" - @objc public var pushNotificationServerProxy: String = "https://push-notifications.nextcloud.com" - @objc public var linkLoginHost: String = "https://nextcloud.com/install" - @objc public var linkloginPreferredProviders: String = "https://nextcloud.com/signup-ios"; - @objc public var webLoginAutenticationProtocol: String = "nc://" // example "abc://" - @objc public var privacy: String = "https://nextcloud.com/privacy" - @objc public var sourceCode: String = "https://github.com/nextcloud/ios" + + @objc public var brand: String = "Nextcloud" + // @objc public var mailMe: String = "ios@nextcloud.com" // Deprecated + @objc public var textCopyrightNextcloudiOS: String = "Nextcloud Liquid for iOS %@ © 2021" + @objc public var textCopyrightNextcloudServer: String = "Nextcloud Server %@" + @objc public var loginBaseUrl: String = "https://cloud.nextcloud.com" + @objc public var pushNotificationServerProxy: String = "https://push-notifications.nextcloud.com" + @objc public var linkLoginHost: String = "https://nextcloud.com/install" + @objc public var linkloginPreferredProviders: String = "https://nextcloud.com/signup-ios" + @objc public var webLoginAutenticationProtocol: String = "nc://" // example "abc://" + @objc public var privacy: String = "https://nextcloud.com/privacy" + @objc public var sourceCode: String = "https://github.com/nextcloud/ios" // Personalized - @objc public var webCloseViewProtocolPersonalized: String = "" // example "abc://change/plan" Don't touch me !! - @objc public var folderBrandAutoUpload: String = "" // example "_auto_upload_folder_" Don't touch me !! - + @objc public var webCloseViewProtocolPersonalized: String = "" // example "abc://change/plan" Don't touch me !! + @objc public var folderBrandAutoUpload: String = "" // example "_auto_upload_folder_" Don't touch me !! + // Auto Upload default folder - @objc public var folderDefaultAutoUpload: String = "Photos" - + @objc public var folderDefaultAutoUpload: String = "Photos" + // Capabilities Group - @objc public var capabilitiesGroups: String = "group.it.twsweb.Crypto-Cloud" - + @objc public var capabilitiesGroups: String = "group.it.twsweb.Crypto-Cloud" + // User Agent - @objc public var userAgent: String = "Nextcloud-iOS" // Don't touch me !! - + @objc public var userAgent: String = "Nextcloud-iOS" // Don't touch me !! + // Options @objc public var use_login_web_personalized: Bool = false // Don't touch me !! @objc public var use_default_auto_upload: Bool = false @@ -92,16 +92,17 @@ import UIKit @objc public var disable_background_color: Bool = true @objc public var disable_background_image: Bool = true + @objc public var disable_ff: Bool = true override init() { - + if folderBrandAutoUpload != "" { folderDefaultAutoUpload = folderBrandAutoUpload } } } -//MARK: - Color +// MARK: - Color class NCBrandColor: NSObject { @objc static let shared: NCBrandColor = { @@ -110,14 +111,14 @@ class NCBrandColor: NSObject { instance.createUserColors() return instance }() - + struct cacheImages { static var file = UIImage() static var shared = UIImage() static var canShare = UIImage() static var shareByLink = UIImage() - + static var favorite = UIImage() static var comment = UIImage() static var livePhoto = UIImage() @@ -131,28 +132,28 @@ class NCBrandColor: NSObject { static var folderExternal = UIImage() static var folderAutomaticUpload = UIImage() static var folder = UIImage() - + static var checkedYes = UIImage() static var checkedNo = UIImage() - + static var buttonMore = UIImage() static var buttonStop = UIImage() static var buttonRestore = UIImage() } // Color - @objc public let customer: UIColor = UIColor(red: 0.0/255.0, green: 130.0/255.0, blue: 201.0/255.0, alpha: 1.0) // BLU NC : #0082c9 - @objc public var customerText: UIColor = .white - - @objc public var brand: UIColor // don't touch me - @objc public var brandElement: UIColor // don't touch me - @objc public var brandText: UIColor // don't touch me - - @objc public let nextcloud: UIColor = UIColor(red: 0.0/255.0, green: 130.0/255.0, blue: 201.0/255.0, alpha: 1.0) - @objc public let gray: UIColor = UIColor(red: 104.0/255.0, green: 104.0/255.0, blue: 104.0/255.0, alpha: 1.0) - @objc public let lightGray: UIColor = UIColor(red: 229.0/255.0, green: 229.0/229.0, blue: 104.0/255.0, alpha: 1.0) - @objc public let yellowFavorite: UIColor = UIColor(red: 248.0/255.0, green: 205.0/255.0, blue: 70.0/255.0, alpha: 1.0) - + @objc public let customer: UIColor = UIColor(red: 0.0/255.0, green: 130.0/255.0, blue: 201.0/255.0, alpha: 1.0) // BLU NC : #0082c9 + @objc public var customerText: UIColor = .white + + @objc public var brand: UIColor // don't touch me + @objc public var brandElement: UIColor // don't touch me + @objc public var brandText: UIColor // don't touch me + + @objc public let nextcloud: UIColor = UIColor(red: 0.0/255.0, green: 130.0/255.0, blue: 201.0/255.0, alpha: 1.0) + @objc public let gray: UIColor = UIColor(red: 104.0/255.0, green: 104.0/255.0, blue: 104.0/255.0, alpha: 1.0) + @objc public let lightGray: UIColor = UIColor(red: 229.0/255.0, green: 229.0/229.0, blue: 104.0/255.0, alpha: 1.0) + @objc public let yellowFavorite: UIColor = UIColor(red: 248.0/255.0, green: 205.0/255.0, blue: 70.0/255.0, alpha: 1.0) + public var userColors: [CGColor] = [] @objc public var systemBackground: UIColor { @@ -164,7 +165,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var secondarySystemBackground: UIColor { get { if #available(iOS 13, *) { @@ -174,7 +175,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var tertiarySystemBackground: UIColor { get { if #available(iOS 13, *) { @@ -184,7 +185,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var systemGroupedBackground: UIColor { get { if #available(iOS 13, *) { @@ -194,7 +195,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var secondarySystemGroupedBackground: UIColor { get { if #available(iOS 13, *) { @@ -204,7 +205,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var label: UIColor { get { if #available(iOS 13, *) { @@ -214,7 +215,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var separator: UIColor { get { if #available(iOS 13, *) { @@ -224,7 +225,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var opaqueSeparator: UIColor { get { if #available(iOS 13, *) { @@ -234,7 +235,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var systemGray: UIColor { get { if #available(iOS 13, *) { @@ -244,7 +245,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var systemGray2: UIColor { get { if #available(iOS 13, *) { @@ -254,7 +255,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var systemGray3: UIColor { get { if #available(iOS 13, *) { @@ -264,7 +265,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var systemGray4: UIColor { get { if #available(iOS 13, *) { @@ -274,7 +275,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var systemGray5: UIColor { get { if #available(iOS 13, *) { @@ -284,7 +285,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var systemGray6: UIColor { get { if #available(iOS 13, *) { @@ -294,7 +295,7 @@ class NCBrandColor: NSObject { } } } - + @objc public var systemFill: UIColor { get { if #available(iOS 13, *) { @@ -304,11 +305,11 @@ class NCBrandColor: NSObject { } } } - + override init() { self.brand = self.customer self.brandElement = self.customer - self.brandText = self.customerText + self.brandText = self.customerText } private func createUserColors() { @@ -316,21 +317,21 @@ class NCBrandColor: NSObject { } public func createImagesThemingColor() { - + let gray: UIColor = UIColor(red: 162.0/255.0, green: 162.0/255.0, blue: 162.0/255.0, alpha: 0.5) - cacheImages.file = UIImage.init(named: "file")! - + cacheImages.file = UIImage(named: "file")! + cacheImages.shared = UIImage(named: "share")!.image(color: gray, size: 50) cacheImages.canShare = UIImage(named: "share")!.image(color: gray, size: 50) cacheImages.shareByLink = UIImage(named: "sharebylink")!.image(color: gray, size: 50) - + cacheImages.favorite = NCUtility.shared.loadImage(named: "star.fill", color: yellowFavorite) cacheImages.comment = UIImage(named: "comment")!.image(color: gray, size: 50) cacheImages.livePhoto = NCUtility.shared.loadImage(named: "livephoto", color: label) - cacheImages.offlineFlag = UIImage.init(named: "offlineFlag")! - cacheImages.local = UIImage.init(named: "local")! - + cacheImages.offlineFlag = UIImage(named: "offlineFlag")! + cacheImages.local = UIImage(named: "local")! + let folderWidth: CGFloat = UIScreen.main.bounds.width / 3 cacheImages.folderEncrypted = UIImage(named: "folderEncrypted")!.image(color: brandElement, size: folderWidth) cacheImages.folderSharedWithMe = UIImage(named: "folder_shared_with_me")!.image(color: brandElement, size: folderWidth) @@ -339,31 +340,31 @@ class NCBrandColor: NSObject { cacheImages.folderExternal = UIImage(named: "folder_external")!.image(color: brandElement, size: folderWidth) cacheImages.folderAutomaticUpload = UIImage(named: "folderAutomaticUpload")!.image(color: brandElement, size: folderWidth) cacheImages.folder = UIImage(named: "folder")!.image(color: brandElement, size: folderWidth) - + cacheImages.checkedYes = NCUtility.shared.loadImage(named: "checkmark.circle.fill", color: .systemBlue) cacheImages.checkedNo = NCUtility.shared.loadImage(named: "circle", color: gray) - + cacheImages.buttonMore = UIImage(named: "more")!.image(color: gray, size: 50) cacheImages.buttonStop = UIImage(named: "stop")!.image(color: gray, size: 50) cacheImages.buttonRestore = UIImage(named: "restore")!.image(color: gray, size: 50) } - + #if !EXTENSION public func settingThemingColor(account: String) { - + let darker: CGFloat = 30 // % let lighter: CGFloat = 30 // % if NCBrandOptions.shared.use_themingColor { - + let themingColor = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesThemingColor) - + let themingColorElement = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesThemingColorElement) - + let themingColorText = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesThemingColorText) - + settingBrandColor(themingColor, themingColorElement: themingColorElement, themingColorText: themingColorText) - + if NCBrandColor.shared.brandElement.isTooLight() { if let color = NCBrandColor.shared.brandElement.darker(by: darker) { NCBrandColor.shared.brandElement = color @@ -372,10 +373,10 @@ class NCBrandColor: NSObject { if let color = NCBrandColor.shared.brandElement.lighter(by: lighter) { NCBrandColor.shared.brandElement = color } - } - + } + } else { - + if NCBrandColor.shared.customer.isTooLight() { if let color = NCBrandColor.shared.customer.darker(by: darker) { NCBrandColor.shared.brandElement = color @@ -387,20 +388,20 @@ class NCBrandColor: NSObject { } else { NCBrandColor.shared.brandElement = NCBrandColor.shared.customer } - + NCBrandColor.shared.brand = NCBrandColor.shared.customer NCBrandColor.shared.brandText = NCBrandColor.shared.customerText } - + DispatchQueue.main.async { self.createImagesThemingColor() NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeTheming) } } #endif - + @objc func settingBrandColor(_ themingColor: String?, themingColorElement: String?, themingColorText: String?) { - + // COLOR if themingColor?.first == "#" { if let color = UIColor(hex: themingColor!) { @@ -411,7 +412,7 @@ class NCBrandColor: NSObject { } else { NCBrandColor.shared.brand = NCBrandColor.shared.customer } - + // COLOR TEXT if themingColorText?.first == "#" { if let color = UIColor(hex: themingColorText!) { @@ -422,7 +423,7 @@ class NCBrandColor: NSObject { } else { NCBrandColor.shared.brandText = NCBrandColor.shared.customerText } - + // COLOR ELEMENT if themingColorElement?.first == "#" { if let color = UIColor(hex: themingColorElement!) { @@ -446,13 +447,13 @@ class NCBrandColor: NSObject { private func mixPalette(steps: Int, color1: CGColor, color2: CGColor) -> [CGColor] { var palette = [color1] let step = stepCalc(steps: steps, color1: color1, color2: color2) - + let c1Components = color1.components! for i in 1 ..< steps { let r = c1Components[0] + step[0] * CGFloat(i) let g = c1Components[1] + step[1] * CGFloat(i) let b = c1Components[2] + step[2] * CGFloat(i) - + palette.append(UIColor(red: r, green: g, blue: b, alpha: 1).cgColor) } return palette diff --git a/iOSClient/Brand/iOSClient.plist b/iOSClient/Brand/iOSClient.plist index ab992f45b..9af7f687d 100755 --- a/iOSClient/Brand/iOSClient.plist +++ b/iOSClient/Brand/iOSClient.plist @@ -109,5 +109,29 @@ <true/> <key>UIViewControllerBasedStatusBarAppearance</key> <true/> + <key>UTExportedTypeDeclarations</key> + <array> + <dict> + <key>UTTypeConformsTo</key> + <array> + <string>public.movie</string> + </array> + <key>UTTypeDescription</key> + <string>Matroska Video File</string> + <key>UTTypeIconFiles</key> + <array/> + <key>UTTypeIdentifier</key> + <string>com.apple.quicktime.mkv</string> + <key>UTTypeReferenceURL</key> + <string>http://www.matroska.org/</string> + <key>UTTypeTagSpecification</key> + <dict> + <key>public.filename-extension</key> + <array> + <string>mkv</string> + </array> + </dict> + </dict> + </array> </dict> </plist> diff --git a/iOSClient/BrowserWeb/NCBrowserWeb.swift b/iOSClient/BrowserWeb/NCBrowserWeb.swift index d472a9afe..a18b00b08 100644 --- a/iOSClient/BrowserWeb/NCBrowserWeb.swift +++ b/iOSClient/BrowserWeb/NCBrowserWeb.swift @@ -29,22 +29,21 @@ import WebKit } class NCBrowserWeb: UIViewController { - + var webView: WKWebView? - let appDelegate = UIApplication.shared.delegate as! AppDelegate - + @objc var urlBase = "" @objc var isHiddenButtonExit = false - @objc var titleBrowser: String? = nil + @objc var titleBrowser: String? @objc weak var delegate: NCBrowserWebDelegate? - + @IBOutlet weak var buttonExit: UIButton! - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + webView = WKWebView(frame: CGRect.zero) webView!.navigationDelegate = self view.addSubview(webView!) @@ -53,7 +52,7 @@ class NCBrowserWeb: UIViewController { webView!.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true webView!.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true webView!.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true - + // button exit if isHiddenButtonExit { buttonExit.isHidden = true @@ -62,29 +61,29 @@ class NCBrowserWeb: UIViewController { let image = NCUtility.shared.loadImage(named: "xmark", color: .systemBlue) buttonExit.setImage(image, for: .normal) } - + if let url = URL(string: urlBase) { loadWebPage(webView: webView!, url: url) } else { let url = URL(fileURLWithPath: urlBase) loadWebPage(webView: webView!, url: url) } - - //navigationItem.rightBarButtonItem = UIBarButtonItem.init(image: UIImage(named: "more")!.image(color: NCBrandColor.shared.label, size: 25), style: .plain, target: self, action: #selector(self.openMenuMore)) + + // navigationItem.rightBarButtonItem = UIBarButtonItem.init(image: UIImage(named: "more")!.image(color: NCBrandColor.shared.label, size: 25), style: .plain, target: self, action: #selector(self.openMenuMore)) } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + if let titleBrowser = titleBrowser { navigationItem.title = titleBrowser } } - + deinit { - + } - + // MARK: - Action @IBAction func touchUpInsideButtonExit(_ sender: UIButton) { @@ -92,14 +91,14 @@ class NCBrowserWeb: UIViewController { self.delegate?.browserWebDismiss?() } } - + // - - func loadWebPage(webView: WKWebView, url: URL) { - + + func loadWebPage(webView: WKWebView, url: URL) { + let language = NSLocale.preferredLanguages[0] as String var request = URLRequest(url: url) - + request.addValue("true", forHTTPHeaderField: "OCS-APIRequest") request.addValue(language, forHTTPHeaderField: "Accept-Language") webView.customUserAgent = CCUtility.getUserAgent() @@ -109,28 +108,28 @@ class NCBrowserWeb: UIViewController { } extension NCBrowserWeb: WKNavigationDelegate { - + public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if let serverTrust = challenge.protectionSpace.serverTrust { completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust)) } else { - completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil); + completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil) } } - + public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { decisionHandler(.allow) } - + public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - print("didStartProvisionalNavigation"); + print("didStartProvisionalNavigation") } - + public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - print("didFinishProvisionalNavigation"); + print("didFinishProvisionalNavigation") } - + public func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { - print("didReceiveServerRedirectForProvisionalNavigation"); + print("didReceiveServerRedirectForProvisionalNavigation") } } diff --git a/iOSClient/Data/NCDataSource.swift b/iOSClient/Data/NCDataSource.swift index 3b646e392..8408c26bb 100644 --- a/iOSClient/Data/NCDataSource.swift +++ b/iOSClient/Data/NCDataSource.swift @@ -24,9 +24,9 @@ import UIKit class NCDataSource: NSObject { - + public var metadatas: [tableMetadata] = [] - public var metadataShare: [String:tableShare] = [:] + public var metadataShare: [String: tableShare] = [:] public var metadataOffLine: [String] = [] private var ascending: Bool = true @@ -34,39 +34,39 @@ class NCDataSource: NSObject { private var directoryOnTop: Bool = true private var favoriteOnTop: Bool = true private var filterLivePhoto: Bool = true - + override init() { super.init() } - + init(metadatasSource: [tableMetadata], sort: String? = "none", ascending: Bool? = false, directoryOnTop: Bool? = true, favoriteOnTop: Bool? = true, filterLivePhoto: Bool? = true) { super.init() - + self.sort = sort ?? "none" self.ascending = ascending ?? false self.directoryOnTop = directoryOnTop ?? true self.favoriteOnTop = favoriteOnTop ?? true self.filterLivePhoto = filterLivePhoto ?? true - + createMetadatas(metadatasSource: metadatasSource) } - + // MARK: - - + private func createMetadatas(metadatasSource: [tableMetadata]) { - + var metadatasSourceSorted: [tableMetadata] = [] var metadataFavoriteDirectory: [tableMetadata] = [] var metadataFavoriteFile: [tableMetadata] = [] var metadataDirectory: [tableMetadata] = [] var metadataFile: [tableMetadata] = [] - + /* Metadata order */ - + if sort != "none" && sort != "" { - metadatasSourceSorted = metadatasSource.sorted { (obj1:tableMetadata, obj2:tableMetadata) -> Bool in + metadatasSourceSorted = metadatasSource.sorted { (obj1: tableMetadata, obj2: tableMetadata) -> Bool in if sort == "date" { if ascending { return obj1.date.compare(obj2.date as Date) == ComparisonResult.orderedAscending @@ -90,29 +90,29 @@ class NCDataSource: NSObject { } else { metadatasSourceSorted = metadatasSource } - + /* Initialize datasource */ - + for metadata in metadatasSourceSorted { - + // skipped the root file if metadata.fileName == "." || metadata.serverUrl == ".." { continue } - + // skipped livePhoto if metadata.ext == "mov" && metadata.livePhoto && filterLivePhoto { continue } - + // share let shares = NCManageDatabase.shared.getTableShares(account: metadata.account, serverUrl: metadata.serverUrl, fileName: metadata.fileName) if shares.count > 0 { metadataShare[metadata.ocId] = shares.first } - + // is Local / offline if !metadata.directory { let size = CCUtility.fileProviderStorageSize(metadata.ocId, fileNameView: metadata.fileNameView) @@ -126,7 +126,7 @@ class NCDataSource: NSObject { } } } - + // Organized the metadata if metadata.favorite && favoriteOnTop { if metadata.directory { @@ -140,17 +140,17 @@ class NCDataSource: NSObject { metadataFile.append(metadata) } } - + metadatas.removeAll() metadatas += metadataFavoriteDirectory metadatas += metadataFavoriteFile metadatas += metadataDirectory metadatas += metadataFile } - + // MARK: - - func getFilesInformation() -> (directories: Int, files: Int, size: Int64) { + func getFilesInformation() -> (directories: Int, files: Int, size: Int64) { var directories: Int = 0 var files: Int = 0 @@ -162,47 +162,47 @@ class NCDataSource: NSObject { } else { files += 1 } - size = size + metadata.size + size += metadata.size } - + return (directories, files, size) } - + func deleteMetadata(ocId: String) -> Int? { - + if let index = self.getIndexMetadata(ocId: ocId) { metadatas.remove(at: index) return index } - + return nil } - + @discardableResult func reloadMetadata(ocId: String, ocIdTemp: String? = nil) -> Int? { - + var index: Int? - + if ocIdTemp != nil { index = self.getIndexMetadata(ocId: ocIdTemp!) } else { index = self.getIndexMetadata(ocId: ocId) } - + if index != nil { if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { metadatas[index!] = metadata - } + } } - + return index } - + @discardableResult func addMetadata(_ metadata: tableMetadata) -> Int? { - + var index: Int = 0 - + // Already exists for metadataCount in metadatas { if metadataCount.fileNameView == metadata.fileNameView || metadataCount.ocId == metadata.ocId { @@ -211,16 +211,16 @@ class NCDataSource: NSObject { } index += 1 } - + // Append & rebuild metadatas.append(metadata) createMetadatas(metadatasSource: metadatas) - + return getIndexMetadata(ocId: metadata.ocId) } - + func getIndexMetadata(ocId: String) -> Int? { - + var index: Int = 0 for metadataCount in metadatas { @@ -229,19 +229,19 @@ class NCDataSource: NSObject { } index += 1 } - + return nil } - + func numberOfItems() -> Int { - + return metadatas.count } - + func cellForItemAt(indexPath: IndexPath) -> tableMetadata? { - + let row = indexPath.row - + if row > metadatas.count - 1 { return nil } else { diff --git a/iOSClient/Data/NCDatabase.swift b/iOSClient/Data/NCDatabase.swift index 712cddf96..2f7ac4789 100644 --- a/iOSClient/Data/NCDatabase.swift +++ b/iOSClient/Data/NCDatabase.swift @@ -76,7 +76,7 @@ class tableAccount: Object, NCUserBaseUrl { @objc dynamic var urlBase = "" @objc dynamic var user = "" @objc dynamic var userId = "" - @objc dynamic var userStatusClearAt: NSDate? = nil + @objc dynamic var userStatusClearAt: NSDate? @objc dynamic var userStatusIcon: String? @objc dynamic var userStatusMessage: String? @objc dynamic var userStatusMessageId: String? @@ -85,7 +85,7 @@ class tableAccount: Object, NCUserBaseUrl { @objc dynamic var userStatusStatusIsUserDefined: Bool = false @objc dynamic var webpage = "" @objc dynamic var zip = "" - + // COLOR Files @objc dynamic var darkColorBackground = "" @objc dynamic var lightColorBackground = "" @@ -94,15 +94,15 @@ class tableAccount: Object, NCUserBaseUrl { @objc dynamic var hcIsTrial: Bool = false @objc dynamic var hcTrialExpired: Bool = false @objc dynamic var hcTrialRemainingSec: Int64 = 0 - @objc dynamic var hcTrialEndTime: NSDate? = nil + @objc dynamic var hcTrialEndTime: NSDate? @objc dynamic var hcAccountRemoveExpired: Bool = false @objc dynamic var hcAccountRemoveRemainingSec: Int64 = 0 - @objc dynamic var hcAccountRemoveTime: NSDate? = nil + @objc dynamic var hcAccountRemoveTime: NSDate? @objc dynamic var hcNextGroupExpirationGroup = "" @objc dynamic var hcNextGroupExpirationGroupExpired: Bool = false - @objc dynamic var hcNextGroupExpirationExpiresTime: NSDate? = nil + @objc dynamic var hcNextGroupExpirationExpiresTime: NSDate? @objc dynamic var hcNextGroupExpirationExpires = "" - + override static func primaryKey() -> String { return "account" } @@ -146,7 +146,7 @@ class tableActivityLatestId: Object { } class tableActivityPreview: Object { - + @objc dynamic var account = "" @objc dynamic var filename = "" @objc dynamic var idPrimaryKey = "" @@ -164,7 +164,7 @@ class tableActivityPreview: Object { } class tableActivitySubjectRich: Object { - + @objc dynamic var account = "" @objc dynamic var idActivity: Int = 0 @objc dynamic var idPrimaryKey = "" @@ -174,14 +174,14 @@ class tableActivitySubjectRich: Object { @objc dynamic var name = "" @objc dynamic var path = "" @objc dynamic var type = "" - + override static func primaryKey() -> String { return "idPrimaryKey" } } class tableAvatar: Object { - + @objc dynamic var date = NSDate() @objc dynamic var etag = "" @objc dynamic var fileName = "" @@ -193,17 +193,17 @@ class tableAvatar: Object { } class tableCapabilities: Object { - + @objc dynamic var account = "" - @objc dynamic var jsondata: Data? = nil - + @objc dynamic var jsondata: Data? + override static func primaryKey() -> String { return "account" } } class tableChunk: Object { - + @objc dynamic var account = "" @objc dynamic var chunkFolder = "" @objc dynamic var fileName = "" @@ -218,8 +218,7 @@ class tableChunk: Object { class tableComments: Object, DateCompareable { var dateKey: Date { creationDateTime as Date } - - + @objc dynamic var account = "" @objc dynamic var actorDisplayName = "" @objc dynamic var actorId = "" @@ -232,14 +231,14 @@ class tableComments: Object, DateCompareable { @objc dynamic var objectType = "" @objc dynamic var path = "" @objc dynamic var verb = "" - + override static func primaryKey() -> String { return "messageId" } } class tableDirectEditingCreators: Object { - + @objc dynamic var account = "" @objc dynamic var editor = "" @objc dynamic var ext = "" @@ -250,7 +249,7 @@ class tableDirectEditingCreators: Object { } class tableDirectEditingEditors: Object { - + @objc dynamic var account = "" @objc dynamic var editor = "" let mimetypes = List<String>() @@ -260,7 +259,7 @@ class tableDirectEditingEditors: Object { } class tableDirectory: Object { - + @objc dynamic var account = "" @objc dynamic var e2eEncrypted: Bool = false @objc dynamic var etag = "" @@ -278,9 +277,9 @@ class tableDirectory: Object { } class tableE2eEncryption: Object { - + @objc dynamic var account = "" - @objc dynamic var authenticationTag: String? = nil + @objc dynamic var authenticationTag: String? @objc dynamic var fileName = "" @objc dynamic var fileNameIdentifier = "" @objc dynamic var fileNamePath = "" @@ -291,7 +290,7 @@ class tableE2eEncryption: Object { @objc dynamic var mimeType = "" @objc dynamic var serverUrl = "" @objc dynamic var version: Int = 1 - + override static func primaryKey() -> String { return "fileNamePath" } @@ -304,14 +303,14 @@ class tableE2eEncryptionLock: Object { @objc dynamic var fileId = "" @objc dynamic var serverUrl = "" @objc dynamic var e2eToken = "" - + override static func primaryKey() -> String { return "fileId" } } class tableExternalSites: Object { - + @objc dynamic var account = "" @objc dynamic var icon = "" @objc dynamic var idExternalSite: Int = 0 @@ -322,7 +321,7 @@ class tableExternalSites: Object { } class tableGPS: Object { - + @objc dynamic var latitude = "" @objc dynamic var location = "" @objc dynamic var longitude = "" @@ -334,25 +333,25 @@ class tableGPS: Object { } class tableLocalFile: Object { - + @objc dynamic var account = "" @objc dynamic var etag = "" - @objc dynamic var exifDate: NSDate? = nil + @objc dynamic var exifDate: NSDate? @objc dynamic var exifLatitude = "" @objc dynamic var exifLongitude = "" - @objc dynamic var exifLensModel: String? = nil + @objc dynamic var exifLensModel: String? @objc dynamic var favorite: Bool = false @objc dynamic var fileName = "" @objc dynamic var ocId = "" @objc dynamic var offline: Bool = false - + override static func primaryKey() -> String { return "ocId" } } class tableMetadata: Object, NCUserBaseUrl { - + @objc dynamic var account = "" @objc dynamic var assetLocalIdentifier = "" @objc dynamic var checksums = "" @@ -415,12 +414,12 @@ class tableMetadata: Object, NCUserBaseUrl { } class tablePhotoLibrary: Object { - + @objc dynamic var account = "" @objc dynamic var assetLocalIdentifier = "" - @objc dynamic var creationDate: NSDate? = nil + @objc dynamic var creationDate: NSDate? @objc dynamic var idAsset = "" - @objc dynamic var modificationDate: NSDate? = nil + @objc dynamic var modificationDate: NSDate? @objc dynamic var mediaType: Int = 0 override static func primaryKey() -> String { @@ -429,14 +428,14 @@ class tablePhotoLibrary: Object { } class tableShare: Object { - + @objc dynamic var account = "" @objc dynamic var canEdit: Bool = false @objc dynamic var canDelete: Bool = false - @objc dynamic var date: NSDate? = nil + @objc dynamic var date: NSDate? @objc dynamic var displaynameFileOwner = "" @objc dynamic var displaynameOwner = "" - @objc dynamic var expirationDate: NSDate? = nil + @objc dynamic var expirationDate: NSDate? @objc dynamic var fileName = "" @objc dynamic var fileParent: Int = 0 @objc dynamic var fileSource: Int = 0 @@ -464,7 +463,7 @@ class tableShare: Object { @objc dynamic var uidFileOwner = "" @objc dynamic var uidOwner = "" @objc dynamic var url = "" - @objc dynamic var userClearAt: NSDate? = nil + @objc dynamic var userClearAt: NSDate? @objc dynamic var userIcon = "" @objc dynamic var userMessage = "" @objc dynamic var userStatus = "" @@ -475,18 +474,18 @@ class tableShare: Object { } class tableTag: Object { - + @objc dynamic var account = "" @objc dynamic var ocId = "" - @objc dynamic var tagIOS: Data? = nil - + @objc dynamic var tagIOS: Data? + override static func primaryKey() -> String { return "ocId" } } class tableTrash: Object { - + @objc dynamic var account = "" @objc dynamic var classFile = "" @objc dynamic var contentType = "" @@ -508,7 +507,7 @@ class tableTrash: Object { } class tableUserStatus: Object { - + @objc dynamic var account = "" @objc dynamic var clearAt: NSDate? @objc dynamic var clearAtTime: String? @@ -522,14 +521,13 @@ class tableUserStatus: Object { } class tableVideo: Object { - + @objc dynamic var account = "" @objc dynamic var duration: Int64 = 0 @objc dynamic var ocId = "" @objc dynamic var time: Int64 = 0 - + override static func primaryKey() -> String { return "ocId" } } - diff --git a/iOSClient/Data/NCElementsJSON.swift b/iOSClient/Data/NCElementsJSON.swift index 74e6b6182..030464637 100644 --- a/iOSClient/Data/NCElementsJSON.swift +++ b/iOSClient/Data/NCElementsJSON.swift @@ -28,40 +28,40 @@ import UIKit let instance = NCElementsJSON() return instance }() - - @objc public let capabilitiesVersionString: Array = ["ocs","data","version","string"] - @objc public let capabilitiesVersionMajor: Array = ["ocs","data","version","major"] - - @objc public let capabilitiesFileSharingApiEnabled: Array = ["ocs","data","capabilities","files_sharing","api_enabled"] - @objc public let capabilitiesFileSharingPubPasswdEnforced: Array = ["ocs","data","capabilities","files_sharing","public","password","enforced"] - @objc public let capabilitiesFileSharingDefaultPermissions: Array = ["ocs","data","capabilities","files_sharing","default_permissions"] + + @objc public let capabilitiesVersionString: Array = ["ocs", "data", "version", "string"] + @objc public let capabilitiesVersionMajor: Array = ["ocs", "data", "version", "major"] + + @objc public let capabilitiesFileSharingApiEnabled: Array = ["ocs", "data", "capabilities", "files_sharing", "api_enabled"] + @objc public let capabilitiesFileSharingPubPasswdEnforced: Array = ["ocs", "data", "capabilities", "files_sharing", "public", "password", "enforced"] + @objc public let capabilitiesFileSharingDefaultPermissions: Array = ["ocs", "data", "capabilities", "files_sharing", "default_permissions"] // NC >= 23 - @objc public let capabilitiesFileSharingSendPasswordMail: Array = ["ocs","data","capabilities","files_sharing","sharebymail","send_password_by_mail"] + @objc public let capabilitiesFileSharingSendPasswordMail: Array = ["ocs", "data", "capabilities", "files_sharing", "sharebymail", "send_password_by_mail"] + + @objc public let capabilitiesThemingColor: Array = ["ocs", "data", "capabilities", "theming", "color"] + @objc public let capabilitiesThemingColorElement: Array = ["ocs", "data", "capabilities", "theming", "color-element"] + @objc public let capabilitiesThemingColorText: Array = ["ocs", "data", "capabilities", "theming", "color-text"] + @objc public let capabilitiesThemingName: Array = ["ocs", "data", "capabilities", "theming", "name"] + @objc public let capabilitiesThemingSlogan: Array = ["ocs", "data", "capabilities", "theming", "slogan"] + + @objc public let capabilitiesWebDavRoot: Array = ["ocs", "data", "capabilities", "core", "webdav-root"] + + @objc public let capabilitiesE2EEEnabled: Array = ["ocs", "data", "capabilities", "end-to-end-encryption", "enabled"] + @objc public let capabilitiesE2EEApiVersion: Array = ["ocs", "data", "capabilities", "end-to-end-encryption", "api-version"] + + @objc public let capabilitiesExternalSitesExists: Array = ["ocs", "data", "capabilities", "external"] + + @objc public let capabilitiesRichdocumentsMimetypes: Array = ["ocs", "data", "capabilities", "richdocuments", "mimetypes"] - @objc public let capabilitiesThemingColor: Array = ["ocs","data","capabilities","theming","color"] - @objc public let capabilitiesThemingColorElement: Array = ["ocs","data","capabilities","theming","color-element"] - @objc public let capabilitiesThemingColorText: Array = ["ocs","data","capabilities","theming","color-text"] - @objc public let capabilitiesThemingName: Array = ["ocs","data","capabilities","theming","name"] - @objc public let capabilitiesThemingSlogan: Array = ["ocs","data","capabilities","theming","slogan"] - - @objc public let capabilitiesWebDavRoot: Array = ["ocs","data","capabilities","core","webdav-root"] - - @objc public let capabilitiesE2EEEnabled: Array = ["ocs","data","capabilities","end-to-end-encryption","enabled"] - @objc public let capabilitiesE2EEApiVersion: Array = ["ocs","data","capabilities","end-to-end-encryption","api-version"] - - @objc public let capabilitiesExternalSitesExists: Array = ["ocs","data","capabilities","external"] + @objc public let capabilitiesActivity: Array = ["ocs", "data", "capabilities", "activity", "apiv2"] - @objc public let capabilitiesRichdocumentsMimetypes: Array = ["ocs","data","capabilities","richdocuments","mimetypes"] + @objc public let capabilitiesNotification: Array = ["ocs", "data", "capabilities", "notifications", "ocs-endpoints"] - @objc public let capabilitiesActivity: Array = ["ocs","data","capabilities","activity","apiv2"] - - @objc public let capabilitiesNotification: Array = ["ocs","data","capabilities","notifications","ocs-endpoints"] + @objc public let capabilitiesFilesUndelete: Array = ["ocs", "data", "capabilities", "files", "undelete"] + @objc public let capabilitiesFilesComments: Array = ["ocs", "data", "capabilities", "files", "comments"] // NC 20 - @objc public let capabilitiesFilesUndelete: Array = ["ocs","data","capabilities","files","undelete"] - @objc public let capabilitiesFilesComments: Array = ["ocs","data","capabilities","files","comments"] // NC 20 + @objc public let capabilitiesHWCEnabled: Array = ["ocs", "data", "capabilities", "handwerkcloud", "enabled"] - @objc public let capabilitiesHWCEnabled: Array = ["ocs","data","capabilities","handwerkcloud","enabled"] - - @objc public let capabilitiesUserStatusEnabled: Array = ["ocs","data","capabilities","user_status","enabled"] - @objc public let capabilitiesUserStatusSupportsEmoji: Array = ["ocs","data","capabilities","user_status","supports_emoji"] + @objc public let capabilitiesUserStatusEnabled: Array = ["ocs", "data", "capabilities", "user_status", "enabled"] + @objc public let capabilitiesUserStatusSupportsEmoji: Array = ["ocs", "data", "capabilities", "user_status", "supports_emoji"] } diff --git a/iOSClient/Data/NCManageDatabase+Account.swift b/iOSClient/Data/NCManageDatabase+Account.swift new file mode 100644 index 000000000..01a687274 --- /dev/null +++ b/iOSClient/Data/NCManageDatabase+Account.swift @@ -0,0 +1,485 @@ +// +// NCManageDatabase+Account.swift +// Nextcloud +// +// Created by Henrik Storch on 30.11.21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation +import RealmSwift +import NCCommunication + +extension NCManageDatabase { + + @objc func copyObject(account: tableAccount) -> tableAccount { + return tableAccount.init(value: account) + } + + @objc func addAccount(_ account: String, urlBase: String, user: String, password: String) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + let addObject = tableAccount() + + addObject.account = account + + // Brand + if NCBrandOptions.shared.use_default_auto_upload { + + addObject.autoUpload = true + addObject.autoUploadImage = true + addObject.autoUploadVideo = true + addObject.autoUploadWWAnVideo = true + } + + CCUtility.setPassword(account, password: password) + + addObject.urlBase = urlBase + addObject.user = user + addObject.userId = user + + realm.add(addObject, update: .all) + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func updateAccount(_ account: tableAccount) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + realm.add(account, update: .all) + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func deleteAccount(_ account: String) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + let result = realm.objects(tableAccount.self).filter("account == %@", account) + + realm.delete(result) + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func getActiveAccount() -> tableAccount? { + + let realm = try! Realm() + + guard let result = realm.objects(tableAccount.self).filter("active == true").first else { + return nil + } + + return tableAccount.init(value: result) + } + + @objc func getAccounts() -> [String]? { + + let realm = try! Realm() + + let results = realm.objects(tableAccount.self).sorted(byKeyPath: "account", ascending: true) + + if results.count > 0 { + return Array(results.map { $0.account }) + } + + return nil + } + + @objc func getAccount(predicate: NSPredicate) -> tableAccount? { + + let realm = try! Realm() + + guard let result = realm.objects(tableAccount.self).filter(predicate).first else { + return nil + } + + return tableAccount.init(value: result) + } + + @objc func getAllAccount() -> [tableAccount] { + + let realm = try! Realm() + + let sorted = [SortDescriptor(keyPath: "active", ascending: false), SortDescriptor(keyPath: "user", ascending: true)] + let results = realm.objects(tableAccount.self).sorted(by: sorted) + + return Array(results.map { tableAccount.init(value: $0) }) + } + + @objc func getAllAccountOrderAlias() -> [tableAccount] { + + let realm = try! Realm() + + let sorted = [SortDescriptor(keyPath: "active", ascending: false), SortDescriptor(keyPath: "alias", ascending: true), SortDescriptor(keyPath: "user", ascending: true)] + let results = realm.objects(tableAccount.self).sorted(by: sorted) + + return Array(results.map { tableAccount.init(value: $0) }) + } + + @objc func getAccountAutoUploadFileName() -> String { + + let realm = try! Realm() + + guard let result = realm.objects(tableAccount.self).filter("active == true").first else { + return "" + } + + if result.autoUploadFileName.count > 0 { + return result.autoUploadFileName + } else { + return NCBrandOptions.shared.folderDefaultAutoUpload + } + } + + @objc func getAccountAutoUploadDirectory(urlBase: String, account: String) -> String { + + let realm = try! Realm() + + guard let result = realm.objects(tableAccount.self).filter("active == true").first else { + return "" + } + + if result.autoUploadDirectory.count > 0 { + // FIX change webdav -> /dav/files/ + if result.autoUploadDirectory.contains("/webdav") { + return NCUtilityFileSystem.shared.getHomeServer(account: account) + } else { + return result.autoUploadDirectory + } + } else { + return NCUtilityFileSystem.shared.getHomeServer(account: account) + } + } + + @objc func getAccountAutoUploadPath(urlBase: String, account: String) -> String { + + let cameraFileName = self.getAccountAutoUploadFileName() + let cameraDirectory = self.getAccountAutoUploadDirectory(urlBase: urlBase, account: account) + + let folderPhotos = CCUtility.stringAppendServerUrl(cameraDirectory, addFileName: cameraFileName)! + + return folderPhotos + } + + @discardableResult + @objc func setAccountActive(_ account: String) -> tableAccount? { + + let realm = try! Realm() + var accountReturn = tableAccount() + + do { + try realm.safeWrite { + + let results = realm.objects(tableAccount.self) + for result in results { + if result.account == account { + result.active = true + accountReturn = result + } else { + result.active = false + } + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + return nil + } + + return tableAccount.init(value: accountReturn) + } + + @objc func removePasswordAccount(_ account: String) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + + if let result = realm.objects(tableAccount.self).filter("account == %@", account).first { + result.password = "********" + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func setAccountAutoUploadProperty(_ property: String, state: Bool) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + if let result = realm.objects(tableAccount.self).filter("active == true").first { + if (tableAccount().objectSchema.properties.contains { $0.name == property }) { + result[property] = state + } + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func setAccountAutoUploadFileName(_ fileName: String?) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + if let result = realm.objects(tableAccount.self).filter("active == true").first { + if let fileName = fileName { + result.autoUploadFileName = fileName + } else { + result.autoUploadFileName = self.getAccountAutoUploadFileName() + } + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func setAccountAutoUploadDirectory(_ serverUrl: String?, urlBase: String, account: String) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + if let result = realm.objects(tableAccount.self).filter("active == true").first { + if let serverUrl = serverUrl { + result.autoUploadDirectory = serverUrl + } else { + result.autoUploadDirectory = self.getAccountAutoUploadDirectory(urlBase: urlBase, account: account) + } + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func setAccountUserProfile(_ userProfile: NCCommunicationUserProfile) -> tableAccount? { + + let realm = try! Realm() + + var returnAccount = tableAccount() + + do { + guard let activeAccount = self.getActiveAccount() else { + return nil + } + + try realm.safeWrite { + + guard let result = realm.objects(tableAccount.self).filter("account == %@", activeAccount.account).first else { + return + } + + result.address = userProfile.address + result.backend = userProfile.backend + result.backendCapabilitiesSetDisplayName = userProfile.backendCapabilitiesSetDisplayName + result.backendCapabilitiesSetPassword = userProfile.backendCapabilitiesSetPassword + result.displayName = userProfile.displayName + result.email = userProfile.email + result.enabled = userProfile.enabled + result.groups = userProfile.groups.joined(separator: ",") + result.language = userProfile.language + result.lastLogin = userProfile.lastLogin + result.locale = userProfile.locale + result.phone = userProfile.phone + result.quota = userProfile.quota + result.quotaFree = userProfile.quotaFree + result.quotaRelative = userProfile.quotaRelative + result.quotaTotal = userProfile.quotaTotal + result.quotaUsed = userProfile.quotaUsed + result.storageLocation = userProfile.storageLocation + result.subadmin = userProfile.subadmin.joined(separator: ",") + result.twitter = userProfile.twitter + result.userId = userProfile.userId + result.webpage = userProfile.webpage + + returnAccount = result + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + + return tableAccount.init(value: returnAccount) + } + + @objc func setAccountUserProfileHC(businessSize: String, businessType: String, city: String, company: String, country: String, role: String, zip: String) -> tableAccount? { + + let realm = try! Realm() + + var returnAccount = tableAccount() + + do { + guard let activeAccount = self.getActiveAccount() else { + return nil + } + + try realm.safeWrite { + + guard let result = realm.objects(tableAccount.self).filter("account == %@", activeAccount.account).first else { + return + } + + result.businessSize = businessSize + result.businessType = businessType + result.city = city + result.company = company + result.country = country + result.role = role + result.zip = zip + + returnAccount = result + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + + return tableAccount.init(value: returnAccount) + } + + /* + #if !EXTENSION + @objc func setAccountHCFeatures(_ features: HCFeatures) -> tableAccount? { + + let realm = try! Realm() + + var returnAccount = tableAccount() + + do { + guard let account = self.getAccountActive() else { + return nil + } + + try realm.write { + + guard let result = realm.objects(tableAccount.self).filter("account == %@", account.account).first else { + return + } + + result.hcIsTrial = features.isTrial + result.hcTrialExpired = features.trialExpired + result.hcTrialRemainingSec = features.trialRemainingSec + if features.trialEndTime > 0 { + result.hcTrialEndTime = Date(timeIntervalSince1970: features.trialEndTime) as NSDate + } else { + result.hcTrialEndTime = nil + } + + result.hcAccountRemoveExpired = features.accountRemoveExpired + result.hcAccountRemoveRemainingSec = features.accountRemoveRemainingSec + if features.accountRemoveTime > 0 { + result.hcAccountRemoveTime = Date(timeIntervalSince1970: features.accountRemoveTime) as NSDate + } else { + result.hcAccountRemoveTime = nil + } + + result.hcNextGroupExpirationGroup = features.nextGroupExpirationGroup + result.hcNextGroupExpirationGroupExpired = features.nextGroupExpirationGroupExpired + if features.nextGroupExpirationExpiresTime > 0 { + result.hcNextGroupExpirationExpiresTime = Date(timeIntervalSince1970: features.nextGroupExpirationExpiresTime) as NSDate + } else { + result.hcNextGroupExpirationExpiresTime = nil + } + result.hcNextGroupExpirationExpires = features.nextGroupExpirationExpires + + returnAccount = result + } + } catch let error { + print("[LOG] Could not write to database: ", error) + } + + return tableAccount.init(value: returnAccount) + } + #endif + */ + + @objc func setAccountMediaPath(_ path: String, account: String) { + + let realm = try! Realm() + do { + try realm.safeWrite { + if let result = realm.objects(tableAccount.self).filter("account == %@", account).first { + result.mediaPath = path + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func setAccountUserStatus(userStatusClearAt: NSDate?, userStatusIcon: String?, userStatusMessage: String?, userStatusMessageId: String?, userStatusMessageIsPredefined: Bool, userStatusStatus: String?, userStatusStatusIsUserDefined: Bool, account: String) { + + let realm = try! Realm() + do { + try realm.safeWrite { + if let result = realm.objects(tableAccount.self).filter("account == %@", account).first { + result.userStatusClearAt = userStatusClearAt + result.userStatusIcon = userStatusIcon + result.userStatusMessage = userStatusMessage + result.userStatusMessageId = userStatusMessageId + result.userStatusMessageIsPredefined = userStatusMessageIsPredefined + result.userStatusStatus = userStatusStatus + result.userStatusStatusIsUserDefined = userStatusStatusIsUserDefined + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func setAccountAlias(_ alias: String?) { + + let realm = try! Realm() + let alias = alias?.trimmingCharacters(in: .whitespacesAndNewlines) + + do { + try realm.safeWrite { + if let result = realm.objects(tableAccount.self).filter("active == true").first { + if let alias = alias { + result.alias = alias + } else { + result.alias = "" + } + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func setAccountColorFiles(lightColorBackground: String, darkColorBackground: String) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + if let result = realm.objects(tableAccount.self).filter("active == true").first { + result.lightColorBackground = lightColorBackground + result.darkColorBackground = darkColorBackground + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } +} diff --git a/iOSClient/Data/NCManageDatabase+Activity.swift b/iOSClient/Data/NCManageDatabase+Activity.swift new file mode 100644 index 000000000..f3d7f3a1f --- /dev/null +++ b/iOSClient/Data/NCManageDatabase+Activity.swift @@ -0,0 +1,235 @@ +// +// NCManageDatabase+Activity.swift +// Nextcloud +// +// Created by Henrik Storch on 30.11.21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation +import RealmSwift +import NCCommunication +import SwiftyJSON + +extension NCManageDatabase { + + // MARK: - + // MARK: Table Activity + + @objc func addActivity(_ activities: [NCCommunicationActivity], account: String) { + + let realm = try! Realm() + + do { + try realm.write { + + for activity in activities { + + let addObjectActivity = tableActivity() + + addObjectActivity.account = account + addObjectActivity.idActivity = activity.idActivity + addObjectActivity.idPrimaryKey = account + String(activity.idActivity) + addObjectActivity.date = activity.date + addObjectActivity.app = activity.app + addObjectActivity.type = activity.type + addObjectActivity.user = activity.user + addObjectActivity.subject = activity.subject + + if let subject_rich = activity.subject_rich, + let json = JSON(subject_rich).array { + + addObjectActivity.subjectRich = json[0].stringValue + if json.count > 1, + let dict = json[1].dictionary { + + for (key, value) in dict { + let addObjectActivitySubjectRich = tableActivitySubjectRich() + let dict = value as JSON + addObjectActivitySubjectRich.account = account + + if dict["id"].intValue > 0 { + addObjectActivitySubjectRich.id = String(dict["id"].intValue) + } else { + addObjectActivitySubjectRich.id = dict["id"].stringValue + } + + addObjectActivitySubjectRich.name = dict["name"].stringValue + addObjectActivitySubjectRich.idPrimaryKey = account + + String(activity.idActivity) + + addObjectActivitySubjectRich.id + + addObjectActivitySubjectRich.name + + addObjectActivitySubjectRich.key = key + addObjectActivitySubjectRich.idActivity = activity.idActivity + addObjectActivitySubjectRich.link = dict["link"].stringValue + addObjectActivitySubjectRich.path = dict["path"].stringValue + addObjectActivitySubjectRich.type = dict["type"].stringValue + + realm.add(addObjectActivitySubjectRich, update: .all) + } + } + } + + if let previews = activity.previews, + let json = JSON(previews).array { + for preview in json { + let addObjectActivityPreview = tableActivityPreview() + + addObjectActivityPreview.account = account + addObjectActivityPreview.idActivity = activity.idActivity + addObjectActivityPreview.fileId = preview["fileId"].intValue + addObjectActivityPreview.filename = preview["filename"].stringValue + addObjectActivityPreview.idPrimaryKey = account + String(activity.idActivity) + String(addObjectActivityPreview.fileId) + addObjectActivityPreview.source = preview["source"].stringValue + addObjectActivityPreview.link = preview["link"].stringValue + addObjectActivityPreview.mimeType = preview["mimeType"].stringValue + addObjectActivityPreview.view = preview["view"].stringValue + addObjectActivityPreview.isMimeTypeIcon = preview["isMimeTypeIcon"].boolValue + + realm.add(addObjectActivityPreview, update: .all) + } + } + + addObjectActivity.icon = activity.icon + addObjectActivity.link = activity.link + addObjectActivity.message = activity.message + addObjectActivity.objectType = activity.object_type + addObjectActivity.objectId = activity.object_id + addObjectActivity.objectName = activity.object_name + + realm.add(addObjectActivity, update: .all) + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + func getActivity(predicate: NSPredicate, filterFileId: String?) -> (all: [tableActivity], filter: [tableActivity]) { + + let realm = try! Realm() + + let results = realm.objects(tableActivity.self).filter(predicate).sorted(byKeyPath: "idActivity", ascending: false) + let allActivity = Array(results.map(tableActivity.init)) + guard let filterFileId = filterFileId else { + return (all: allActivity, filter: allActivity) + } + + // comments are loaded seperately, see NCManageDatabase.getComments + let filtered = allActivity.filter({ String($0.objectId) == filterFileId && $0.type != "comments" }) + return (all: allActivity, filter: filtered) + } + + @objc func getActivitySubjectRich(account: String, idActivity: Int, key: String) -> tableActivitySubjectRich? { + + let realm = try! Realm() + + let results = realm.objects(tableActivitySubjectRich.self).filter("account == %@ && idActivity == %d && key == %@", account, idActivity, key).first + + return results.map { tableActivitySubjectRich.init(value: $0) } + } + + @objc func getActivitySubjectRich(account: String, idActivity: Int, id: String) -> tableActivitySubjectRich? { + + let realm = try! Realm() + + let results = realm.objects(tableActivitySubjectRich.self).filter("account == %@ && idActivity == %d && id == %@", account, idActivity, id).first + + return results.map { tableActivitySubjectRich.init(value: $0) } + } + + @objc func getActivityPreview(account: String, idActivity: Int, orderKeysId: [String]) -> [tableActivityPreview] { + + let realm = try! Realm() + + var results: [tableActivityPreview] = [] + + for id in orderKeysId { + if let result = realm.objects(tableActivityPreview.self).filter("account == %@ && idActivity == %d && fileId == %d", account, idActivity, Int(id) ?? 0).first { + results.append(result) + } + } + + return results + } + + @objc func updateLatestActivityId(_ activities: [NCCommunicationActivity], account: String) { + let realm = try! Realm() + let previousRecentId = getLatestActivityId(account: account) + + do { + try realm.write { + guard + let mostRecentActivityId = activities.map({ $0.idActivity }).max(), + mostRecentActivityId > previousRecentId + else { return } + + let newRecentActivity = tableActivityLatestId() + newRecentActivity.mostRecentlyLoadedActivityId = mostRecentActivityId + newRecentActivity.account = account + realm.add(newRecentActivity, update: .all) + } + } catch { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func getLatestActivityId(account: String) -> Int { + + let realm = try! Realm() + guard let maxId = realm.objects(tableActivityLatestId.self) + .filter("account == %@", account) + .map({ $0.mostRecentlyLoadedActivityId }).max() + else { return 0 } + + return maxId + } + + // MARK: - + // MARK: Table Comments + + @objc func addComments(_ comments: [NCCommunicationComments], account: String, objectId: String) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + + let results = realm.objects(tableComments.self).filter("account == %@ AND objectId == %@", account, objectId) + realm.delete(results) + + for comment in comments { + + let object = tableComments() + + object.account = account + object.actorDisplayName = comment.actorDisplayName + object.actorId = comment.actorId + object.actorType = comment.actorType + object.creationDateTime = comment.creationDateTime as NSDate + object.isUnread = comment.isUnread + object.message = comment.message + object.messageId = comment.messageId + object.objectId = comment.objectId + object.objectType = comment.objectType + object.path = comment.path + object.verb = comment.verb + + realm.add(object, update: .all) + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func getComments(account: String, objectId: String) -> [tableComments] { + + let realm = try! Realm() + + let results = realm.objects(tableComments.self).filter("account == %@ AND objectId == %@", account, objectId).sorted(byKeyPath: "creationDateTime", ascending: false) + + return Array(results.map(tableComments.init)) + } +} diff --git a/iOSClient/Data/NCManageDatabase.swift b/iOSClient/Data/NCManageDatabase.swift index 656ad559d..efc5cac1b 100644 --- a/iOSClient/Data/NCManageDatabase.swift +++ b/iOSClient/Data/NCManageDatabase.swift @@ -33,16 +33,16 @@ class NCManageDatabase: NSObject { let instance = NCManageDatabase() return instance }() - + override init() { - + let dirGroup = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroups) let databaseFilePath = dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + NCGlobal.shared.databaseDefault) let bundleUrl: URL = Bundle.main.bundleURL let bundlePathExtension: String = bundleUrl.pathExtension let isAppex: Bool = bundlePathExtension == "appex" - + // Disable file protection for directory DB // https://docs.mongodb.com/realm/sdk/ios/examples/configure-and-open-a-realm/#std-label-ios-open-a-local-realm if let folderPathURL = dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud) { @@ -53,34 +53,34 @@ class NCManageDatabase: NSObject { print("Dangerous error") } } - + if isAppex { - + // App Extension config - + let config = Realm.Configuration( fileURL: dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + NCGlobal.shared.databaseDefault), schemaVersion: NCGlobal.shared.databaseSchemaVersion, objectTypes: [tableMetadata.self, tableLocalFile.self, tableDirectory.self, tableTag.self, tableAccount.self, tableCapabilities.self, tableE2eEncryption.self, tableE2eEncryptionLock.self, tableShare.self, tableChunk.self, tableAvatar.self] ) - + Realm.Configuration.defaultConfiguration = config - + } else { - + // App config let configCompact = Realm.Configuration( - + fileURL: databaseFilePath, schemaVersion: NCGlobal.shared.databaseSchemaVersion, - + migrationBlock: { migration, oldSchemaVersion in - + if oldSchemaVersion < 61 { migration.deleteData(forType: tableShare.className()) } - + if oldSchemaVersion < 74 { migration.enumerateObjects(ofType: tableLocalFile.className()) { oldObject, newObject in newObject!["ocId"] = oldObject!["fileID"] @@ -95,7 +95,7 @@ class NCManageDatabase: NSObject { newObject!["ocId"] = oldObject!["fileID"] } } - + if oldSchemaVersion < 87 { migration.deleteData(forType: tableActivity.className()) migration.deleteData(forType: tableActivityPreview.className()) @@ -104,31 +104,31 @@ class NCManageDatabase: NSObject { migration.deleteData(forType: tableGPS.className()) migration.deleteData(forType: tableTag.className()) } - + if oldSchemaVersion < 120 { migration.deleteData(forType: tableCapabilities.className()) migration.deleteData(forType: tableComments.className()) } - + if oldSchemaVersion < 134 { migration.deleteData(forType: tableDirectEditingCreators.className()) migration.deleteData(forType: tableDirectEditingEditors.className()) migration.deleteData(forType: tableExternalSites.className()) } - + if oldSchemaVersion < 141 { migration.enumerateObjects(ofType: tableAccount.className()) { oldObject, newObject in newObject!["urlBase"] = oldObject!["url"] } } - + if oldSchemaVersion < 162 { migration.enumerateObjects(ofType: tableAccount.className()) { oldObject, newObject in newObject!["userId"] = oldObject!["userID"] migration.deleteData(forType: tableMetadata.className()) } } - + if oldSchemaVersion < 212 { migration.deleteData(forType: tableDirectory.className()) migration.deleteData(forType: tableE2eEncryption.className()) @@ -148,18 +148,18 @@ class NCManageDatabase: NSObject { } catch { } } } - + }, shouldCompactOnLaunch: { totalBytes, usedBytes in - + // totalBytes refers to the size of the file on disk in bytes (data + free space) // usedBytes refers to the number of bytes used by data in the file - + // Compact if the file is over 100MB in size and less than 50% 'used' let oneHundredMB = 100 * 1024 * 1024 return (totalBytes > oneHundredMB) && (Double(usedBytes) / Double(totalBytes)) < 0.5 } ) - + do { _ = try Realm(configuration: configCompact) } catch { @@ -172,18 +172,18 @@ class NCManageDatabase: NSObject { } catch {} } } - + let config = Realm.Configuration( fileURL: dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + NCGlobal.shared.databaseDefault), schemaVersion: NCGlobal.shared.databaseSchemaVersion ) - + Realm.Configuration.defaultConfiguration = config } - + // Verify Database, if corrupr remove it do { - let _ = try Realm() + _ = try Realm() } catch { if let databaseFilePath = databaseFilePath { do { @@ -194,37 +194,37 @@ class NCManageDatabase: NSObject { } catch {} } } - + // Open Real _ = try! Realm() } - - //MARK: - - //MARK: Utility Database - @objc func clearTable(_ table : Object.Type, account: String? = nil) { - + // MARK: - + // MARK: Utility Database + + @objc func clearTable(_ table: Object.Type, account: String? = nil) { + let realm = try! Realm() do { try realm.safeWrite { - var results : Results<Object> + var results: Results<Object> if let account = account { results = realm.objects(table).filter("account == %@", account) } else { results = realm.objects(table) } - + realm.delete(results) } } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func clearDatabase(account: String?, removeAccount: Bool) { - + self.clearTable(tableActivity.self, account: account) self.clearTable(tableActivityLatestId.self, account: account) self.clearTable(tableActivityPreview.self, account: account) @@ -253,9 +253,9 @@ class NCManageDatabase: NSObject { self.clearTable(tableAccount.self, account: account) } } - + @objc func removeDB() { - + let realmURL = Realm.Configuration.defaultConfiguration.fileURL! let realmURLs = [ realmURL, @@ -271,686 +271,39 @@ class NCManageDatabase: NSObject { } } } - + @objc func getThreadConfined(_ object: Object) -> Any { - + // id tradeReference = [[NCManageDatabase shared] getThreadConfined:metadata]; return ThreadSafeReference(to: object) } - - @objc func putThreadConfined(_ tableRef: Any) -> Object? { - - //tableMetadata *metadataThread = (tableMetadata *)[[NCManageDatabase shared] putThreadConfined:tradeReference]; - let realm = try! Realm() - - return realm.resolve(tableRef as! ThreadSafeReference<Object>) - } - - @objc func isTableInvalidated(_ object: Object) -> Bool { - - return object.isInvalidated - } - - //MARK: - - //MARK: Table Account - - @objc func copyObject(account: tableAccount) -> tableAccount { - return tableAccount.init(value: account) - } - - @objc func addAccount(_ account: String, urlBase: String, user: String, password: String) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - let addObject = tableAccount() - - addObject.account = account - - // Brand - if NCBrandOptions.shared.use_default_auto_upload { - - addObject.autoUpload = true - addObject.autoUploadImage = true - addObject.autoUploadVideo = true - addObject.autoUploadWWAnVideo = true - } - - CCUtility.setPassword(account, password: password) - - addObject.urlBase = urlBase - addObject.user = user - addObject.userId = user - - realm.add(addObject, update: .all) - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func updateAccount(_ account: tableAccount) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - realm.add(account, update: .all) - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func deleteAccount(_ account: String) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - let result = realm.objects(tableAccount.self).filter("account == %@", account) - - realm.delete(result) - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func getActiveAccount() -> tableAccount? { - - let realm = try! Realm() - - guard let result = realm.objects(tableAccount.self).filter("active == true").first else { - return nil - } - - return tableAccount.init(value: result) - } - - @objc func getAccounts() -> [String]? { - - let realm = try! Realm() - - let results = realm.objects(tableAccount.self).sorted(byKeyPath: "account", ascending: true) - - if results.count > 0 { - return Array(results.map { $0.account }) - } - - return nil - } - - @objc func getAccount(predicate: NSPredicate) -> tableAccount? { - - let realm = try! Realm() - - guard let result = realm.objects(tableAccount.self).filter(predicate).first else { - return nil - } - - return tableAccount.init(value: result) - } - - @objc func getAllAccount() -> [tableAccount] { - - let realm = try! Realm() - - let sorted = [SortDescriptor(keyPath: "active", ascending: false), SortDescriptor(keyPath: "user", ascending: true)] - let results = realm.objects(tableAccount.self).sorted(by: sorted) - - return Array(results.map { tableAccount.init(value:$0) }) - } - - @objc func getAllAccountOrderAlias() -> [tableAccount] { - - let realm = try! Realm() - - let sorted = [SortDescriptor(keyPath: "active", ascending: false), SortDescriptor(keyPath: "alias", ascending: true), SortDescriptor(keyPath: "user", ascending: true)] - let results = realm.objects(tableAccount.self).sorted(by: sorted) - - return Array(results.map { tableAccount.init(value:$0) }) - } - - @objc func getAccountAutoUploadFileName() -> String { - - let realm = try! Realm() - - guard let result = realm.objects(tableAccount.self).filter("active == true").first else { - return "" - } - - if result.autoUploadFileName.count > 0 { - return result.autoUploadFileName - } else { - return NCBrandOptions.shared.folderDefaultAutoUpload - } - } - - @objc func getAccountAutoUploadDirectory(urlBase : String, account: String) -> String { - - let realm = try! Realm() - - guard let result = realm.objects(tableAccount.self).filter("active == true").first else { - return "" - } - - if result.autoUploadDirectory.count > 0 { - // FIX change webdav -> /dav/files/ - if result.autoUploadDirectory.contains("/webdav") { - return NCUtilityFileSystem.shared.getHomeServer(account: account) - } else { - return result.autoUploadDirectory - } - } else { - return NCUtilityFileSystem.shared.getHomeServer(account: account) - } - } - - @objc func getAccountAutoUploadPath(urlBase : String, account: String) -> String { - - let cameraFileName = self.getAccountAutoUploadFileName() - let cameraDirectory = self.getAccountAutoUploadDirectory(urlBase: urlBase, account: account) - - let folderPhotos = CCUtility.stringAppendServerUrl(cameraDirectory, addFileName: cameraFileName)! - - return folderPhotos - } - - @discardableResult - @objc func setAccountActive(_ account: String) -> tableAccount? { - - let realm = try! Realm() - var accountReturn = tableAccount() - - do { - try realm.safeWrite { - - let results = realm.objects(tableAccount.self) - for result in results { - if result.account == account { - result.active = true - accountReturn = result - } else { - result.active = false - } - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - return nil - } - - return tableAccount.init(value: accountReturn) - } - - @objc func removePasswordAccount(_ account: String) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - - if let result = realm.objects(tableAccount.self).filter("account == %@", account).first { - result.password = "********" - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func setAccountAutoUploadProperty(_ property: String, state: Bool) { - - let realm = try! Realm() - do { - try realm.safeWrite { - if let result = realm.objects(tableAccount.self).filter("active == true").first { - if (tableAccount().objectSchema.properties.contains { $0.name == property }) { - result[property] = state - } - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func setAccountAutoUploadFileName(_ fileName: String?) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - if let result = realm.objects(tableAccount.self).filter("active == true").first { - if let fileName = fileName { - result.autoUploadFileName = fileName - } else { - result.autoUploadFileName = self.getAccountAutoUploadFileName() - } - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } + @objc func putThreadConfined(_ tableRef: Any) -> Object? { - @objc func setAccountAutoUploadDirectory(_ serverUrl: String?, urlBase: String, account: String) { - + // tableMetadata *metadataThread = (tableMetadata *)[[NCManageDatabase shared] putThreadConfined:tradeReference]; let realm = try! Realm() - do { - try realm.safeWrite { - if let result = realm.objects(tableAccount.self).filter("active == true").first { - if let serverUrl = serverUrl { - result.autoUploadDirectory = serverUrl - } else { - result.autoUploadDirectory = self.getAccountAutoUploadDirectory(urlBase: urlBase, account: account) - } - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } + return realm.resolve(tableRef as! ThreadSafeReference<Object>) } - - @objc func setAccountUserProfile(_ userProfile: NCCommunicationUserProfile) -> tableAccount? { - - let realm = try! Realm() - var returnAccount = tableAccount() + @objc func isTableInvalidated(_ object: Object) -> Bool { - do { - guard let activeAccount = self.getActiveAccount() else { - return nil - } - - try realm.safeWrite { - - guard let result = realm.objects(tableAccount.self).filter("account == %@", activeAccount.account).first else { - return - } - - result.address = userProfile.address - result.backend = userProfile.backend - result.backendCapabilitiesSetDisplayName = userProfile.backendCapabilitiesSetDisplayName - result.backendCapabilitiesSetPassword = userProfile.backendCapabilitiesSetPassword - result.displayName = userProfile.displayName - result.email = userProfile.email - result.enabled = userProfile.enabled - result.groups = userProfile.groups.joined(separator: ",") - result.language = userProfile.language - result.lastLogin = userProfile.lastLogin - result.locale = userProfile.locale - result.phone = userProfile.phone - result.quota = userProfile.quota - result.quotaFree = userProfile.quotaFree - result.quotaRelative = userProfile.quotaRelative - result.quotaTotal = userProfile.quotaTotal - result.quotaUsed = userProfile.quotaUsed - result.storageLocation = userProfile.storageLocation - result.subadmin = userProfile.subadmin.joined(separator: ",") - result.twitter = userProfile.twitter - result.userId = userProfile.userId - result.webpage = userProfile.webpage - - returnAccount = result - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - - return tableAccount.init(value: returnAccount) + return object.isInvalidated } - - @objc func setAccountUserProfileHC(businessSize: String, businessType: String, city: String, company: String, country: String, role: String, zip: String) -> tableAccount? { - - let realm = try! Realm() - var returnAccount = tableAccount() + // MARK: - + // MARK: Table Avatar - do { - guard let activeAccount = self.getActiveAccount() else { - return nil - } - - try realm.safeWrite { - - guard let result = realm.objects(tableAccount.self).filter("account == %@", activeAccount.account).first else { - return - } - - result.businessSize = businessSize - result.businessType = businessType - result.city = city - result.company = company - result.country = country - result.role = role - result.zip = zip - - returnAccount = result - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - - return tableAccount.init(value: returnAccount) - } - - /* - #if !EXTENSION - @objc func setAccountHCFeatures(_ features: HCFeatures) -> tableAccount? { - - let realm = try! Realm() - - var returnAccount = tableAccount() - - do { - guard let account = self.getAccountActive() else { - return nil - } - - try realm.write { - - guard let result = realm.objects(tableAccount.self).filter("account == %@", account.account).first else { - return - } - - result.hcIsTrial = features.isTrial - result.hcTrialExpired = features.trialExpired - result.hcTrialRemainingSec = features.trialRemainingSec - if features.trialEndTime > 0 { - result.hcTrialEndTime = Date(timeIntervalSince1970: features.trialEndTime) as NSDate - } else { - result.hcTrialEndTime = nil - } - - result.hcAccountRemoveExpired = features.accountRemoveExpired - result.hcAccountRemoveRemainingSec = features.accountRemoveRemainingSec - if features.accountRemoveTime > 0 { - result.hcAccountRemoveTime = Date(timeIntervalSince1970: features.accountRemoveTime) as NSDate - } else { - result.hcAccountRemoveTime = nil - } - - result.hcNextGroupExpirationGroup = features.nextGroupExpirationGroup - result.hcNextGroupExpirationGroupExpired = features.nextGroupExpirationGroupExpired - if features.nextGroupExpirationExpiresTime > 0 { - result.hcNextGroupExpirationExpiresTime = Date(timeIntervalSince1970: features.nextGroupExpirationExpiresTime) as NSDate - } else { - result.hcNextGroupExpirationExpiresTime = nil - } - result.hcNextGroupExpirationExpires = features.nextGroupExpirationExpires - - returnAccount = result - } - } catch let error { - print("[LOG] Could not write to database: ", error) - } - - return tableAccount.init(value: returnAccount) - } - #endif - */ - - @objc func setAccountMediaPath(_ path: String, account: String) { - - let realm = try! Realm() - do { - try realm.safeWrite { - if let result = realm.objects(tableAccount.self).filter("account == %@", account).first { - result.mediaPath = path - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func setAccountUserStatus(userStatusClearAt: NSDate?, userStatusIcon: String?, userStatusMessage: String?, userStatusMessageId: String?, userStatusMessageIsPredefined: Bool, userStatusStatus: String?, userStatusStatusIsUserDefined: Bool, account: String) { - - let realm = try! Realm() - do { - try realm.safeWrite { - if let result = realm.objects(tableAccount.self).filter("account == %@", account).first { - result.userStatusClearAt = userStatusClearAt - result.userStatusIcon = userStatusIcon - result.userStatusMessage = userStatusMessage - result.userStatusMessageId = userStatusMessageId - result.userStatusMessageIsPredefined = userStatusMessageIsPredefined - result.userStatusStatus = userStatusStatus - result.userStatusStatusIsUserDefined = userStatusStatusIsUserDefined - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func setAccountAlias(_ alias: String?) { - - let realm = try! Realm() - let alias = alias?.trimmingCharacters(in: .whitespacesAndNewlines) + @objc func addAvatar(fileName: String, etag: String) { - do { - try realm.safeWrite { - if let result = realm.objects(tableAccount.self).filter("active == true").first { - if let alias = alias { - result.alias = alias - } else { - result.alias = "" - } - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func setAccountColorFiles(lightColorBackground: String, darkColorBackground: String) { - let realm = try! Realm() do { try realm.safeWrite { - if let result = realm.objects(tableAccount.self).filter("active == true").first { - result.lightColorBackground = lightColorBackground - result.darkColorBackground = darkColorBackground - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - //MARK: - - //MARK: Table Activity - - @objc func addActivity(_ activities: [NCCommunicationActivity], account: String) { - let realm = try! Realm() - - do { - try realm.write { - - for activity in activities { - - let addObjectActivity = tableActivity() - - addObjectActivity.account = account - addObjectActivity.idActivity = activity.idActivity - addObjectActivity.idPrimaryKey = account + String(activity.idActivity) - addObjectActivity.date = activity.date - addObjectActivity.app = activity.app - addObjectActivity.type = activity.type - addObjectActivity.user = activity.user - addObjectActivity.subject = activity.subject - - if let subject_rich = activity.subject_rich, - let json = JSON(subject_rich).array { - - addObjectActivity.subjectRich = json[0].stringValue - if json.count > 1, - let dict = json[1].dictionary { - - for (key, value) in dict { - let addObjectActivitySubjectRich = tableActivitySubjectRich() - let dict = value as JSON - addObjectActivitySubjectRich.account = account - - if dict["id"].intValue > 0 { - addObjectActivitySubjectRich.id = String(dict["id"].intValue) - } else { - addObjectActivitySubjectRich.id = dict["id"].stringValue - } - - addObjectActivitySubjectRich.name = dict["name"].stringValue - addObjectActivitySubjectRich.idPrimaryKey = account - + String(activity.idActivity) - + addObjectActivitySubjectRich.id - + addObjectActivitySubjectRich.name - - addObjectActivitySubjectRich.key = key - addObjectActivitySubjectRich.idActivity = activity.idActivity - addObjectActivitySubjectRich.link = dict["link"].stringValue - addObjectActivitySubjectRich.path = dict["path"].stringValue - addObjectActivitySubjectRich.type = dict["type"].stringValue - - realm.add(addObjectActivitySubjectRich, update: .all) - } - } - } - - if let previews = activity.previews, - let json = JSON(previews).array { - for preview in json { - let addObjectActivityPreview = tableActivityPreview() - - addObjectActivityPreview.account = account - addObjectActivityPreview.idActivity = activity.idActivity - addObjectActivityPreview.fileId = preview["fileId"].intValue - addObjectActivityPreview.filename = preview["filename"].stringValue - addObjectActivityPreview.idPrimaryKey = account + String(activity.idActivity) + String(addObjectActivityPreview.fileId) - addObjectActivityPreview.source = preview["source"].stringValue - addObjectActivityPreview.link = preview["link"].stringValue - addObjectActivityPreview.mimeType = preview["mimeType"].stringValue - addObjectActivityPreview.view = preview["view"].stringValue - addObjectActivityPreview.isMimeTypeIcon = preview["isMimeTypeIcon"].boolValue - - realm.add(addObjectActivityPreview, update: .all) - } - } - - addObjectActivity.icon = activity.icon - addObjectActivity.link = activity.link - addObjectActivity.message = activity.message - addObjectActivity.objectType = activity.object_type - addObjectActivity.objectId = activity.object_id - addObjectActivity.objectName = activity.object_name - - realm.add(addObjectActivity, update: .all) - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - func getActivity(predicate: NSPredicate, filterFileId: String?) -> (all: [tableActivity], filter: [tableActivity]) { - - let realm = try! Realm() - - let results = realm.objects(tableActivity.self).filter(predicate).sorted(byKeyPath: "idActivity", ascending: false) - let allActivity = Array(results.map(tableActivity.init)) - guard let filterFileId = filterFileId else { - return (all: allActivity, filter: allActivity) - } - - // comments are loaded seperately, see NCManageDatabase.getComments - let filtered = allActivity.filter({ String($0.objectId) == filterFileId && $0.type != "comments" }) - return (all: allActivity, filter: filtered) - } - - @objc func getActivitySubjectRich(account: String, idActivity: Int, key: String) -> tableActivitySubjectRich? { - - let realm = try! Realm() - - let results = realm.objects(tableActivitySubjectRich.self).filter("account == %@ && idActivity == %d && key == %@", account, idActivity, key).first - - return results.map { tableActivitySubjectRich.init(value:$0) } - } - - @objc func getActivitySubjectRich(account: String, idActivity: Int, id: String) -> tableActivitySubjectRich? { - - let realm = try! Realm() - - let results = realm.objects(tableActivitySubjectRich.self).filter("account == %@ && idActivity == %d && id == %@", account, idActivity, id).first - - return results.map { tableActivitySubjectRich.init(value:$0) } - } - - @objc func getActivityPreview(account: String, idActivity: Int, orderKeysId: [String]) -> [tableActivityPreview] { - - let realm = try! Realm() - - var results: [tableActivityPreview] = [] - - for id in orderKeysId { - if let result = realm.objects(tableActivityPreview.self).filter("account == %@ && idActivity == %d && fileId == %d", account, idActivity, Int(id) ?? 0).first { - results.append(result) - } - } - - return results - } - - @objc func updateLatestActivityId(_ activities: [NCCommunicationActivity], account: String) { - let realm = try! Realm() - let previousRecentId = getLatestActivityId(account: account) - - do { - try realm.write { - guard - let mostRecentActivityId = activities.map({ $0.idActivity }).max(), - mostRecentActivityId > previousRecentId - else { return } - - let newRecentActivity = tableActivityLatestId() - newRecentActivity.mostRecentlyLoadedActivityId = mostRecentActivityId - newRecentActivity.account = account - realm.add(newRecentActivity, update: .all) - } - } catch { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func getLatestActivityId(account: String) -> Int { - - let realm = try! Realm() - guard let maxId = realm.objects(tableActivityLatestId.self) - .filter("account == %@", account) - .map({ $0.mostRecentlyLoadedActivityId }).max() - else { return 0 } - - return maxId - } - - //MARK: - - //MARK: Table Avatar - - @objc func addAvatar(fileName: String, etag: String) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - // Add new let addObject = tableAvatar() - + addObject.date = NSDate() addObject.etag = etag addObject.fileName = fileName @@ -962,25 +315,25 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + func getTableAvatar(fileName: String) -> tableAvatar? { - + let realm = try! Realm() - + guard let result = realm.objects(tableAvatar.self).filter("fileName == %@", fileName).first else { return nil } - + return tableAvatar.init(value: result) } func clearAllAvatarLoaded() { - + let realm = try! Realm() - + do { try realm.safeWrite { - + let results = realm.objects(tableAvatar.self) for result in results { result.loaded = false @@ -991,14 +344,14 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @discardableResult func setAvatarLoaded(fileName: String) -> UIImage? { - + let realm = try! Realm() let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName var image: UIImage? - + do { try realm.safeWrite { if let result = realm.objects(tableAvatar.self).filter("fileName == %@", fileName).first { @@ -1013,12 +366,12 @@ class NCManageDatabase: NSObject { } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } - + return image } - + func getImageAvatarLoaded(fileName: String) -> UIImage? { - + let realm = try! Realm() let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName @@ -1029,134 +382,134 @@ class NCManageDatabase: NSObject { } else if result?.loaded == false { return nil } - + return UIImage(contentsOfFile: fileNameLocalPath) } - - //MARK: - - //MARK: Table Capabilities - + + // MARK: - + // MARK: Table Capabilities + @objc func addCapabilitiesJSon(_ data: Data, account: String) { - + let realm = try! Realm() do { try realm.safeWrite { let addObject = tableCapabilities() - + addObject.account = account addObject.jsondata = data - + realm.add(addObject, update: .all) } } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func getCapabilities(account: String) -> String? { - + let realm = try! Realm() - + guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else { return nil } guard let jsondata = result.jsondata else { return nil } - + let json = JSON(jsondata) - + return json.rawString()?.replacingOccurrences(of: "\\/", with: "/") } - - @objc func getCapabilitiesServerString(account: String, elements: Array<String>) -> String? { + + @objc func getCapabilitiesServerString(account: String, elements: [String]) -> String? { let realm = try! Realm() - + guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else { return nil } guard let jsondata = result.jsondata else { return nil } - + let json = JSON(jsondata) return json[elements].string } - - @objc func getCapabilitiesServerInt(account: String, elements: Array<String>) -> Int { + + @objc func getCapabilitiesServerInt(account: String, elements: [String]) -> Int { let realm = try! Realm() - + guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first, let jsondata = result.jsondata else { return 0 } - + let json = JSON(jsondata) return json[elements].intValue } - - @objc func getCapabilitiesServerBool(account: String, elements: Array<String>, exists: Bool) -> Bool { + + @objc func getCapabilitiesServerBool(account: String, elements: [String], exists: Bool) -> Bool { let realm = try! Realm() - + guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else { return false } guard let jsondata = result.jsondata else { return false } - + let json = JSON(jsondata) if exists { return json[elements].exists() } else { return json[elements].boolValue - } + } } - - @objc func getCapabilitiesServerArray(account: String, elements: Array<String>) -> [String]? { + + @objc func getCapabilitiesServerArray(account: String, elements: [String]) -> [String]? { let realm = try! Realm() var resultArray: [String] = [] - + guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else { return nil } guard let jsondata = result.jsondata else { return nil } - + let json = JSON(jsondata) - + if let results = json[elements].array { for result in results { resultArray.append(result.string ?? "") } return resultArray } - + return nil } - - //MARK: - - //MARK: Table Chunk - + + // MARK: - + // MARK: Table Chunk + func getChunkFolder(account: String, ocId: String) -> String { - + let realm = try! Realm() if let result = realm.objects(tableChunk.self).filter("account == %@ AND ocId == %@", account, ocId).first { return result.chunkFolder } - + return NSUUID().uuidString } - + func getChunks(account: String, ocId: String) -> [String] { - + let realm = try! Realm() var filesNames: [String] = [] @@ -1164,30 +517,30 @@ class NCManageDatabase: NSObject { for result in results { filesNames.append(result.fileName) } - + return filesNames } - + func addChunks(account: String, ocId: String, chunkFolder: String, fileNames: [String]) { - + let realm = try! Realm() var size: Int64 = 0 - + do { try realm.safeWrite { - + for fileName in fileNames { - + let object = tableChunk() - size = size + NCUtilityFileSystem.shared.getFileSize(filePath: CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)!) - + size += NCUtilityFileSystem.shared.getFileSize(filePath: CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)!) + object.account = account object.chunkFolder = chunkFolder object.fileName = fileName object.index = ocId + fileName object.ocId = ocId object.size = size - + realm.add(object, update: .all) } } @@ -1195,9 +548,9 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + func getChunk(account: String, fileName: String) -> tableChunk? { - + let realm = try! Realm() if let result = realm.objects(tableChunk.self).filter("account == %@ AND fileName == %@", account, fileName).first { @@ -1206,14 +559,14 @@ class NCManageDatabase: NSObject { return nil } } - + func deleteChunk(account: String, ocId: String, fileName: String) { - + let realm = try! Realm() do { try realm.safeWrite { - + let result = realm.objects(tableChunk.self).filter(NSPredicate(format: "account == %@ AND ocId == %@ AND fileName == %@", account, ocId, fileName)) realm.delete(result) } @@ -1221,14 +574,14 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + func deleteChunks(account: String, ocId: String) { - + let realm = try! Realm() do { try realm.safeWrite { - + let result = realm.objects(tableChunk.self).filter(NSPredicate(format: "account == %@ AND ocId == %@", account, ocId)) realm.delete(result) } @@ -1236,74 +589,27 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - - //MARK: - - //MARK: Table Comments - - @objc func addComments(_ comments: [NCCommunicationComments], account: String, objectId: String) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - - let results = realm.objects(tableComments.self).filter("account == %@ AND objectId == %@", account, objectId) - realm.delete(results) - - for comment in comments { - - let object = tableComments() - - object.account = account - object.actorDisplayName = comment.actorDisplayName - object.actorId = comment.actorId - object.actorType = comment.actorType - object.creationDateTime = comment.creationDateTime as NSDate - object.isUnread = comment.isUnread - object.message = comment.message - object.messageId = comment.messageId - object.objectId = comment.objectId - object.objectType = comment.objectType - object.path = comment.path - object.verb = comment.verb - - realm.add(object, update: .all) - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func getComments(account: String, objectId: String) -> [tableComments] { - - let realm = try! Realm() - - let results = realm.objects(tableComments.self).filter("account == %@ AND objectId == %@", account, objectId).sorted(byKeyPath: "creationDateTime", ascending: false) - - return Array(results.map(tableComments.init)) - } - - //MARK: - - //MARK: Table Direct Editing - + + // MARK: - + // MARK: Table Direct Editing + @objc func addDirectEditing(account: String, editors: [NCCommunicationEditorDetailsEditors], creators: [NCCommunicationEditorDetailsCreators]) { - + let realm = try! Realm() do { try realm.safeWrite { - + let resultsCreators = realm.objects(tableDirectEditingCreators.self).filter("account == %@", account) realm.delete(resultsCreators) - + let resultsEditors = realm.objects(tableDirectEditingEditors.self).filter("account == %@", account) realm.delete(resultsEditors) - + for creator in creators { - + let addObject = tableDirectEditingCreators() - + addObject.account = account addObject.editor = creator.editor addObject.ext = creator.ext @@ -1311,14 +617,14 @@ class NCManageDatabase: NSObject { addObject.mimetype = creator.mimetype addObject.name = creator.name addObject.templates = creator.templates - + realm.add(addObject) } - + for editor in editors { - + let addObject = tableDirectEditingEditors() - + addObject.account = account for mimeType in editor.mimetypes { addObject.mimetypes.append(mimeType) @@ -1333,7 +639,7 @@ class NCManageDatabase: NSObject { addObject.optionalMimetypes.append(mimeType) } addObject.secure = editor.secure - + realm.add(addObject) } } @@ -1341,51 +647,51 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func getDirectEditingCreators(account: String) -> [tableDirectEditingCreators]? { - + let realm = try! Realm() let results = realm.objects(tableDirectEditingCreators.self).filter("account == %@", account) - - if (results.count > 0) { - return Array(results.map { tableDirectEditingCreators.init(value:$0) }) + + if results.count > 0 { + return Array(results.map { tableDirectEditingCreators.init(value: $0) }) } else { return nil } } - + @objc func getDirectEditingCreators(predicate: NSPredicate) -> [tableDirectEditingCreators]? { - + let realm = try! Realm() - + let results = realm.objects(tableDirectEditingCreators.self).filter(predicate) - - if (results.count > 0) { - return Array(results.map { tableDirectEditingCreators.init(value:$0) }) + + if results.count > 0 { + return Array(results.map { tableDirectEditingCreators.init(value: $0) }) } else { return nil } } - + @objc func getDirectEditingEditors(account: String) -> [tableDirectEditingEditors]? { - + let realm = try! Realm() let results = realm.objects(tableDirectEditingEditors.self).filter("account == %@", account) - - if (results.count > 0) { - return Array(results.map { tableDirectEditingEditors.init(value:$0) }) + + if results.count > 0 { + return Array(results.map { tableDirectEditingEditors.init(value: $0) }) } else { return nil } } - - //MARK: - - //MARK: Table Directory - + + // MARK: - + // MARK: Table Directory + @objc func copyObject(directory: tableDirectory) -> tableDirectory { return tableDirectory.init(value: directory) } - + /* @objc func addDirectoryRichWorkspace(ocId: String, richWorkspace: String?) { @@ -1402,22 +708,22 @@ class NCManageDatabase: NSObject { } } */ - + @objc func addDirectory(encrypted: Bool, favorite: Bool, ocId: String, fileId: String, etag: String? = nil, permissions: String? = nil, serverUrl: String, account: String) { - + let realm = try! Realm() do { try realm.safeWrite { var addObject = tableDirectory() let result = realm.objects(tableDirectory.self).filter("ocId == %@", ocId).first - + if result != nil { addObject = result! } else { addObject.ocId = ocId } - + addObject.account = account addObject.e2eEncrypted = encrypted addObject.favorite = favorite @@ -1429,27 +735,27 @@ class NCManageDatabase: NSObject { addObject.permissions = permissions } addObject.serverUrl = serverUrl - + realm.add(addObject, update: .all) } } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func deleteDirectoryAndSubDirectory(serverUrl: String, account: String) { - + let realm = try! Realm() - + let results = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl BEGINSWITH %@", account, serverUrl) - + // Delete table Metadata & LocalFile for result in results { - + self.deleteMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", result.account, result.serverUrl)) self.deleteLocalFile(predicate: NSPredicate(format: "ocId == %@", result.ocId)) } - + // Delete table Dirrectory do { try realm.safeWrite { @@ -1459,22 +765,22 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func setDirectory(serverUrl: String, serverUrlTo: String? = nil, etag: String? = nil, ocId: String? = nil, fileId: String? = nil, encrypted: Bool, richWorkspace: String? = nil, account: String) { - + let realm = try! Realm() do { try realm.safeWrite { - + guard let result = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first else { return } - + let directory = tableDirectory.init(value: result) - + realm.delete(result) - + directory.e2eEncrypted = encrypted if let etag = etag { directory.etag = etag @@ -1491,42 +797,42 @@ class NCManageDatabase: NSObject { if let richWorkspace = richWorkspace { directory.richWorkspace = richWorkspace } - + realm.add(directory, update: .all) } } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func getTableDirectory(predicate: NSPredicate) -> tableDirectory? { - + let realm = try! Realm() guard let result = realm.objects(tableDirectory.self).filter(predicate).first else { return nil } - + return tableDirectory.init(value: result) } - + @objc func getTablesDirectory(predicate: NSPredicate, sorted: String, ascending: Bool) -> [tableDirectory]? { - + let realm = try! Realm() let results = realm.objects(tableDirectory.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending) - - if (results.count > 0) { - return Array(results.map { tableDirectory.init(value:$0) }) + + if results.count > 0 { + return Array(results.map { tableDirectory.init(value: $0) }) } else { return nil } } - + @objc func renameDirectory(ocId: String, serverUrl: String) { - + let realm = try! Realm() - + do { try realm.safeWrite { let result = realm.objects(tableDirectory.self).filter("ocId == %@", ocId).first @@ -1536,11 +842,11 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func setDirectory(serverUrl: String, offline: Bool, account: String) { - + let realm = try! Realm() - + do { try realm.safeWrite { let result = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first @@ -1550,10 +856,10 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @discardableResult @objc func setDirectory(richWorkspace: String?, serverUrl: String, account: String) -> tableDirectory? { - + let realm = try! Realm() var result: tableDirectory? @@ -1565,17 +871,17 @@ class NCManageDatabase: NSObject { } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } - + if let result = result { return tableDirectory.init(value: result) } else { return nil } } - - //MARK: - - //MARK: Table e2e Encryption - + + // MARK: - + // MARK: Table e2e Encryption + @objc func addE2eEncryption(_ e2e: tableE2eEncryption) { let realm = try! Realm() @@ -1588,14 +894,14 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func deleteE2eEncryption(predicate: NSPredicate) { - + let realm = try! Realm() do { try realm.safeWrite { - + let results = realm.objects(tableE2eEncryption.self).filter(predicate) realm.delete(results) } @@ -1603,54 +909,54 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func getE2eEncryption(predicate: NSPredicate) -> tableE2eEncryption? { - + let realm = try! Realm() - + guard let result = realm.objects(tableE2eEncryption.self).filter(predicate).sorted(byKeyPath: "metadataKeyIndex", ascending: false).first else { return nil } - + return tableE2eEncryption.init(value: result) } - + @objc func getE2eEncryptions(predicate: NSPredicate) -> [tableE2eEncryption]? { - + guard self.getActiveAccount() != nil else { return nil } - + let realm = try! Realm() - - let results : Results<tableE2eEncryption> - + + let results: Results<tableE2eEncryption> + results = realm.objects(tableE2eEncryption.self).filter(predicate) - - if (results.count > 0) { - return Array(results.map { tableE2eEncryption.init(value:$0) }) + + if results.count > 0 { + return Array(results.map { tableE2eEncryption.init(value: $0) }) } else { return nil } } - + @objc func renameFileE2eEncryption(serverUrl: String, fileNameIdentifier: String, newFileName: String, newFileNamePath: String) { - + guard let activeAccount = self.getActiveAccount() else { return } - + let realm = try! Realm() realm.beginWrite() guard let result = realm.objects(tableE2eEncryption.self).filter("account == %@ AND serverUrl == %@ AND fileNameIdentifier == %@", activeAccount.account, serverUrl, fileNameIdentifier).first else { realm.cancelWrite() - return + return } - + let object = tableE2eEncryption.init(value: result) - + realm.delete(result) object.fileName = newFileName @@ -1664,43 +970,43 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - - //MARK: - - //MARK: Table e2e Encryption Lock - + + // MARK: - + // MARK: Table e2e Encryption Lock + @objc func getE2ETokenLock(account: String, serverUrl: String) -> tableE2eEncryptionLock? { - + let realm = try! Realm() - + guard let result = realm.objects(tableE2eEncryptionLock.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first else { return nil } - + return tableE2eEncryptionLock.init(value: result) } - + @objc func setE2ETokenLock(account: String, serverUrl: String, fileId: String, e2eToken: String) { - + let realm = try! Realm() do { try realm.safeWrite { let addObject = tableE2eEncryptionLock() - + addObject.account = account addObject.fileId = fileId addObject.serverUrl = serverUrl addObject.e2eToken = e2eToken - + realm.add(addObject, update: .all) } } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func deteleE2ETokenLock(account: String, serverUrl: String) { - + let realm = try! Realm() do { @@ -1714,17 +1020,17 @@ class NCManageDatabase: NSObject { } } - //MARK: - - //MARK: Table External Sites - + // MARK: - + // MARK: Table External Sites + @objc func addExternalSites(_ externalSite: NCCommunicationExternalSite, account: String) { - + let realm = try! Realm() do { try realm.safeWrite { let addObject = tableExternalSites() - + addObject.account = account addObject.idExternalSite = externalSite.idExternalSite addObject.icon = externalSite.icon @@ -1732,16 +1038,16 @@ class NCManageDatabase: NSObject { addObject.name = externalSite.name addObject.url = externalSite.url addObject.type = externalSite.type - + realm.add(addObject) } } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func deleteExternalSites(account: String) { - + let realm = try! Realm() do { @@ -1753,23 +1059,23 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func getAllExternalSites(account: String) -> [tableExternalSites]? { - + let realm = try! Realm() - + let results = realm.objects(tableExternalSites.self).filter("account == %@", account).sorted(byKeyPath: "idExternalSite", ascending: true) - + if results.count > 0 { - return Array(results.map { tableExternalSites.init(value:$0) }) - } else { + return Array(results.map { tableExternalSites.init(value: $0) }) + } else { return nil } } - //MARK: - - //MARK: Table GPS - + // MARK: - + // MARK: Table GPS + @objc func addGeocoderLocation(_ location: String, placemarkAdministrativeArea: String, placemarkCountry: String, placemarkLocality: String, placemarkPostalCode: String, placemarkThoroughfare: String, latitude: String, longitude: String) { let realm = try! Realm() @@ -1781,10 +1087,10 @@ class NCManageDatabase: NSObject { realm.cancelWrite() return } - + // Add new GPS let addObject = tableGPS() - + addObject.latitude = latitude addObject.location = location addObject.longitude = longitude @@ -1793,40 +1099,40 @@ class NCManageDatabase: NSObject { addObject.placemarkLocality = placemarkLocality addObject.placemarkPostalCode = placemarkPostalCode addObject.placemarkThoroughfare = placemarkThoroughfare - + realm.add(addObject) - + do { try realm.commitWrite() } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func getLocationFromGeoLatitude(_ latitude: String, longitude: String) -> String? { - + let realm = try! Realm() - + let result = realm.objects(tableGPS.self).filter("latitude == %@ AND longitude == %@", latitude, longitude).first return result?.location } - //MARK: - - //MARK: Table LocalFile - + // MARK: - + // MARK: Table LocalFile + @objc func copyObject(localFile: tableLocalFile) -> tableLocalFile { return tableLocalFile.init(value: localFile) } - + func addLocalFile(metadata: tableMetadata) { - + let realm = try! Realm() - + do { try realm.safeWrite { - + let addObject = tableLocalFile() - + addObject.account = metadata.account addObject.etag = metadata.etag addObject.exifDate = NSDate() @@ -1834,23 +1140,23 @@ class NCManageDatabase: NSObject { addObject.exifLongitude = "-1" addObject.ocId = metadata.ocId addObject.fileName = metadata.fileName - + realm.add(addObject, update: .all) } } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + func addLocalFile(account: String, etag: String, ocId: String, fileName: String) { - + let realm = try! Realm() - + do { try realm.safeWrite { - + let addObject = tableLocalFile() - + addObject.account = account addObject.etag = etag addObject.exifDate = NSDate() @@ -1858,16 +1164,16 @@ class NCManageDatabase: NSObject { addObject.exifLongitude = "-1" addObject.ocId = ocId addObject.fileName = fileName - + realm.add(addObject, update: .all) } } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func deleteLocalFile(predicate: NSPredicate) { - + let realm = try! Realm() do { @@ -1879,9 +1185,9 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func setLocalFile(ocId: String, fileName: String?, etag: String?) { - + let realm = try! Realm() do { @@ -1898,9 +1204,9 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func setLocalFile(ocId: String, exifDate: NSDate?, exifLatitude: String, exifLongitude: String, exifLensModel: String?) { - + let realm = try! Realm() do { @@ -1918,850 +1224,72 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func getTableLocalFile(predicate: NSPredicate) -> tableLocalFile? { - + let realm = try! Realm() - + guard let result = realm.objects(tableLocalFile.self).filter(predicate).first else { return nil } - + return tableLocalFile.init(value: result) } - - @objc func getTableLocalFiles(predicate: NSPredicate, sorted: String, ascending: Bool) -> [tableLocalFile] { - - let realm = try! Realm() - - let results = realm.objects(tableLocalFile.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending) - return Array(results.map { tableLocalFile.init(value:$0) }) - } - - @objc func setLocalFile(ocId: String, offline: Bool) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - let result = realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first - result?.offline = offline - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - //MARK: - - //MARK: Table Metadata - - @objc func copyObject(metadata: tableMetadata) -> tableMetadata { - return tableMetadata.init(value: metadata) - } - - @objc func convertNCFileToMetadata(_ file: NCCommunicationFile, isEncrypted: Bool, account: String) -> tableMetadata { - - let metadata = tableMetadata() - - metadata.account = account - metadata.checksums = file.checksums - metadata.commentsUnread = file.commentsUnread - metadata.contentType = file.contentType - if let date = file.creationDate { - metadata.creationDate = date - } else { - metadata.creationDate = file.date - } - metadata.dataFingerprint = file.dataFingerprint - metadata.date = file.date - metadata.directory = file.directory - metadata.downloadURL = file.downloadURL - metadata.e2eEncrypted = file.e2eEncrypted - metadata.etag = file.etag - metadata.ext = file.ext - metadata.favorite = file.favorite - metadata.fileId = file.fileId - metadata.fileName = file.fileName - metadata.fileNameView = file.fileName - metadata.fileNameWithoutExt = file.fileNameWithoutExt - metadata.hasPreview = file.hasPreview - metadata.iconName = file.iconName - metadata.livePhoto = file.livePhoto - metadata.mountType = file.mountType - metadata.note = file.note - metadata.ocId = file.ocId - metadata.ownerId = file.ownerId - metadata.ownerDisplayName = file.ownerDisplayName - metadata.path = file.path - metadata.permissions = file.permissions - metadata.quotaUsedBytes = file.quotaUsedBytes - metadata.quotaAvailableBytes = file.quotaAvailableBytes - metadata.richWorkspace = file.richWorkspace - metadata.resourceType = file.resourceType - metadata.serverUrl = file.serverUrl - metadata.sharePermissionsCollaborationServices = file.sharePermissionsCollaborationServices - for element in file.sharePermissionsCloudMesh { - metadata.sharePermissionsCloudMesh.append(element) - } - for element in file.shareType { - metadata.shareType.append(element) - } - metadata.size = file.size - metadata.classFile = file.classFile - if let date = file.uploadDate { - metadata.uploadDate = date - } else { - metadata.uploadDate = file.date - } - metadata.urlBase = file.urlBase - metadata.user = file.user - metadata.userId = file.userId - - // E2EE find the fileName for fileNameView - if isEncrypted || metadata.e2eEncrypted { - if let tableE2eEncryption = NCManageDatabase.shared.getE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameIdentifier == %@", account, file.serverUrl, file.fileName)) { - metadata.fileNameView = tableE2eEncryption.fileName - let results = NCCommunicationCommon.shared.getInternalType(fileName: metadata.fileNameView, mimeType: file.contentType, directory: file.directory) - metadata.contentType = results.mimeType - metadata.iconName = results.iconName - metadata.classFile = results.classFile - } - } - - // Live Photo "DETECT" - if !metadata.directory && !metadata.livePhoto && (metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue) { - var classFile = metadata.classFile - if classFile == NCCommunicationCommon.typeClassFile.image.rawValue { - classFile = NCCommunicationCommon.typeClassFile.video.rawValue - } else { - classFile = NCCommunicationCommon.typeClassFile.image.rawValue - } - if getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameWithoutExt == %@ AND ocId != %@ AND classFile == %@", metadata.account, metadata.serverUrl, metadata.fileNameWithoutExt, metadata.ocId, classFile)) != nil { - metadata.livePhoto = true - } - } - - return metadata - } - - @objc func convertNCCommunicationFilesToMetadatas(_ files: [NCCommunicationFile], useMetadataFolder: Bool, account: String, completion: @escaping (_ metadataFolder: tableMetadata,_ metadatasFolder: [tableMetadata], _ metadatas: [tableMetadata])->()) { - - var counter: Int = 0 - var isEncrypted: Bool = false - var listServerUrl: [String: Bool] = [:] - - var metadataFolder = tableMetadata() - var metadataFolders: [tableMetadata] = [] - var metadatas: [tableMetadata] = [] - - for file in files { - - if let key = listServerUrl[file.serverUrl] { - isEncrypted = key - } else { - isEncrypted = CCUtility.isFolderEncrypted(file.serverUrl, e2eEncrypted: file.e2eEncrypted, account: account, urlBase: file.urlBase) - listServerUrl[file.serverUrl] = isEncrypted - } - - let metadata = convertNCFileToMetadata(file, isEncrypted: isEncrypted, account: account) - - if counter == 0 && useMetadataFolder { - metadataFolder = tableMetadata.init(value: metadata) - } else { - metadatas.append(metadata) - if metadata.directory { - metadataFolders.append(metadata) - } - } - - counter += 1 - } - - completion(metadataFolder, metadataFolders, metadatas) - } - - @objc func createMetadata(account: String, user: String, userId: String, fileName: String, fileNameView: String, ocId: String, serverUrl: String, urlBase: String, url: String, contentType: String, livePhoto: Bool) -> tableMetadata { - - let metadata = tableMetadata() - let resultInternalType = NCCommunicationCommon.shared.getInternalType(fileName: fileName, mimeType: contentType, directory: false) - - metadata.account = account - metadata.chunk = false - metadata.contentType = resultInternalType.mimeType - metadata.creationDate = Date() as NSDate - metadata.date = Date() as NSDate - metadata.hasPreview = true - metadata.iconName = resultInternalType.iconName - metadata.etag = ocId - metadata.ext = (fileName as NSString).pathExtension.lowercased() - metadata.fileName = fileName - metadata.fileNameView = fileName - metadata.fileNameWithoutExt = (fileName as NSString).deletingPathExtension - metadata.livePhoto = livePhoto - metadata.ocId = ocId - metadata.permissions = "RGDNVW" - metadata.serverUrl = serverUrl - metadata.classFile = resultInternalType.classFile - metadata.uploadDate = Date() as NSDate - metadata.url = url - metadata.urlBase = urlBase - metadata.user = user - metadata.userId = userId - - return metadata - } - - @objc func addMetadata(_ metadata: tableMetadata) { - let realm = try! Realm() + @objc func getTableLocalFiles(predicate: NSPredicate, sorted: String, ascending: Bool) -> [tableLocalFile] { - do { - try realm.safeWrite { - realm.add(metadata, update: .all) - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func addMetadatas(_ metadatas: [tableMetadata]) { - let realm = try! Realm() - do { - try realm.safeWrite { - for metadata in metadatas { - realm.add(metadata, update: .all) - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func deleteMetadata(predicate: NSPredicate) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - let results = realm.objects(tableMetadata.self).filter(predicate) - realm.delete(results) - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } + let results = realm.objects(tableLocalFile.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending) + return Array(results.map { tableLocalFile.init(value: $0) }) } - - @objc func moveMetadata(ocId: String, serverUrlTo: String) { - - let realm = try! Realm() - do { - try realm.safeWrite { - if let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first { - result.serverUrl = serverUrlTo - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func addMetadataServerUrl(ocId: String, serverUrl: String) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - let results = realm.objects(tableMetadata.self).filter("ocId == %@", ocId) - for result in results { - result.serverUrl = serverUrl - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func renameMetadata(fileNameTo: String, ocId: String) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - if let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first { - let resultsType = NCCommunicationCommon.shared.getInternalType(fileName: fileNameTo, mimeType: "", directory: result.directory) - result.fileName = fileNameTo - result.fileNameView = fileNameTo - if result.directory { - result.fileNameWithoutExt = fileNameTo - result.ext = "" - } else { - result.fileNameWithoutExt = (fileNameTo as NSString).deletingPathExtension - result.ext = resultsType.ext - } - result.iconName = resultsType.iconName - result.contentType = resultsType.mimeType - result.classFile = resultsType.classFile - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } + @objc func setLocalFile(ocId: String, offline: Bool) { - @discardableResult - func updateMetadatas(_ metadatas: [tableMetadata], metadatasResult: [tableMetadata], addCompareLivePhoto: Bool = true, addExistsInLocal: Bool = false, addCompareEtagLocal: Bool = false, addDirectorySynchronized: Bool = false) -> (metadatasUpdate: [tableMetadata], metadatasLocalUpdate: [tableMetadata], metadatasDelete: [tableMetadata]) { - - let realm = try! Realm() - var ocIdsUdate: [String] = [] - var ocIdsLocalUdate: [String] = [] - var metadatasDelete: [tableMetadata] = [] - var metadatasUpdate: [tableMetadata] = [] - var metadatasLocalUpdate: [tableMetadata] = [] - - realm.refresh() - - do { - try realm.safeWrite { - - // DELETE - for metadataResult in metadatasResult { - if metadatas.firstIndex(where: { $0.ocId == metadataResult.ocId }) == nil { - if let result = realm.objects(tableMetadata.self).filter(NSPredicate(format: "ocId == %@", metadataResult.ocId)).first { - metadatasDelete.append(tableMetadata.init(value: result)) - realm.delete(result) - } - } - } - - // UPDATE/NEW - for metadata in metadatas { - - if let result = metadatasResult.first(where: { $0.ocId == metadata.ocId }) { - // update - if result.status == NCGlobal.shared.metadataStatusNormal && (result.etag != metadata.etag || result.fileNameView != metadata.fileNameView || result.date != metadata.date || result.permissions != metadata.permissions || result.hasPreview != metadata.hasPreview || result.note != metadata.note) { - ocIdsUdate.append(metadata.ocId) - realm.add(tableMetadata.init(value: metadata), update: .all) - } else if result.status == NCGlobal.shared.metadataStatusNormal && addCompareLivePhoto && result.livePhoto != metadata.livePhoto { - ocIdsUdate.append(metadata.ocId) - realm.add(tableMetadata.init(value: metadata), update: .all) - } - } else { - // new - ocIdsUdate.append(metadata.ocId) - realm.add(tableMetadata.init(value: metadata), update: .all) - } - - if metadata.directory && !ocIdsUdate.contains(metadata.ocId) { - let table = realm.objects(tableDirectory.self).filter(NSPredicate(format: "ocId == %@", metadata.ocId)).first - if table?.etag != metadata.etag { - ocIdsUdate.append(metadata.ocId) - } - } - - // Local - if !metadata.directory && (addExistsInLocal || addCompareEtagLocal) { - let localFile = realm.objects(tableLocalFile.self).filter(NSPredicate(format: "ocId == %@", metadata.ocId)).first - if addCompareEtagLocal && localFile != nil && localFile?.etag != metadata.etag { - ocIdsLocalUdate.append(metadata.ocId) - } - if addExistsInLocal && (localFile == nil || localFile?.etag != metadata.etag) && !ocIdsLocalUdate.contains(metadata.ocId) { - ocIdsLocalUdate.append(metadata.ocId) - } - } - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - - for ocId in ocIdsUdate { - if let result = realm.objects(tableMetadata.self).filter(NSPredicate(format: "ocId == %@", ocId)).first { - metadatasUpdate.append(tableMetadata.init(value: result)) - } - } - - for ocId in ocIdsLocalUdate { - if let result = realm.objects(tableMetadata.self).filter(NSPredicate(format: "ocId == %@", ocId)).first { - metadatasLocalUpdate.append(tableMetadata.init(value: result)) - } - } - - return (metadatasUpdate, metadatasLocalUpdate, metadatasDelete) - } - - func setMetadataSession(ocId: String, session: String? = nil, sessionError: String? = nil, sessionSelector: String? = nil, sessionTaskIdentifier: Int? = nil, status: Int? = nil, etag: String? = nil) { - let realm = try! Realm() - realm.refresh() do { try realm.safeWrite { - let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first - if let session = session { - result?.session = session - } - if let sessionError = sessionError { - result?.sessionError = sessionError - } - if let sessionSelector = sessionSelector { - result?.sessionSelector = sessionSelector - } - if let sessionTaskIdentifier = sessionTaskIdentifier { - result?.sessionTaskIdentifier = sessionTaskIdentifier - } - if let status = status { - result?.status = status - } - if let etag = etag { - result?.etag = etag - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @discardableResult - func setMetadataStatus(ocId: String, status: Int) -> tableMetadata? { - - let realm = try! Realm() - var result: tableMetadata? - - do { - try realm.safeWrite { - result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first - result?.status = status - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - - if let result = result { - return tableMetadata.init(value: result) - } else { - return nil - } - } - - func setMetadataEtagResource(ocId: String, etagResource: String?) { - - let realm = try! Realm() - var result: tableMetadata? - guard let etagResource = etagResource else { return } - - do { - try realm.safeWrite { - result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first - result?.etagResource = etagResource - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func setMetadataFavorite(ocId: String, favorite: Bool) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first - result?.favorite = favorite - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func updateMetadatasFavorite(account: String, metadatas: [tableMetadata]) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - let results = realm.objects(tableMetadata.self).filter("account == %@ AND favorite == true", account) - for result in results { - result.favorite = false - } - for metadata in metadatas { - realm.add(metadata, update: .all) - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func setMetadataEncrypted(ocId: String, encrypted: Bool) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first - result?.e2eEncrypted = encrypted - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func setMetadataFileNameView(serverUrl: String, fileName: String, newFileNameView: String, account: String) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - let result = realm.objects(tableMetadata.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@", account, serverUrl, fileName).first - result?.fileNameView = newFileNameView - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func getMetadata(predicate: NSPredicate) -> tableMetadata? { - - let realm = try! Realm() - realm.refresh() - - guard let result = realm.objects(tableMetadata.self).filter(predicate).first else { - return nil - } - - return tableMetadata.init(value: result) - } - - @objc func getMetadata(predicate: NSPredicate, sorted: String, ascending: Bool) -> tableMetadata? { - - let realm = try! Realm() - realm.refresh() - - guard let result = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending).first else { - return nil - } - - return tableMetadata.init(value: result) - } - - @objc func getMetadatasViewer(predicate: NSPredicate, sorted: String, ascending: Bool) -> [tableMetadata]? { - - let realm = try! Realm() - realm.refresh() - - let results: Results<tableMetadata> - var finals: [tableMetadata] = [] - - if (tableMetadata().objectSchema.properties.contains { $0.name == sorted }) { - results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending) - } else { - results = realm.objects(tableMetadata.self).filter(predicate) - } - - // For Live Photo - var fileNameImages: [String] = [] - let filtered = results.filter{ $0.classFile.contains(NCCommunicationCommon.typeClassFile.image.rawValue) } - filtered.forEach { print($0) - let fileName = ($0.fileNameView as NSString).deletingPathExtension - fileNameImages.append(fileName) - } - - for result in results { - - let ext = (result.fileNameView as NSString).pathExtension.uppercased() - let fileName = (result.fileNameView as NSString).deletingPathExtension - - if !(ext == "MOV" && fileNameImages.contains(fileName)) { - finals.append(result) - } - } - - if (finals.count > 0) { - return Array(finals.map { tableMetadata.init(value:$0) }) - } else { - return nil - } - } - - @objc func getMetadatas(predicate: NSPredicate) -> [tableMetadata] { - - let realm = try! Realm() - realm.refresh() - - let results = realm.objects(tableMetadata.self).filter(predicate) - - return Array(results.map { tableMetadata.init(value:$0) }) - } - - @objc func getAdvancedMetadatas(predicate: NSPredicate, page: Int = 0, limit: Int = 0, sorted: String, ascending: Bool) -> [tableMetadata] { - - let realm = try! Realm() - realm.refresh() - var metadatas: [tableMetadata] = [] - - let results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending) - - if results.count > 0 { - if page == 0 || limit == 0 { - return Array(results.map { tableMetadata.init(value:$0) }) - } else { - - let nFrom = (page - 1) * limit - let nTo = nFrom + (limit - 1) - - for n in nFrom...nTo { - if n == results.count { - break - } - metadatas.append(tableMetadata.init(value:results[n])) - } - } - } - return metadatas - } - - @objc func getMetadataAtIndex(predicate: NSPredicate, sorted: String, ascending: Bool, index: Int) -> tableMetadata? { - - let realm = try! Realm() - realm.refresh() - - let results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending) - - if (results.count > 0 && results.count > index) { - return tableMetadata.init(value: results[index]) - } else { - return nil - } - } - - @objc func getMetadataFromOcId(_ ocId: String?) -> tableMetadata? { - - let realm = try! Realm() - realm.refresh() - - guard let ocId = ocId else { return nil } - guard let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first else { return nil } - - return tableMetadata.init(value: result) - } - - @objc func getMetadataFolder(account: String, urlBase: String, serverUrl: String) -> tableMetadata? { - - let realm = try! Realm() - realm.refresh() - var serverUrl = serverUrl - var fileName = "" - - let serverUrlHome = NCUtilityFileSystem.shared.getHomeServer(account: account) - if serverUrlHome == serverUrl { - fileName = "." - serverUrl = ".." - } else { - fileName = (serverUrl as NSString).lastPathComponent - serverUrl = NCUtilityFileSystem.shared.deletingLastPathComponent(account: account, serverUrl: serverUrl) - } - - guard let result = realm.objects(tableMetadata.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@", account, serverUrl, fileName).first else { return nil } - - return tableMetadata.init(value: result) - } - - @objc func getTableMetadatasDirectoryFavoriteIdentifierRank(account: String) -> [String: NSNumber] { - - var listIdentifierRank: [String: NSNumber] = [:] - let realm = try! Realm() - var counter = 10 as Int64 - - let results = realm.objects(tableMetadata.self).filter("account == %@ AND directory == true AND favorite == true", account).sorted(byKeyPath: "fileNameView", ascending: true) - - for result in results { - counter += 1 - listIdentifierRank[result.ocId] = NSNumber(value: Int64(counter)) - } - - return listIdentifierRank - } - - @objc func clearMetadatasUpload(account: String) { - - let realm = try! Realm() - realm.refresh() - - do { - try realm.safeWrite { - - let results = realm.objects(tableMetadata.self).filter("account == %@ AND (status == %d OR status == %@)", account, NCGlobal.shared.metadataStatusWaitUpload, NCGlobal.shared.metadataStatusUploadError) - realm.delete(results) - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func readMarkerMetadata(account: String, fileId: String) { - - let realm = try! Realm() - - do { - try realm.safeWrite { - let results = realm.objects(tableMetadata.self).filter("account == %@ AND fileId == %@", account, fileId) - for result in results { - result.commentsUnread = false - } + let result = realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first + result?.offline = offline } } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - - @objc func getAssetLocalIdentifiersUploaded(account: String, sessionSelector: String) -> [String] { - - let realm = try! Realm() - realm.refresh() - - var assetLocalIdentifiers: [String] = [] - - let results = realm.objects(tableMetadata.self).filter("account == %@ AND assetLocalIdentifier != '' AND deleteAssetLocalIdentifier == true AND sessionSelector == %@", account, sessionSelector) - for result in results { - assetLocalIdentifiers.append(result.assetLocalIdentifier) - } - - return assetLocalIdentifiers - } - - @objc func clearAssetLocalIdentifiers(_ assetLocalIdentifiers: [String], account: String) { - - let realm = try! Realm() - do { - try realm.safeWrite { - let results = realm.objects(tableMetadata.self).filter("account == %@ AND assetLocalIdentifier IN %@", account, assetLocalIdentifiers) - for result in results { - result.assetLocalIdentifier = "" - result.deleteAssetLocalIdentifier = false - } - } - } catch let error { - NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") - } - } - - @objc func getMetadataLivePhoto(metadata: tableMetadata) -> tableMetadata? { - - let realm = try! Realm() - var classFile = metadata.classFile + // MARK: - + // MARK: Table Photo Library - realm.refresh() - - if !metadata.livePhoto || !CCUtility.getLivePhoto() { - return nil - } - - if classFile == NCCommunicationCommon.typeClassFile.image.rawValue { - classFile = NCCommunicationCommon.typeClassFile.video.rawValue - } else { - classFile = NCCommunicationCommon.typeClassFile.image.rawValue - } - - guard let result = realm.objects(tableMetadata.self).filter(NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameWithoutExt == %@ AND ocId != %@ AND classFile == %@", metadata.account, metadata.serverUrl, metadata.fileNameWithoutExt, metadata.ocId, classFile)).first else { - return nil - } - - return tableMetadata.init(value: result) - } - - func getMetadatasMedia(predicate: NSPredicate, sort: String, ascending: Bool = false) -> [tableMetadata] { - - let realm = try! Realm() - realm.refresh() - - let sortProperties = [SortDescriptor(keyPath: sort, ascending: ascending), SortDescriptor(keyPath: "fileNameView", ascending: false)] - let results = realm.objects(tableMetadata.self).filter(predicate).sorted(by: sortProperties) - - return Array(results.map { tableMetadata.init(value:$0) }) - } - - func isMetadataShareOrMounted(metadata: tableMetadata, metadataFolder: tableMetadata?) -> Bool { - - var isShare = false - var isMounted = false - - if metadataFolder != nil { - - isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !metadataFolder!.permissions.contains(NCGlobal.shared.permissionShared) - isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !metadataFolder!.permissions.contains(NCGlobal.shared.permissionMounted) - - } else if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)) { - - isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !directory.permissions.contains(NCGlobal.shared.permissionShared) - isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !directory.permissions.contains(NCGlobal.shared.permissionMounted) - } - - if isShare || isMounted { - return true - } else { - return false - } - } - - func isDownloadMetadata(_ metadata: tableMetadata, download: Bool) -> Bool { - - let localFile = getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) - let fileSize = CCUtility.fileProviderStorageSize(metadata.ocId, fileNameView: metadata.fileNameView) - if (localFile != nil || download) && (localFile?.etag != metadata.etag || fileSize == 0) { - return true - } - return false - } - - func getMetadataConflict(account: String, serverUrl: String, fileName: String) -> tableMetadata? { - - // verify exists conflict - let fileNameExtension = (fileName as NSString).pathExtension.lowercased() - let fileNameWithoutExtension = (fileName as NSString).deletingPathExtension - var fileNameConflict = fileName - - if fileNameExtension == "heic" && CCUtility.getFormatCompatibility() { - fileNameConflict = fileNameWithoutExtension + ".jpg" - } - return getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView == %@", account, serverUrl, fileNameConflict)) - } - - //MARK: - - //MARK: Table Photo Library - @discardableResult @objc func addPhotoLibrary(_ assets: [PHAsset], account: String) -> Bool { - + let realm = try! Realm() do { try realm.safeWrite { - + var creationDateString = "" for asset in assets { - + let addObject = tablePhotoLibrary() - + addObject.account = account addObject.assetLocalIdentifier = asset.localIdentifier addObject.mediaType = asset.mediaType.rawValue - + if let creationDate = asset.creationDate { addObject.creationDate = creationDate as NSDate creationDateString = String(describing: creationDate) } else { creationDateString = "" } - + if let modificationDate = asset.modificationDate { addObject.modificationDate = modificationDate as NSDate } - + addObject.idAsset = "\(account)\(asset.localIdentifier)\(creationDateString)" realm.add(addObject, update: .all) @@ -2771,54 +1299,54 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") return false } - + return true } - + @objc func getPhotoLibraryIdAsset(image: Bool, video: Bool, account: String) -> [String]? { - + let realm = try! Realm() var predicate = NSPredicate() - - if (image && video) { - + + if image && video { + predicate = NSPredicate(format: "account == %@ AND (mediaType == %d OR mediaType == %d)", account, PHAssetMediaType.image.rawValue, PHAssetMediaType.video.rawValue) - - } else if (image) { - + + } else if image { + predicate = NSPredicate(format: "account == %@ AND mediaType == %d", account, PHAssetMediaType.image.rawValue) - } else if (video) { - + } else if video { + predicate = NSPredicate(format: "account == %@ AND mediaType == %d", account, PHAssetMediaType.video.rawValue) } - + let results = realm.objects(tablePhotoLibrary.self).filter(predicate) - + let idsAsset = results.map { $0.idAsset } - + return Array(idsAsset) } - - //MARK: - - //MARK: Table Share - + + // MARK: - + // MARK: Table Share + @objc func addShare(urlBase: String, account: String, shares: [NCCommunicationShare]) { - + let realm = try! Realm() realm.beginWrite() for share in shares { - + let addObject = tableShare() let fullPath = NCUtilityFileSystem.shared.getHomeServer(account: account) + share.path - let serverUrl = NCUtilityFileSystem.shared.deletingLastPathComponent(account: account, serverUrl:fullPath) + let serverUrl = NCUtilityFileSystem.shared.deletingLastPathComponent(account: account, serverUrl: fullPath) let fileName = NSString(string: fullPath).lastPathComponent - + addObject.account = account addObject.fileName = fileName addObject.serverUrl = serverUrl - + addObject.canEdit = share.canEdit addObject.canDelete = share.canDelete addObject.date = share.date @@ -2857,179 +1385,179 @@ class NCManageDatabase: NSObject { realm.add(addObject, update: .all) } - + do { try realm.commitWrite() } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func getTableShares(account: String) -> [tableShare] { - + let realm = try! Realm() - + let sortProperties = [SortDescriptor(keyPath: "shareType", ascending: false), SortDescriptor(keyPath: "idShare", ascending: false)] let results = realm.objects(tableShare.self).filter("account == %@", account).sorted(by: sortProperties) - - return Array(results.map { tableShare.init(value:$0) }) + + return Array(results.map { tableShare.init(value: $0) }) } - - func getTableShares(metadata: tableMetadata) -> (firstShareLink: tableShare?, share: [tableShare]?) { - + + func getTableShares(metadata: tableMetadata) -> (firstShareLink: tableShare?, share: [tableShare]?) { + let realm = try! Realm() - + let sortProperties = [SortDescriptor(keyPath: "shareType", ascending: false), SortDescriptor(keyPath: "idShare", ascending: false)] - + let firstShareLink = realm.objects(tableShare.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@ AND shareType == 3", metadata.account, metadata.serverUrl, metadata.fileName).first - + if firstShareLink == nil { - + let results = realm.objects(tableShare.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@", metadata.account, metadata.serverUrl, metadata.fileName).sorted(by: sortProperties) - return(firstShareLink: firstShareLink, share: Array(results.map { tableShare.init(value:$0) })) - + return(firstShareLink: firstShareLink, share: Array(results.map { tableShare.init(value: $0) })) + } else { - + let results = realm.objects(tableShare.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@ AND idShare != %d", metadata.account, metadata.serverUrl, metadata.fileName, firstShareLink!.idShare).sorted(by: sortProperties) - return(firstShareLink: firstShareLink, share: Array(results.map { tableShare.init(value:$0) })) + return(firstShareLink: firstShareLink, share: Array(results.map { tableShare.init(value: $0) })) } } - + func getTableShare(account: String, idShare: Int) -> tableShare? { - + let realm = try! Realm() - + guard let result = realm.objects(tableShare.self).filter("account = %@ AND idShare = %d", account, idShare).first else { return nil } - + return tableShare.init(value: result) } - + @objc func getTableShares(account: String, serverUrl: String) -> [tableShare] { - + let realm = try! Realm() - + let sortProperties = [SortDescriptor(keyPath: "shareType", ascending: false), SortDescriptor(keyPath: "idShare", ascending: false)] let results = realm.objects(tableShare.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).sorted(by: sortProperties) - return Array(results.map { tableShare.init(value:$0) }) + return Array(results.map { tableShare.init(value: $0) }) } - + @objc func getTableShares(account: String, serverUrl: String, fileName: String) -> [tableShare] { - + let realm = try! Realm() - + let sortProperties = [SortDescriptor(keyPath: "shareType", ascending: false), SortDescriptor(keyPath: "idShare", ascending: false)] let results = realm.objects(tableShare.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@", account, serverUrl, fileName).sorted(by: sortProperties) - - return Array(results.map { tableShare.init(value:$0) }) + + return Array(results.map { tableShare.init(value: $0) }) } - + @objc func deleteTableShare(account: String, idShare: Int) { - + let realm = try! Realm() - + realm.beginWrite() - + let result = realm.objects(tableShare.self).filter("account == %@ AND idShare == %d", account, idShare) realm.delete(result) - + do { try realm.commitWrite() } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func deleteTableShare(account: String) { - + let realm = try! Realm() - + realm.beginWrite() - + let result = realm.objects(tableShare.self).filter("account == %@", account) realm.delete(result) - + do { try realm.commitWrite() } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - - //MARK: - - //MARK: Table Tag - - @objc func addTag(_ ocId: String ,tagIOS: Data?, account: String) { - + + // MARK: - + // MARK: Table Tag + + @objc func addTag(_ ocId: String, tagIOS: Data?, account: String) { + let realm = try! Realm() - + do { try realm.safeWrite { - + // Add new let addObject = tableTag() - + addObject.account = account addObject.ocId = ocId addObject.tagIOS = tagIOS - + realm.add(addObject, update: .all) } } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func deleteTag(_ ocId: String) { - + let realm = try! Realm() - + realm.beginWrite() - + let result = realm.objects(tableTag.self).filter("ocId == %@", ocId) realm.delete(result) - + do { try realm.commitWrite() } catch let error { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func getTags(predicate: NSPredicate) -> [tableTag] { - + let realm = try! Realm() let results = realm.objects(tableTag.self).filter(predicate) - - return Array(results.map { tableTag.init(value:$0) }) + + return Array(results.map { tableTag.init(value: $0) }) } - + @objc func getTag(predicate: NSPredicate) -> tableTag? { - + let realm = try! Realm() - + guard let result = realm.objects(tableTag.self).filter(predicate).first else { return nil } - + return tableTag.init(value: result) } - - //MARK: - - //MARK: Table Trash - + + // MARK: - + // MARK: Table Trash + @objc func addTrash(account: String, items: [NCCommunicationTrash]) { - + let realm = try! Realm() - + do { try realm.safeWrite { for trash in items { let object = tableTrash() - + object.account = account object.contentType = trash.contentType object.date = trash.date @@ -3044,7 +1572,7 @@ class NCManageDatabase: NSObject { object.trashbinFileName = trash.trashbinFileName object.trashbinOriginalLocation = trash.trashbinOriginalLocation object.classFile = trash.classFile - + realm.add(object, update: .all) } } @@ -3052,21 +1580,21 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func deleteTrash(filePath: String?, account: String) { - + let realm = try! Realm() var predicate = NSPredicate() do { try realm.safeWrite { - + if filePath == nil { predicate = NSPredicate(format: "account == %@", account) } else { predicate = NSPredicate(format: "account == %@ AND filePath == %@", account, filePath!) } - + let result = realm.objects(tableTrash.self).filter(predicate) realm.delete(result) } @@ -3074,21 +1602,21 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + @objc func deleteTrash(fileId: String?, account: String) { - + let realm = try! Realm() var predicate = NSPredicate() do { try realm.safeWrite { - + if fileId == nil { predicate = NSPredicate(format: "account == %@", account) } else { predicate = NSPredicate(format: "account == %@ AND fileId == %@", account, fileId!) } - + let result = realm.objects(tableTrash.self).filter(predicate) realm.delete(result) } @@ -3096,46 +1624,46 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + func getTrash(filePath: String, sort: String?, ascending: Bool?, account: String) -> [tableTrash]? { - + let realm = try! Realm() let sort = sort ?? "date" let ascending = ascending ?? false - + let results = realm.objects(tableTrash.self).filter("account == %@ AND filePath == %@", account, filePath).sorted(byKeyPath: sort, ascending: ascending) - return Array(results.map { tableTrash.init(value:$0) }) + return Array(results.map { tableTrash.init(value: $0) }) } - + @objc func getTrashItem(fileId: String, account: String) -> tableTrash? { - + let realm = try! Realm() - + guard let result = realm.objects(tableTrash.self).filter("account == %@ AND fileId == %@", account, fileId).first else { return nil } - + return tableTrash.init(value: result) } - - //MARK: - - //MARK: Table UserStatus - + + // MARK: - + // MARK: Table UserStatus + @objc func addUserStatus(_ userStatuses: [NCCommunicationUserStatus], account: String, predefined: Bool) { - + let realm = try! Realm() - + do { try realm.safeWrite { - + let results = realm.objects(tableUserStatus.self).filter("account == %@ AND predefined == %@", account, predefined) realm.delete(results) - + for userStatus in userStatuses { - + let object = tableUserStatus() - + object.account = account object.clearAt = userStatus.clearAt object.clearAtTime = userStatus.clearAtTime @@ -3146,7 +1674,7 @@ class NCManageDatabase: NSObject { object.predefined = userStatus.predefined object.status = userStatus.status object.userId = userStatus.userId - + realm.add(object) } } @@ -3154,18 +1682,18 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - //MARK: - - //MARK: Table Video - + // MARK: - + // MARK: Table Video + func addVideoTime(metadata: tableMetadata, time: CMTime?, durationTime: CMTime?) { - + if metadata.livePhoto { return } let realm = try! Realm() - + do { try realm.safeWrite { if let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first { - + if let durationTime = durationTime { result.duration = durationTime.convertScale(1000, method: .default).value } @@ -3175,9 +1703,9 @@ class NCManageDatabase: NSObject { realm.add(result, update: .all) } else { - + let addObject = tableVideo() - + addObject.account = metadata.account if let durationTime = durationTime { addObject.duration = durationTime.convertScale(1000, method: .default).value @@ -3193,38 +1721,38 @@ class NCManageDatabase: NSObject { NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") } } - + func getVideoDurationTime(metadata: tableMetadata?) -> CMTime? { guard let metadata = metadata else { return nil } if metadata.livePhoto { return nil } let realm = try! Realm() - + guard let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first else { return nil } - + if result.duration == 0 { return nil } let duration = CMTimeMake(value: result.duration, timescale: 1000) return duration } - + func getVideoTime(metadata: tableMetadata) -> CMTime? { - + if metadata.livePhoto { return nil } let realm = try! Realm() - + guard let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first else { return nil } - + if result.time == 0 { return nil } let time = CMTimeMake(value: result.time, timescale: 1000) return time } - + func deleteVideo(metadata: tableMetadata) { - + let realm = try! Realm() do { @@ -3238,7 +1766,7 @@ class NCManageDatabase: NSObject { } } -//MARK: - +// MARK: - extension Realm { public func safeWrite(_ block: (() throws -> Void)) throws { diff --git a/iOSClient/Data/NCManageDatabse+Metadata.swift b/iOSClient/Data/NCManageDatabse+Metadata.swift new file mode 100644 index 000000000..bc45836a8 --- /dev/null +++ b/iOSClient/Data/NCManageDatabse+Metadata.swift @@ -0,0 +1,789 @@ +// +// NCManageDatabse+Metadata.swift +// Nextcloud +// +// Created by Henrik Storch on 30.11.21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation +import RealmSwift +import NCCommunication + +extension NCManageDatabase { + + @objc func copyObject(metadata: tableMetadata) -> tableMetadata { + return tableMetadata.init(value: metadata) + } + + @objc func convertNCFileToMetadata(_ file: NCCommunicationFile, isEncrypted: Bool, account: String) -> tableMetadata { + + let metadata = tableMetadata() + + metadata.account = account + metadata.checksums = file.checksums + metadata.commentsUnread = file.commentsUnread + metadata.contentType = file.contentType + if let date = file.creationDate { + metadata.creationDate = date + } else { + metadata.creationDate = file.date + } + metadata.dataFingerprint = file.dataFingerprint + metadata.date = file.date + metadata.directory = file.directory + metadata.downloadURL = file.downloadURL + metadata.e2eEncrypted = file.e2eEncrypted + metadata.etag = file.etag + metadata.ext = file.ext + metadata.favorite = file.favorite + metadata.fileId = file.fileId + metadata.fileName = file.fileName + metadata.fileNameView = file.fileName + metadata.fileNameWithoutExt = file.fileNameWithoutExt + metadata.hasPreview = file.hasPreview + metadata.iconName = file.iconName + metadata.livePhoto = file.livePhoto + metadata.mountType = file.mountType + metadata.note = file.note + metadata.ocId = file.ocId + metadata.ownerId = file.ownerId + metadata.ownerDisplayName = file.ownerDisplayName + metadata.path = file.path + metadata.permissions = file.permissions + metadata.quotaUsedBytes = file.quotaUsedBytes + metadata.quotaAvailableBytes = file.quotaAvailableBytes + metadata.richWorkspace = file.richWorkspace + metadata.resourceType = file.resourceType + metadata.serverUrl = file.serverUrl + metadata.sharePermissionsCollaborationServices = file.sharePermissionsCollaborationServices + for element in file.sharePermissionsCloudMesh { + metadata.sharePermissionsCloudMesh.append(element) + } + for element in file.shareType { + metadata.shareType.append(element) + } + metadata.size = file.size + metadata.classFile = file.classFile + if let date = file.uploadDate { + metadata.uploadDate = date + } else { + metadata.uploadDate = file.date + } + metadata.urlBase = file.urlBase + metadata.user = file.user + metadata.userId = file.userId + + // E2EE find the fileName for fileNameView + if isEncrypted || metadata.e2eEncrypted { + if let tableE2eEncryption = NCManageDatabase.shared.getE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameIdentifier == %@", account, file.serverUrl, file.fileName)) { + metadata.fileNameView = tableE2eEncryption.fileName + let results = NCCommunicationCommon.shared.getInternalType(fileName: metadata.fileNameView, mimeType: file.contentType, directory: file.directory) + metadata.contentType = results.mimeType + metadata.iconName = results.iconName + metadata.classFile = results.classFile + } + } + + // Live Photo "DETECT" + if !metadata.directory && !metadata.livePhoto && (metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue) { + var classFile = metadata.classFile + if classFile == NCCommunicationCommon.typeClassFile.image.rawValue { + classFile = NCCommunicationCommon.typeClassFile.video.rawValue + } else { + classFile = NCCommunicationCommon.typeClassFile.image.rawValue + } + if getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameWithoutExt == %@ AND ocId != %@ AND classFile == %@", metadata.account, metadata.serverUrl, metadata.fileNameWithoutExt, metadata.ocId, classFile)) != nil { + metadata.livePhoto = true + } + } + + return metadata + } + + @objc func convertNCCommunicationFilesToMetadatas(_ files: [NCCommunicationFile], useMetadataFolder: Bool, account: String, completion: @escaping (_ metadataFolder: tableMetadata, _ metadatasFolder: [tableMetadata], _ metadatas: [tableMetadata]) -> Void) { + + var counter: Int = 0 + var isEncrypted: Bool = false + var listServerUrl: [String: Bool] = [:] + + var metadataFolder = tableMetadata() + var metadataFolders: [tableMetadata] = [] + var metadatas: [tableMetadata] = [] + + for file in files { + + if let key = listServerUrl[file.serverUrl] { + isEncrypted = key + } else { + isEncrypted = CCUtility.isFolderEncrypted(file.serverUrl, e2eEncrypted: file.e2eEncrypted, account: account, urlBase: file.urlBase) + listServerUrl[file.serverUrl] = isEncrypted + } + + let metadata = convertNCFileToMetadata(file, isEncrypted: isEncrypted, account: account) + + if counter == 0 && useMetadataFolder { + metadataFolder = tableMetadata.init(value: metadata) + } else { + metadatas.append(metadata) + if metadata.directory { + metadataFolders.append(metadata) + } + } + + counter += 1 + } + + completion(metadataFolder, metadataFolders, metadatas) + } + + @objc func createMetadata(account: String, user: String, userId: String, fileName: String, fileNameView: String, ocId: String, serverUrl: String, urlBase: String, url: String, contentType: String, livePhoto: Bool) -> tableMetadata { + + let metadata = tableMetadata() + let resultInternalType = NCCommunicationCommon.shared.getInternalType(fileName: fileName, mimeType: contentType, directory: false) + + metadata.account = account + metadata.chunk = false + metadata.contentType = resultInternalType.mimeType + metadata.creationDate = Date() as NSDate + metadata.date = Date() as NSDate + metadata.hasPreview = true + metadata.iconName = resultInternalType.iconName + metadata.etag = ocId + metadata.ext = (fileName as NSString).pathExtension.lowercased() + metadata.fileName = fileName + metadata.fileNameView = fileName + metadata.fileNameWithoutExt = (fileName as NSString).deletingPathExtension + metadata.livePhoto = livePhoto + metadata.ocId = ocId + metadata.permissions = "RGDNVW" + metadata.serverUrl = serverUrl + metadata.classFile = resultInternalType.classFile + metadata.uploadDate = Date() as NSDate + metadata.url = url + metadata.urlBase = urlBase + metadata.user = user + metadata.userId = userId + + return metadata + } + + @objc func addMetadata(_ metadata: tableMetadata) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + realm.add(metadata, update: .all) + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func addMetadatas(_ metadatas: [tableMetadata]) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + for metadata in metadatas { + realm.add(metadata, update: .all) + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func deleteMetadata(predicate: NSPredicate) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + let results = realm.objects(tableMetadata.self).filter(predicate) + realm.delete(results) + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func moveMetadata(ocId: String, serverUrlTo: String) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + if let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first { + result.serverUrl = serverUrlTo + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func addMetadataServerUrl(ocId: String, serverUrl: String) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + let results = realm.objects(tableMetadata.self).filter("ocId == %@", ocId) + for result in results { + result.serverUrl = serverUrl + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func renameMetadata(fileNameTo: String, ocId: String) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + if let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first { + let resultsType = NCCommunicationCommon.shared.getInternalType(fileName: fileNameTo, mimeType: "", directory: result.directory) + result.fileName = fileNameTo + result.fileNameView = fileNameTo + if result.directory { + result.fileNameWithoutExt = fileNameTo + result.ext = "" + } else { + result.fileNameWithoutExt = (fileNameTo as NSString).deletingPathExtension + result.ext = resultsType.ext + } + result.iconName = resultsType.iconName + result.contentType = resultsType.mimeType + result.classFile = resultsType.classFile + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @discardableResult + func updateMetadatas(_ metadatas: [tableMetadata], metadatasResult: [tableMetadata], addCompareLivePhoto: Bool = true, addExistsInLocal: Bool = false, addCompareEtagLocal: Bool = false, addDirectorySynchronized: Bool = false) -> (metadatasUpdate: [tableMetadata], metadatasLocalUpdate: [tableMetadata], metadatasDelete: [tableMetadata]) { + + let realm = try! Realm() + var ocIdsUdate: [String] = [] + var ocIdsLocalUdate: [String] = [] + var metadatasDelete: [tableMetadata] = [] + var metadatasUpdate: [tableMetadata] = [] + var metadatasLocalUpdate: [tableMetadata] = [] + + realm.refresh() + + do { + try realm.safeWrite { + + // DELETE + for metadataResult in metadatasResult { + if metadatas.firstIndex(where: { $0.ocId == metadataResult.ocId }) == nil { + if let result = realm.objects(tableMetadata.self).filter(NSPredicate(format: "ocId == %@", metadataResult.ocId)).first { + metadatasDelete.append(tableMetadata.init(value: result)) + realm.delete(result) + } + } + } + + // UPDATE/NEW + for metadata in metadatas { + + if let result = metadatasResult.first(where: { $0.ocId == metadata.ocId }) { + // update + if result.status == NCGlobal.shared.metadataStatusNormal && (result.etag != metadata.etag || result.fileNameView != metadata.fileNameView || result.date != metadata.date || result.permissions != metadata.permissions || result.hasPreview != metadata.hasPreview || result.note != metadata.note) { + ocIdsUdate.append(metadata.ocId) + realm.add(tableMetadata.init(value: metadata), update: .all) + } else if result.status == NCGlobal.shared.metadataStatusNormal && addCompareLivePhoto && result.livePhoto != metadata.livePhoto { + ocIdsUdate.append(metadata.ocId) + realm.add(tableMetadata.init(value: metadata), update: .all) + } + } else { + // new + ocIdsUdate.append(metadata.ocId) + realm.add(tableMetadata.init(value: metadata), update: .all) + } + + if metadata.directory && !ocIdsUdate.contains(metadata.ocId) { + let table = realm.objects(tableDirectory.self).filter(NSPredicate(format: "ocId == %@", metadata.ocId)).first + if table?.etag != metadata.etag { + ocIdsUdate.append(metadata.ocId) + } + } + + // Local + if !metadata.directory && (addExistsInLocal || addCompareEtagLocal) { + let localFile = realm.objects(tableLocalFile.self).filter(NSPredicate(format: "ocId == %@", metadata.ocId)).first + if addCompareEtagLocal && localFile != nil && localFile?.etag != metadata.etag { + ocIdsLocalUdate.append(metadata.ocId) + } + if addExistsInLocal && (localFile == nil || localFile?.etag != metadata.etag) && !ocIdsLocalUdate.contains(metadata.ocId) { + ocIdsLocalUdate.append(metadata.ocId) + } + } + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + + for ocId in ocIdsUdate { + if let result = realm.objects(tableMetadata.self).filter(NSPredicate(format: "ocId == %@", ocId)).first { + metadatasUpdate.append(tableMetadata.init(value: result)) + } + } + + for ocId in ocIdsLocalUdate { + if let result = realm.objects(tableMetadata.self).filter(NSPredicate(format: "ocId == %@", ocId)).first { + metadatasLocalUpdate.append(tableMetadata.init(value: result)) + } + } + + return (metadatasUpdate, metadatasLocalUpdate, metadatasDelete) + } + + func setMetadataSession(ocId: String, session: String? = nil, sessionError: String? = nil, sessionSelector: String? = nil, sessionTaskIdentifier: Int? = nil, status: Int? = nil, etag: String? = nil) { + + let realm = try! Realm() + realm.refresh() + + do { + try realm.safeWrite { + let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first + if let session = session { + result?.session = session + } + if let sessionError = sessionError { + result?.sessionError = sessionError + } + if let sessionSelector = sessionSelector { + result?.sessionSelector = sessionSelector + } + if let sessionTaskIdentifier = sessionTaskIdentifier { + result?.sessionTaskIdentifier = sessionTaskIdentifier + } + if let status = status { + result?.status = status + } + if let etag = etag { + result?.etag = etag + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @discardableResult + func setMetadataStatus(ocId: String, status: Int) -> tableMetadata? { + + let realm = try! Realm() + var result: tableMetadata? + + do { + try realm.safeWrite { + result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first + result?.status = status + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + + if let result = result { + return tableMetadata.init(value: result) + } else { + return nil + } + } + + func setMetadataEtagResource(ocId: String, etagResource: String?) { + + let realm = try! Realm() + var result: tableMetadata? + guard let etagResource = etagResource else { return } + + do { + try realm.safeWrite { + result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first + result?.etagResource = etagResource + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func setMetadataFavorite(ocId: String, favorite: Bool) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first + result?.favorite = favorite + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func updateMetadatasFavorite(account: String, metadatas: [tableMetadata]) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + let results = realm.objects(tableMetadata.self).filter("account == %@ AND favorite == true", account) + for result in results { + result.favorite = false + } + for metadata in metadatas { + realm.add(metadata, update: .all) + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func setMetadataEncrypted(ocId: String, encrypted: Bool) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first + result?.e2eEncrypted = encrypted + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func setMetadataFileNameView(serverUrl: String, fileName: String, newFileNameView: String, account: String) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + let result = realm.objects(tableMetadata.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@", account, serverUrl, fileName).first + result?.fileNameView = newFileNameView + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func getMetadata(predicate: NSPredicate) -> tableMetadata? { + + let realm = try! Realm() + realm.refresh() + + guard let result = realm.objects(tableMetadata.self).filter(predicate).first else { + return nil + } + + return tableMetadata.init(value: result) + } + + @objc func getMetadata(predicate: NSPredicate, sorted: String, ascending: Bool) -> tableMetadata? { + + let realm = try! Realm() + realm.refresh() + + guard let result = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending).first else { + return nil + } + + return tableMetadata.init(value: result) + } + + @objc func getMetadatasViewer(predicate: NSPredicate, sorted: String, ascending: Bool) -> [tableMetadata]? { + + let realm = try! Realm() + realm.refresh() + + let results: Results<tableMetadata> + var finals: [tableMetadata] = [] + + if (tableMetadata().objectSchema.properties.contains { $0.name == sorted }) { + results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending) + } else { + results = realm.objects(tableMetadata.self).filter(predicate) + } + + // For Live Photo + var fileNameImages: [String] = [] + let filtered = results.filter { $0.classFile.contains(NCCommunicationCommon.typeClassFile.image.rawValue) } + filtered.forEach { print($0) + let fileName = ($0.fileNameView as NSString).deletingPathExtension + fileNameImages.append(fileName) + } + + for result in results { + + let ext = (result.fileNameView as NSString).pathExtension.uppercased() + let fileName = (result.fileNameView as NSString).deletingPathExtension + + if !(ext == "MOV" && fileNameImages.contains(fileName)) { + finals.append(result) + } + } + + if finals.count > 0 { + return Array(finals.map { tableMetadata.init(value: $0) }) + } else { + return nil + } + } + + @objc func getMetadatas(predicate: NSPredicate) -> [tableMetadata] { + + let realm = try! Realm() + realm.refresh() + + let results = realm.objects(tableMetadata.self).filter(predicate) + + return Array(results.map { tableMetadata.init(value: $0) }) + } + + @objc func getAdvancedMetadatas(predicate: NSPredicate, page: Int = 0, limit: Int = 0, sorted: String, ascending: Bool) -> [tableMetadata] { + + let realm = try! Realm() + realm.refresh() + var metadatas: [tableMetadata] = [] + + let results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending) + + if results.count > 0 { + if page == 0 || limit == 0 { + return Array(results.map { tableMetadata.init(value: $0) }) + } else { + + let nFrom = (page - 1) * limit + let nTo = nFrom + (limit - 1) + + for n in nFrom...nTo { + if n == results.count { + break + } + metadatas.append(tableMetadata.init(value: results[n])) + } + } + } + return metadatas + } + + @objc func getMetadataAtIndex(predicate: NSPredicate, sorted: String, ascending: Bool, index: Int) -> tableMetadata? { + + let realm = try! Realm() + realm.refresh() + + let results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending) + + if results.count > 0 && results.count > index { + return tableMetadata.init(value: results[index]) + } else { + return nil + } + } + + @objc func getMetadataFromOcId(_ ocId: String?) -> tableMetadata? { + + let realm = try! Realm() + realm.refresh() + + guard let ocId = ocId else { return nil } + guard let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first else { return nil } + + return tableMetadata.init(value: result) + } + + @objc func getMetadataFolder(account: String, urlBase: String, serverUrl: String) -> tableMetadata? { + + let realm = try! Realm() + realm.refresh() + var serverUrl = serverUrl + var fileName = "" + + let serverUrlHome = NCUtilityFileSystem.shared.getHomeServer(account: account) + if serverUrlHome == serverUrl { + fileName = "." + serverUrl = ".." + } else { + fileName = (serverUrl as NSString).lastPathComponent + serverUrl = NCUtilityFileSystem.shared.deletingLastPathComponent(account: account, serverUrl: serverUrl) + } + + guard let result = realm.objects(tableMetadata.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@", account, serverUrl, fileName).first else { return nil } + + return tableMetadata.init(value: result) + } + + @objc func getTableMetadatasDirectoryFavoriteIdentifierRank(account: String) -> [String: NSNumber] { + + var listIdentifierRank: [String: NSNumber] = [:] + let realm = try! Realm() + var counter = 10 as Int64 + + let results = realm.objects(tableMetadata.self).filter("account == %@ AND directory == true AND favorite == true", account).sorted(byKeyPath: "fileNameView", ascending: true) + + for result in results { + counter += 1 + listIdentifierRank[result.ocId] = NSNumber(value: Int64(counter)) + } + + return listIdentifierRank + } + + @objc func clearMetadatasUpload(account: String) { + + let realm = try! Realm() + realm.refresh() + + do { + try realm.safeWrite { + + let results = realm.objects(tableMetadata.self).filter("account == %@ AND (status == %d OR status == %@)", account, NCGlobal.shared.metadataStatusWaitUpload, NCGlobal.shared.metadataStatusUploadError) + realm.delete(results) + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func readMarkerMetadata(account: String, fileId: String) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + let results = realm.objects(tableMetadata.self).filter("account == %@ AND fileId == %@", account, fileId) + for result in results { + result.commentsUnread = false + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func getAssetLocalIdentifiersUploaded(account: String, sessionSelector: String) -> [String] { + + let realm = try! Realm() + realm.refresh() + + var assetLocalIdentifiers: [String] = [] + + let results = realm.objects(tableMetadata.self).filter("account == %@ AND assetLocalIdentifier != '' AND deleteAssetLocalIdentifier == true AND sessionSelector == %@", account, sessionSelector) + for result in results { + assetLocalIdentifiers.append(result.assetLocalIdentifier) + } + + return assetLocalIdentifiers + } + + @objc func clearAssetLocalIdentifiers(_ assetLocalIdentifiers: [String], account: String) { + + let realm = try! Realm() + + do { + try realm.safeWrite { + let results = realm.objects(tableMetadata.self).filter("account == %@ AND assetLocalIdentifier IN %@", account, assetLocalIdentifiers) + for result in results { + result.assetLocalIdentifier = "" + result.deleteAssetLocalIdentifier = false + } + } + } catch let error { + NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)") + } + } + + @objc func getMetadataLivePhoto(metadata: tableMetadata) -> tableMetadata? { + + let realm = try! Realm() + var classFile = metadata.classFile + + realm.refresh() + + if !metadata.livePhoto || !CCUtility.getLivePhoto() { + return nil + } + + if classFile == NCCommunicationCommon.typeClassFile.image.rawValue { + classFile = NCCommunicationCommon.typeClassFile.video.rawValue + } else { + classFile = NCCommunicationCommon.typeClassFile.image.rawValue + } + + guard let result = realm.objects(tableMetadata.self).filter(NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameWithoutExt == %@ AND ocId != %@ AND classFile == %@", metadata.account, metadata.serverUrl, metadata.fileNameWithoutExt, metadata.ocId, classFile)).first else { + return nil + } + + return tableMetadata.init(value: result) + } + + func getMetadatasMedia(predicate: NSPredicate, sort: String, ascending: Bool = false) -> [tableMetadata] { + + let realm = try! Realm() + realm.refresh() + + let sortProperties = [SortDescriptor(keyPath: sort, ascending: ascending), SortDescriptor(keyPath: "fileNameView", ascending: false)] + let results = realm.objects(tableMetadata.self).filter(predicate).sorted(by: sortProperties) + + return Array(results.map { tableMetadata.init(value: $0) }) + } + + func isMetadataShareOrMounted(metadata: tableMetadata, metadataFolder: tableMetadata?) -> Bool { + + var isShare = false + var isMounted = false + + if metadataFolder != nil { + + isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !metadataFolder!.permissions.contains(NCGlobal.shared.permissionShared) + isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !metadataFolder!.permissions.contains(NCGlobal.shared.permissionMounted) + + } else if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)) { + + isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !directory.permissions.contains(NCGlobal.shared.permissionShared) + isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !directory.permissions.contains(NCGlobal.shared.permissionMounted) + } + + if isShare || isMounted { + return true + } else { + return false + } + } + + func isDownloadMetadata(_ metadata: tableMetadata, download: Bool) -> Bool { + + let localFile = getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) + let fileSize = CCUtility.fileProviderStorageSize(metadata.ocId, fileNameView: metadata.fileNameView) + if (localFile != nil || download) && (localFile?.etag != metadata.etag || fileSize == 0) { + return true + } + return false + } + + func getMetadataConflict(account: String, serverUrl: String, fileName: String) -> tableMetadata? { + + // verify exists conflict + let fileNameExtension = (fileName as NSString).pathExtension.lowercased() + let fileNameWithoutExtension = (fileName as NSString).deletingPathExtension + var fileNameConflict = fileName + + if fileNameExtension == "heic" && CCUtility.getFormatCompatibility() { + fileNameConflict = fileNameWithoutExtension + ".jpg" + } + return getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView == %@", account, serverUrl, fileNameConflict)) + } +} diff --git a/iOSClient/Diagnostics/NCCapabilitiesViewController.swift b/iOSClient/Diagnostics/NCCapabilitiesViewController.swift index 61679ac9b..c8d4ada34 100644 --- a/iOSClient/Diagnostics/NCCapabilitiesViewController.swift +++ b/iOSClient/Diagnostics/NCCapabilitiesViewController.swift @@ -27,63 +27,63 @@ import NCCommunication class NCCapabilitiesViewController: UIViewController, UIDocumentInteractionControllerDelegate { @IBOutlet weak var textView: UITextView! - + @IBOutlet weak var imageFileSharing: UIImageView! @IBOutlet weak var statusFileSharing: UILabel! - + @IBOutlet weak var imageExternalSite: UIImageView! @IBOutlet weak var statusExternalSite: UILabel! - + @IBOutlet weak var imageEndToEndEncryption: UIImageView! @IBOutlet weak var statusEndToEndEncryption: UILabel! - + @IBOutlet weak var imageActivity: UIImageView! @IBOutlet weak var statusActivity: UILabel! - + @IBOutlet weak var imageNotification: UIImageView! @IBOutlet weak var statusNotification: UILabel! - + @IBOutlet weak var imageDeletedFiles: UIImageView! @IBOutlet weak var statusDeletedFiles: UILabel! - + @IBOutlet weak var imageUserStatus: UIImageView! @IBOutlet weak var statusUserStatus: UILabel! - + @IBOutlet weak var imageComments: UIImageView! @IBOutlet weak var statusComments: UILabel! - + @IBOutlet weak var imageText: UIImageView! @IBOutlet weak var statusText: UILabel! - + @IBOutlet weak var imageCollabora: UIImageView! @IBOutlet weak var statusCollabora: UILabel! - + @IBOutlet weak var imageOnlyOffice: UIImageView! @IBOutlet weak var statusOnlyOffice: UILabel! - + @IBOutlet weak var homeImage: UIImageView! @IBOutlet weak var homeServer: UILabel! - + private let appDelegate = UIApplication.shared.delegate as! AppDelegate private var documentController: UIDocumentInteractionController? private var account: String = "" private var capabilitiesText = "" - //private var timer: Timer? - + // private var timer: Timer? + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + self.title = NSLocalizedString("_capabilities_", comment: "") - - let shareImage = UIImage.init(named: "shareFill")!.image(color: .gray, size: 25) + + let shareImage = UIImage(named: "shareFill")!.image(color: .gray, size: 25) self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: shareImage, style: UIBarButtonItem.Style.plain, target: self, action: #selector(share)) self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(close)) textView.layer.cornerRadius = 15 textView.layer.masksToBounds = true - + statusFileSharing.layer.cornerRadius = 12.5 statusFileSharing.layer.borderWidth = 0.5 statusFileSharing.layer.borderColor = UIColor.gray.cgColor @@ -139,77 +139,77 @@ class NCCapabilitiesViewController: UIViewController, UIDocumentInteractionContr statusComments.layer.borderColor = UIColor.gray.cgColor statusComments.layer.masksToBounds = true - imageFileSharing.image = UIImage.init(named: "share")!.image(color: NCBrandColor.shared.gray, size: 50) + imageFileSharing.image = UIImage(named: "share")!.image(color: NCBrandColor.shared.gray, size: 50) imageExternalSite.image = NCUtility.shared.loadImage(named: "network", color: NCBrandColor.shared.gray) imageEndToEndEncryption.image = NCUtility.shared.loadImage(named: "lock", color: NCBrandColor.shared.gray) - imageActivity.image = UIImage.init(named: "bolt")!.image(color: NCBrandColor.shared.gray, size: 50) + imageActivity.image = UIImage(named: "bolt")!.image(color: NCBrandColor.shared.gray, size: 50) imageNotification.image = NCUtility.shared.loadImage(named: "bell", color: NCBrandColor.shared.gray) imageDeletedFiles.image = NCUtility.shared.loadImage(named: "trash", color: NCBrandColor.shared.gray) - imageText.image = UIImage.init(named: "text")!.image(color: NCBrandColor.shared.gray, size: 50) - imageCollabora.image = UIImage.init(named: "collabora")!.image(color: NCBrandColor.shared.gray, size: 50) - imageOnlyOffice.image = UIImage.init(named: "onlyoffice")!.image(color: NCBrandColor.shared.gray, size: 50) - imageUserStatus.image = UIImage.init(named: "userStatusAway")!.image(color: NCBrandColor.shared.gray, size: 50) - imageComments.image = UIImage.init(named: "comments")!.image(color: NCBrandColor.shared.gray, size: 50) + imageText.image = UIImage(named: "text")!.image(color: NCBrandColor.shared.gray, size: 50) + imageCollabora.image = UIImage(named: "collabora")!.image(color: NCBrandColor.shared.gray, size: 50) + imageOnlyOffice.image = UIImage(named: "onlyoffice")!.image(color: NCBrandColor.shared.gray, size: 50) + imageUserStatus.image = UIImage(named: "userStatusAway")!.image(color: NCBrandColor.shared.gray, size: 50) + imageComments.image = UIImage(named: "comments")!.image(color: NCBrandColor.shared.gray, size: 50) guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return } self.account = activeAccount.account - + if let text = NCManageDatabase.shared.getCapabilities(account: activeAccount.account) { capabilitiesText = text updateCapabilities() } else { NCContentPresenter.shared.messageNotification("_error_", description: "_no_capabilities_found_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorInternalError, priority: .max) - + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { self.dismiss(animated: true, completion: nil) } } - - homeImage.image = UIImage.init(named: "home")!.image(color: NCBrandColor.shared.gray, size: 50) + + homeImage.image = UIImage(named: "home")!.image(color: NCBrandColor.shared.gray, size: 50) homeServer.text = NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) + "/" } @objc func updateCapabilities() { - - NCCommunication.shared.getCapabilities() { (account, data, errorCode, errorDescription) in + + NCCommunication.shared.getCapabilities { account, data, errorCode, _ in if errorCode == 0 && data != nil { NCManageDatabase.shared.addCapabilitiesJSon(data!, account: account) - + // EDITORS let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesVersionMajor) if serverVersionMajor >= NCGlobal.shared.nextcloudVersion18 { - NCCommunication.shared.NCTextObtainEditorDetails() { (account, editors, creators, errorCode, errorMessage) in + NCCommunication.shared.NCTextObtainEditorDetails { account, editors, creators, errorCode, _ in if errorCode == 0 && account == self.appDelegate.account { NCManageDatabase.shared.addDirectEditing(account: account, editors: editors, creators: creators) self.readCapabilities() } if self.view.window != nil { - //self.timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.updateCapabilities), userInfo: nil, repeats: false) + // self.timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.updateCapabilities), userInfo: nil, repeats: false) } } } else { if self.view.window != nil { - //self.timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.updateCapabilities), userInfo: nil, repeats: false) + // self.timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.updateCapabilities), userInfo: nil, repeats: false) } } - + if let text = NCManageDatabase.shared.getCapabilities(account: account) { self.capabilitiesText = text } self.readCapabilities() } } - + readCapabilities() } - + @objc func share() { - //timer?.invalidate() + // timer?.invalidate() self.dismiss(animated: true) { let fileURL = NSURL.fileURL(withPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent("capabilities.txt") do { try self.capabilitiesText.write(to: fileURL, atomically: true, encoding: .utf8) - + if let view = self.appDelegate.window?.rootViewController?.view { self.documentController = UIDocumentInteractionController(url: fileURL) self.documentController?.delegate = self @@ -218,58 +218,58 @@ class NCCapabilitiesViewController: UIViewController, UIDocumentInteractionContr } catch { } } } - + @objc func close() { - //timer?.invalidate() + // timer?.invalidate() self.dismiss(animated: true, completion: nil) } - + func readCapabilities() { - + textView.text = capabilitiesText - + if NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingApiEnabled, exists: false) { statusFileSharing.text = "✓ " + NSLocalizedString("_available_", comment: "") } else { statusFileSharing.text = NSLocalizedString("_not_available_", comment: "") } - + if NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesExternalSitesExists, exists: true) { statusExternalSite.text = "✓ " + NSLocalizedString("_available_", comment: "") } else { statusExternalSite.text = NSLocalizedString("_not_available_", comment: "") } - + let isE2EEEnabled = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesE2EEEnabled, exists: false) - //let versionE2EE = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesE2EEApiVersion) - + // let versionE2EE = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesE2EEApiVersion) + if isE2EEEnabled { statusEndToEndEncryption.text = "✓ " + NSLocalizedString("_available_", comment: "") } else { statusEndToEndEncryption.text = NSLocalizedString("_not_available_", comment: "") } - + let activity = NCManageDatabase.shared.getCapabilitiesServerArray(account: account, elements: NCElementsJSON.shared.capabilitiesActivity) if activity != nil { statusActivity.text = "✓ " + NSLocalizedString("_available_", comment: "") } else { statusActivity.text = NSLocalizedString("_not_available_", comment: "") } - + let notification = NCManageDatabase.shared.getCapabilitiesServerArray(account: account, elements: NCElementsJSON.shared.capabilitiesNotification) if notification != nil { statusNotification.text = "✓ " + NSLocalizedString("_available_", comment: "") } else { statusNotification.text = NSLocalizedString("_not_available_", comment: "") } - + let deleteFiles = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFilesUndelete, exists: false) if deleteFiles { statusDeletedFiles.text = "✓ " + NSLocalizedString("_available_", comment: "") } else { statusDeletedFiles.text = NSLocalizedString("_not_available_", comment: "") } - + var textEditor = false var onlyofficeEditors = false if let editors = NCManageDatabase.shared.getDirectEditingEditors(account: account) { @@ -281,40 +281,40 @@ class NCCapabilitiesViewController: UIViewController, UIDocumentInteractionContr } } } - + if textEditor { statusText.text = "✓ " + NSLocalizedString("_available_", comment: "") } else { statusText.text = NSLocalizedString("_not_available_", comment: "") } - + let richdocumentsMimetypes = NCManageDatabase.shared.getCapabilitiesServerArray(account: account, elements: NCElementsJSON.shared.capabilitiesRichdocumentsMimetypes) if richdocumentsMimetypes != nil { statusCollabora.text = "✓ " + NSLocalizedString("_available_", comment: "") } else { statusCollabora.text = NSLocalizedString("_not_available_", comment: "") } - + if onlyofficeEditors { statusOnlyOffice.text = "✓ " + NSLocalizedString("_available_", comment: "") } else { statusOnlyOffice.text = NSLocalizedString("_not_available_", comment: "") } - + let userStatus = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesUserStatusEnabled, exists: false) if userStatus { statusUserStatus.text = "✓ " + NSLocalizedString("_available_", comment: "") } else { statusUserStatus.text = NSLocalizedString("_not_available_", comment: "") } - + let comments = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFilesComments, exists: false) if comments { statusComments.text = "✓ " + NSLocalizedString("_available_", comment: "") } else { statusComments.text = NSLocalizedString("_not_available_", comment: "") } - + print("end.") } } diff --git a/iOSClient/EmptyView/NCEmptyDataSet.swift b/iOSClient/EmptyView/NCEmptyDataSet.swift index ea9479abb..23b91e475 100644 --- a/iOSClient/EmptyView/NCEmptyDataSet.swift +++ b/iOSClient/EmptyView/NCEmptyDataSet.swift @@ -23,7 +23,7 @@ import UIKit -public protocol NCEmptyDataSetDelegate { +public protocol NCEmptyDataSetDelegate: AnyObject { func emptyDataSetView(_ view: NCEmptyView) } @@ -33,32 +33,32 @@ public extension NCEmptyDataSetDelegate { } class NCEmptyDataSet: NSObject { - + private var emptyView: NCEmptyView? private var timer: Timer? private var numberItemsForSections: Int = 0 - private var delegate: NCEmptyDataSetDelegate? + private weak var delegate: NCEmptyDataSetDelegate? private var fillBackgroundName: String = "" private var fillBackgroundView = UIImageView() init(view: UIView, offset: CGFloat = 0, delegate: NCEmptyDataSetDelegate?) { super.init() - + if let emptyView = UINib(nibName: "NCEmptyView", bundle: nil).instantiate(withOwner: self, options: nil).first as? NCEmptyView { - + self.delegate = delegate self.emptyView = emptyView - + emptyView.isHidden = true emptyView.translatesAutoresizingMaskIntoConstraints = false - + // emptyView.backgroundColor = .red // emptyView.isHidden = false - + emptyView.emptyTitle.sizeToFit() emptyView.emptyDescription.sizeToFit() - + view.addSubview(emptyView) emptyView.widthAnchor.constraint(equalToConstant: 350).isActive = true @@ -72,31 +72,31 @@ class NCEmptyDataSet: NSObject { } } } - + func numberOfItemsInSection(_ num: Int, section: Int) { - + if section == 0 { numberItemsForSections = num } else { - numberItemsForSections = numberItemsForSections + num + numberItemsForSections += num } - + if let emptyView = emptyView { - + self.delegate?.emptyDataSetView(emptyView) - + if !(timer?.isValid ?? false) && emptyView.isHidden == true { timer = Timer.scheduledTimer(timeInterval: 0.3, target: self, selector: #selector(timerHandler(_:)), userInfo: nil, repeats: false) } - + if numberItemsForSections > 0 { self.emptyView?.isHidden = true } } } - + @objc func timerHandler(_ timer: Timer) { - + if numberItemsForSections == 0 { self.emptyView?.isHidden = false } else { @@ -106,14 +106,14 @@ class NCEmptyDataSet: NSObject { } public class NCEmptyView: UIView { - + @IBOutlet weak var emptyImage: UIImageView! @IBOutlet weak var emptyTitle: UILabel! @IBOutlet weak var emptyDescription: UILabel! - + public override func awakeFromNib() { super.awakeFromNib() - + emptyTitle.textColor = NCBrandColor.shared.label } } diff --git a/iOSClient/Extensions/NSMutableAttributedString+Extensions.swift b/iOSClient/Extensions/NSMutableAttributedString+Extensions.swift index 953f94d2a..8d7eafd6d 100644 --- a/iOSClient/Extensions/NSMutableAttributedString+Extensions.swift +++ b/iOSClient/Extensions/NSMutableAttributedString+Extensions.swift @@ -27,9 +27,9 @@ import UIKit extension NSMutableAttributedString { func setColor(color: UIColor, font: UIFont? = nil, forText stringValue: String) { - + let range: NSRange = self.mutableString.range(of: stringValue, options: .caseInsensitive) - + self.addAttribute(NSAttributedString.Key.foregroundColor, value: color, range: range) if let font = font { self.addAttribute(NSAttributedString.Key.font, value: font, range: range) diff --git a/iOSClient/Extensions/NotificationCenter+MainThread.swift b/iOSClient/Extensions/NotificationCenter+MainThread.swift index 09b0cf2de..94214d48f 100644 --- a/iOSClient/Extensions/NotificationCenter+MainThread.swift +++ b/iOSClient/Extensions/NotificationCenter+MainThread.swift @@ -26,13 +26,12 @@ import UIKit extension NotificationCenter { - func postOnMainThread(name: String, object anObject: Any? = nil, userInfo aUserInfo: [AnyHashable : Any]? = nil, second: Double = 0) { + func postOnMainThread(name: String, object anObject: Any? = nil, userInfo aUserInfo: [AnyHashable: Any]? = nil, second: Double = 0) { // if UIApplication.shared.applicationState == .background { // return // } DispatchQueue.main.asyncAfter(deadline: .now() + second) { - NotificationCenter.default.post(name: Notification.Name.init(rawValue: name), object: anObject, userInfo: aUserInfo) + NotificationCenter.default.post(name: Notification.Name(rawValue: name), object: anObject, userInfo: aUserInfo) } } } - diff --git a/iOSClient/Extensions/String+Extensions.swift b/iOSClient/Extensions/String+Extensions.swift index 31a0f4c93..40bd244af 100644 --- a/iOSClient/Extensions/String+Extensions.swift +++ b/iOSClient/Extensions/String+Extensions.swift @@ -34,7 +34,7 @@ extension String { }) return initials.isEmpty ? nil : initials } - + func formatSecondsToString(_ seconds: TimeInterval) -> String { if seconds.isNaN { return "00:00:00" @@ -44,14 +44,14 @@ extension String { let hour = Int(seconds / 3600) return String(format: "%02d:%02d:%02d", hour, min, sec) } - + func md5() -> String { //https://stackoverflow.com/a/32166735/9506784 let length = Int(CC_MD5_DIGEST_LENGTH) - let messageData = self.data(using:.utf8)! + let messageData = self.data(using: .utf8)! var digestData = Data(count: length) - + _ = digestData.withUnsafeMutableBytes { digestBytes -> UInt8 in messageData.withUnsafeBytes { messageBytes -> UInt8 in if let messageBytesBaseAddress = messageBytes.baseAddress, let digestBytesBlindMemory = digestBytes.bindMemory(to: UInt8.self).baseAddress { @@ -61,7 +61,7 @@ extension String { return 0 } } - + return digestData.map { String(format: "%02hhx", $0) }.joined() } } diff --git a/iOSClient/Extensions/UIApplication+Orientation.swift b/iOSClient/Extensions/UIApplication+Orientation.swift new file mode 100644 index 000000000..d49c72e88 --- /dev/null +++ b/iOSClient/Extensions/UIApplication+Orientation.swift @@ -0,0 +1,36 @@ +// +// UIApplication+Orientation.swift +// Nextcloud +// +// Created by Henrik Storch on 15.12.2021. +// Copyright (c) 2021 Henrik Storch. All rights reserved. +// +// Author Henrik Storch <henrik.storch@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 + +extension UIApplication { + // indicates if current device is in landscape orientation + var isLandscape: Bool { + if UIDevice.current.orientation.isValidInterfaceOrientation { + return UIDevice.current.orientation.isLandscape + } else if #available(iOS 13.0, *) { + return windows.first?.windowScene?.interfaceOrientation.isLandscape ?? false + } else { + return statusBarOrientation.isLandscape + } + } +} diff --git a/iOSClient/Extensions/UIColor+Extensions.swift b/iOSClient/Extensions/UIColor+Extensions.swift index 138c709a3..56ca5b9a2 100644 --- a/iOSClient/Extensions/UIColor+Extensions.swift +++ b/iOSClient/Extensions/UIColor+Extensions.swift @@ -25,9 +25,9 @@ import Foundation import UIKit extension UIColor { - + var hexString: String { - + let cgColorInRGB = cgColor.converted(to: CGColorSpace(name: CGColorSpace.sRGB)!, intent: .defaultIntent, options: nil)! let colorRef = cgColorInRGB.components let r = colorRef?[0] ?? 0 @@ -48,29 +48,29 @@ extension UIColor { return color } - + @objc convenience init?(hex: String) { let r, g, b, a: CGFloat - + if hex.hasPrefix("#") { - + let start = hex.index(hex.startIndex, offsetBy: 1) let hexColor = String(hex[start...]) let scanner = Scanner(string: hexColor) var hexNumber: UInt64 = 0 - + if hexColor.count == 6 && scanner.scanHexInt64(&hexNumber) { - + r = CGFloat((hexNumber & 0xff0000) >> 16) / 255.0 g = CGFloat((hexNumber & 0x00ff00) >> 8) / 255.0 b = CGFloat(hexNumber & 0x0000ff) / 255.0 self.init(red: r, green: g, blue: b, alpha: 1) return - + } else if hexColor.count == 7 && scanner.scanHexInt64(&hexNumber) { - + r = CGFloat((hexNumber & 0xff000000) >> 24) / 255 g = CGFloat((hexNumber & 0x00ff0000) >> 16) / 255 b = CGFloat((hexNumber & 0x0000ff00) >> 8) / 255 @@ -80,10 +80,10 @@ extension UIColor { return } } - + return nil } - + @objc func lighter(by percentage: CGFloat = 30.0) -> UIColor? { return self.adjust(by: abs(percentage) ) } @@ -103,29 +103,29 @@ extension UIColor { return nil } } - + @objc func isTooLight() -> Bool { - + var white: CGFloat = 0.0 self.getWhite(&white, alpha: nil) if white == 1 { return true } - + guard let components = cgColor.components, components.count > 2 else {return false} let brightness = ((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000 return (brightness > 0.95) } - + @objc func isTooDark() -> Bool { - + var white: CGFloat = 0.0 self.getWhite(&white, alpha: nil) if white == 0 { return true } - + guard let components = cgColor.components, components.count > 2 else {return false} let brightness = ((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000 return (brightness < 0.05) } - + func isLight(threshold: Float = 0.7) -> Bool { let originalCGColor = self.cgColor @@ -138,7 +138,7 @@ extension UIColor { let brightness = Float(((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000) return (brightness > threshold) } - + func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage { return UIGraphicsImageRenderer(size: size).image { rendererContext in self.setFill() diff --git a/iOSClient/Extensions/UIControl+Extensions.swift b/iOSClient/Extensions/UIControl+Extensions.swift index f4f571390..390734d65 100644 --- a/iOSClient/Extensions/UIControl+Extensions.swift +++ b/iOSClient/Extensions/UIControl+Extensions.swift @@ -25,16 +25,16 @@ import Foundation public class ActionClosure { - - public let selector : Selector - private let closure : (_ sendersender: Any?) -> () - - init(_ attachObj: AnyObject, closure: @escaping (_ sender: Any?) -> ()) { + + public let selector: Selector + private let closure : (_ sendersender: Any?) -> Void + + init(_ attachObj: AnyObject, closure: @escaping (_ sender: Any?) -> Void) { self.closure = closure self.selector = #selector(target(_ :)) objc_setAssociatedObject(attachObj, UUID().uuidString, self, .OBJC_ASSOCIATION_RETAIN) } - + @objc func target(_ sender: Any?) { closure(sender) } diff --git a/iOSClient/Extensions/UIImage+Extensions.swift b/iOSClient/Extensions/UIImage+Extensions.swift index c2de2951e..0211ca167 100644 --- a/iOSClient/Extensions/UIImage+Extensions.swift +++ b/iOSClient/Extensions/UIImage+Extensions.swift @@ -26,9 +26,9 @@ import UIKit import Accelerate extension UIImage { - + @objc func resizeImage(size: CGSize, isAspectRation: Bool) -> UIImage? { - + let originRatio = self.size.width / self.size.height let newRatio = size.width / size.height var newSize = size @@ -38,11 +38,11 @@ extension UIImage { newSize.height = size.height newSize.width = size.height * originRatio } else { - newSize.width = size.width; + newSize.width = size.width newSize.height = size.width / originRatio } } - + UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0) self.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)) let newImage = UIGraphicsGetImageFromCurrentImageContext() @@ -52,25 +52,25 @@ extension UIImage { } return self } - + func fixedOrientation() -> UIImage? { - + guard imageOrientation != UIImage.Orientation.up else { // This is default orientation, don't need to do anything return self.copy() as? UIImage } - + guard let cgImage = self.cgImage else { // CGImage is not available return nil } - + guard let colorSpace = cgImage.colorSpace, let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { return nil // Not able to create CGContext } - + var transform: CGAffineTransform = CGAffineTransform.identity - + switch imageOrientation { case .down, .downMirrored: transform = transform.translatedBy(x: size.width, y: size.height) @@ -86,7 +86,7 @@ extension UIImage { @unknown default: break } - + // Flip image one more time if needed to, this is to prevent flipped image switch imageOrientation { case .upMirrored, .downMirrored: @@ -100,9 +100,9 @@ extension UIImage { @unknown default: break } - + ctx.concatenate(transform) - + switch imageOrientation { case .left, .leftMirrored, .right, .rightMirrored: ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.height, height: size.width)) @@ -110,16 +110,16 @@ extension UIImage { ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) break } - + guard let newCGImage = ctx.makeImage() else { return nil } - return UIImage.init(cgImage: newCGImage, scale: 1, orientation: .up) + return UIImage(cgImage: newCGImage, scale: 1, orientation: .up) } - + @objc func image(color: UIColor, size: CGFloat) -> UIImage { - + return autoreleasepool { () -> UIImage in let size = CGSize(width: size, height: size) - + UIGraphicsBeginImageContextWithOptions(size, false, self.scale) color.setFill() @@ -135,13 +135,13 @@ extension UIImage { let newImage = UIGraphicsGetImageFromCurrentImageContext() ?? self UIGraphicsEndImageContext() - + return newImage } } - + func imageColor(_ color: UIColor) -> UIImage { - + if #available(iOS 13.0, *) { return self.withTintColor(color, renderingMode: .alwaysOriginal) } else { @@ -151,21 +151,21 @@ extension UIImage { } } } - + func isEqualToImage(image: UIImage?) -> Bool { if image == nil { return false } let data1: NSData = self.pngData()! as NSData let data2: NSData = image!.pngData()! as NSData return data1.isEqual(data2) } - + class func imageWithView(_ view: UIView) -> UIImage { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0) defer { UIGraphicsEndImageContext() } view.drawHierarchy(in: view.bounds, afterScreenUpdates: true) return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage() } - + func image(alpha: CGFloat) -> UIImage? { UIGraphicsBeginImageContextWithOptions(size, false, scale) draw(at: .zero, blendMode: .normal, alpha: alpha) diff --git a/iOSClient/Favorites/NCFavorite.swift b/iOSClient/Favorites/NCFavorite.swift index 476835908..a94fc6ba4 100644 --- a/iOSClient/Favorites/NCFavorite.swift +++ b/iOSClient/Favorites/NCFavorite.swift @@ -24,74 +24,74 @@ import UIKit import NCCommunication -class NCFavorite: NCCollectionViewCommon { - +class NCFavorite: NCCollectionViewCommon { + // MARK: - View Life Cycle required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - + titleCurrentFolder = NSLocalizedString("_favorites_", comment: "") layoutKey = NCGlobal.shared.layoutViewFavorite enableSearchBar = true - emptyImage = UIImage.init(named: "star.fill")?.image(color: NCBrandColor.shared.yellowFavorite, size: UIScreen.main.bounds.width) + emptyImage = UIImage(named: "star.fill")?.image(color: NCBrandColor.shared.yellowFavorite, size: UIScreen.main.bounds.width) emptyTitle = "_favorite_no_files_" emptyDescription = "_tutorial_favorite_view_" } - + // MARK: - DataSource + NC Endpoint - + override func reloadDataSource() { super.reloadDataSource() - + DispatchQueue.global().async { - + if !self.isSearching { - + if self.serverUrl == "" { self.metadatasSource = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND favorite == true", self.appDelegate.account)) } else { self.metadatasSource = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl)) } } - - self.dataSource = NCDataSource.init(metadatasSource: self.metadatasSource, sort:self.layoutForView?.sort, ascending: self.layoutForView?.ascending, directoryOnTop: self.layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) - + + self.dataSource = NCDataSource(metadatasSource: self.metadatasSource, sort: self.layoutForView?.sort, ascending: self.layoutForView?.ascending, directoryOnTop: self.layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) + DispatchQueue.main.async { self.refreshControl.endRefreshing() self.collectionView.reloadData() } } } - + override func reloadDataSourceNetwork(forced: Bool = false) { super.reloadDataSourceNetwork(forced: forced) - + if isSearching { networkSearch() return } - + isReloadDataSourceNetworkInProgress = true collectionView?.reloadData() - + if serverUrl == "" { - - NCNetworking.shared.listingFavoritescompletion(selector: NCGlobal.shared.selectorListingFavorite) { (account, metadatas, errorCode, errorDescription) in + + NCNetworking.shared.listingFavoritescompletion(selector: NCGlobal.shared.selectorListingFavorite) { _, _, errorCode, errorDescription in if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } - + DispatchQueue.main.async { self.refreshControl.endRefreshing() self.isReloadDataSourceNetworkInProgress = false self.reloadDataSource() } } - + } else { - - networkReadFolder(forced: forced) { (tableDirectory, metadatas, metadatasUpdate, metadatasDelete, errorCode, errorDescription) in + + networkReadFolder(forced: forced) { tableDirectory, metadatas, metadatasUpdate, metadatasDelete, errorCode, _ in if errorCode == 0 { for metadata in metadatas ?? [] { if !metadata.directory { @@ -101,7 +101,7 @@ class NCFavorite: NCCollectionViewCommon { } } } - + DispatchQueue.main.async { self.refreshControl.endRefreshing() self.isReloadDataSourceNetworkInProgress = false @@ -116,4 +116,3 @@ class NCFavorite: NCCollectionViewCommon { } } } - diff --git a/iOSClient/FileViewInFolder/NCFileViewInFolder.swift b/iOSClient/FileViewInFolder/NCFileViewInFolder.swift index 642d311c1..ac6f63af8 100644 --- a/iOSClient/FileViewInFolder/NCFileViewInFolder.swift +++ b/iOSClient/FileViewInFolder/NCFileViewInFolder.swift @@ -25,39 +25,39 @@ import UIKit import NCCommunication class NCFileViewInFolder: NCCollectionViewCommon { - + internal var fileName: String? // MARK: - View Life Cycle required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - + appDelegate.activeFileViewInFolder = self titleCurrentFolder = NCBrandOptions.shared.brand layoutKey = NCGlobal.shared.layoutViewViewInFolder enableSearchBar = false - emptyImage = UIImage.init(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width) + emptyImage = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width) emptyTitle = "_files_no_files_" emptyDescription = "_no_file_pull_down_" } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + appDelegate.activeViewController = self - + if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) { self.navigationItem.title = NCBrandOptions.shared.brand } else { self.navigationItem.title = (serverUrl as NSString).lastPathComponent } - + presentationController?.delegate = self - + layoutForView = NCUtility.shared.getLayoutForView(key: layoutKey, serverUrl: serverUrl) gridLayout.itemForLine = CGFloat(layoutForView?.itemForLine ?? 3) - + if layoutForView?.layout == NCGlobal.shared.layoutList { collectionView?.collectionViewLayout = listLayout } else { @@ -65,38 +65,36 @@ class NCFileViewInFolder: NCCollectionViewCommon { } self.navigationItem.leftBarButtonItem = nil - self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_close_", comment: ""), style: .plain, target: self, action: #selector(tapClose(sender:))) + self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_close_", comment: ""), style: .plain, target: self, action: #selector(tapClose(sender:))) } // MARK: - TAP EVENT @objc func tapClose(sender: Any) { - dismiss(animated: true) { - self.appDelegate.activeFileViewInFolder = nil - } + dismiss(animated: true) } - + // MARK: - DataSource + NC Endpoint - + override func reloadDataSource() { super.reloadDataSource() - + DispatchQueue.global().async { - + if !self.isSearching { self.metadatasSource = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl)) if self.metadataFolder == nil { - self.metadataFolder = NCManageDatabase.shared.getMetadataFolder(account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, serverUrl: self.serverUrl) + self.metadataFolder = NCManageDatabase.shared.getMetadataFolder(account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, serverUrl: self.serverUrl) } } - - self.dataSource = NCDataSource.init(metadatasSource: self.metadatasSource, sort: self.layoutForView?.sort, ascending: self.layoutForView?.ascending, directoryOnTop: self.layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) - + + self.dataSource = NCDataSource(metadatasSource: self.metadatasSource, sort: self.layoutForView?.sort, ascending: self.layoutForView?.ascending, directoryOnTop: self.layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) + DispatchQueue.main.async { - + self.refreshControl.endRefreshing() self.collectionView.reloadData() - + // Blink file if self.fileName != nil { if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@", self.appDelegate.account, self.serverUrl, self.fileName!)) { @@ -104,7 +102,7 @@ class NCFileViewInFolder: NCCollectionViewCommon { DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { UIView.animate(withDuration: 0.3) { self.collectionView.scrollToItem(at: IndexPath(row: row, section: 0), at: .centeredVertically, animated: false) - } completion: { (_) in + } completion: { _ in if let cell = self.collectionView.cellForItem(at: IndexPath(row: row, section: 0)) { cell.backgroundColor = .darkGray UIView.animate(withDuration: 2) { @@ -120,19 +118,19 @@ class NCFileViewInFolder: NCCollectionViewCommon { } } } - + override func reloadDataSourceNetwork(forced: Bool = false) { super.reloadDataSourceNetwork(forced: forced) - + if isSearching { networkSearch() return } - + isReloadDataSourceNetworkInProgress = true collectionView?.reloadData() - - networkReadFolder(forced: forced) { (tableDirectory, metadatas, metadatasUpdate, metadatasDelete, errorCode, errorDescription) in + + networkReadFolder(forced: forced) { tableDirectory, metadatas, _, _, errorCode, _ in if errorCode == 0 { for metadata in metadatas ?? [] { if !metadata.directory { @@ -142,7 +140,7 @@ class NCFileViewInFolder: NCCollectionViewCommon { } } } - + DispatchQueue.main.async { self.refreshControl.endRefreshing() self.isReloadDataSourceNetworkInProgress = false @@ -152,4 +150,3 @@ class NCFileViewInFolder: NCCollectionViewCommon { } } } - diff --git a/iOSClient/Files/NCFiles.swift b/iOSClient/Files/NCFiles.swift index 3cffadf8f..f90c7f7f5 100644 --- a/iOSClient/Files/NCFiles.swift +++ b/iOSClient/Files/NCFiles.swift @@ -24,82 +24,82 @@ import UIKit import NCCommunication -class NCFiles: NCCollectionViewCommon { - +class NCFiles: NCCollectionViewCommon { + internal var isRoot: Bool = true // MARK: - View Life Cycle required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - + appDelegate.activeFiles = self titleCurrentFolder = NCBrandOptions.shared.brand layoutKey = NCGlobal.shared.layoutViewFiles enableSearchBar = true - emptyImage = UIImage.init(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width) + emptyImage = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width) emptyTitle = "_files_no_files_" emptyDescription = "_no_file_pull_down_" } - + override func viewWillAppear(_ animated: Bool) { - + if isRoot { serverUrl = NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) titleCurrentFolder = getNavigationTitle() } - + super.viewWillAppear(animated) } - + // MARK: - NotificationCenter - + override func initialize() { - + if isRoot { serverUrl = NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) titleCurrentFolder = getNavigationTitle() reloadDataSourceNetwork(forced: true) } - + super.initialize() } - + // MARK: - DataSource + NC Endpoint - + override func reloadDataSource() { super.reloadDataSource() - + DispatchQueue.global(qos: .background).async { - + if !self.isSearching && self.appDelegate.account != "" && self.appDelegate.urlBase != "" { self.metadatasSource = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl)) if self.metadataFolder == nil { self.metadataFolder = NCManageDatabase.shared.getMetadataFolder(account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, serverUrl: self.serverUrl) } } - - self.dataSource = NCDataSource.init(metadatasSource: self.metadatasSource, sort: self.layoutForView?.sort, ascending: self.layoutForView?.ascending, directoryOnTop: self.layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) - + + self.dataSource = NCDataSource(metadatasSource: self.metadatasSource, sort: self.layoutForView?.sort, ascending: self.layoutForView?.ascending, directoryOnTop: self.layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) + DispatchQueue.main.async { [weak self] in self?.refreshControl.endRefreshing() - self?.collectionView.reloadData() + self?.collectionView.reloadData() } } } - + override func reloadDataSourceNetwork(forced: Bool = false) { super.reloadDataSourceNetwork(forced: forced) - + if isSearching { networkSearch() return } - + isReloadDataSourceNetworkInProgress = true collectionView?.reloadData() - - networkReadFolder(forced: forced) { (tableDirectory, metadatas, metadatasUpdate, metadatasDelete, errorCode, errorDescription) in + + networkReadFolder(forced: forced) { tableDirectory, metadatas, metadatasUpdate, metadatasDelete, errorCode, _ in if errorCode == 0 { for metadata in metadatas ?? [] { if !metadata.directory { @@ -109,7 +109,7 @@ class NCFiles: NCCollectionViewCommon { } } } - + DispatchQueue.main.async { self.refreshControl.endRefreshing() self.isReloadDataSourceNetworkInProgress = false @@ -123,4 +123,3 @@ class NCFiles: NCCollectionViewCommon { } } } - diff --git a/iOSClient/Login/NCAppConfigView.swift b/iOSClient/Login/NCAppConfigView.swift index 6d4d50029..6eb28bab1 100644 --- a/iOSClient/Login/NCAppConfigView.swift +++ b/iOSClient/Login/NCAppConfigView.swift @@ -31,20 +31,20 @@ class NCAppConfigView: UIViewController { private var serverUrl: String? private var username: String? private var password: String? - + @IBOutlet weak var logoImage: UIImageView! @IBOutlet weak var titleLabel: UILabel! - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + self.view.backgroundColor = NCBrandColor.shared.brandElement titleLabel.textColor = NCBrandColor.shared.brandText - + titleLabel.text = NSLocalizedString("_appconfig_view_title_", comment: "") - + if let serverConfig = UserDefaults.standard.dictionary(forKey: NCBrandConfiguration.shared.configuration_bundleId) { serverUrl = serverConfig[NCBrandConfiguration.shared.configuration_serverUrl] as? String username = serverConfig[NCBrandConfiguration.shared.configuration_username] as? String @@ -55,13 +55,13 @@ class NCAppConfigView: UIViewController { password = UserDefaults.standard.string(forKey: NCBrandConfiguration.shared.configuration_password) } } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + // Stop timer error network appDelegate.timerErrorNetworking?.invalidate() - + guard let serverUrl = self.serverUrl else { NCContentPresenter.shared.messageNotification("_error_", description: "User Default, serverUrl not found", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError) return @@ -74,28 +74,28 @@ class NCAppConfigView: UIViewController { NCContentPresenter.shared.messageNotification("_error_", description: "User Default, password not found", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError) return } - - NCCommunication.shared.getAppPassword(serverUrl: serverUrl, username: username, password: password, userAgent: nil) { (token, errorCode, errorDescription) in + + NCCommunication.shared.getAppPassword(serverUrl: serverUrl, username: username, password: password, userAgent: nil) { token, errorCode, errorDescription in DispatchQueue.main.async { if errorCode == 0 && token != nil { let account: String = "\(username) \(serverUrl)" - + // NO account found, clear if NCManageDatabase.shared.getAccounts() == nil { NCUtility.shared.removeAllSettings() } - + // Add new account NCManageDatabase.shared.deleteAccount(account) NCManageDatabase.shared.addAccount(account, urlBase: serverUrl, user: username, password: token!) - + guard let tableAccount = NCManageDatabase.shared.setAccountActive(account) else { NCContentPresenter.shared.messageNotification("_error_", description: "setAccountActive error", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError) self.dismiss(animated: true, completion: nil) return } - + self.appDelegate.settingAccount(account, urlBase: serverUrl, user: username, userId: tableAccount.userId, password: token!) NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterInitialize) - + self.dismiss(animated: true) {} } else { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) @@ -103,10 +103,10 @@ class NCAppConfigView: UIViewController { } } } - + override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) - + // Start timer error network appDelegate.startTimerErrorNetworking() } diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index 9b0c6954a..1fb3c4081 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -25,7 +25,7 @@ import UIKit import NCCommunication class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { - + @IBOutlet weak var imageBrand: UIImageView! @IBOutlet weak var imageBrandConstraintY: NSLayoutConstraint! @IBOutlet weak var baseUrl: UITextField! @@ -45,7 +45,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { override func viewDidLoad() { super.viewDidLoad() - + // Text color if NCBrandColor.shared.customer.isTooLight() { textColor = .black @@ -57,10 +57,10 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { textColor = .white textColorOpponent = .black } - + // Image Brand imageBrand.image = UIImage(named: "logo") - + // Url baseUrl.textColor = textColor baseUrl.tintColor = textColor @@ -73,28 +73,28 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { baseUrl.rightViewMode = .always baseUrl.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("_login_url_", comment: ""), attributes: [NSAttributedString.Key.foregroundColor: textColor.withAlphaComponent(0.5)]) baseUrl.delegate = self - + // Login button loginAddressDetail.textColor = textColor loginAddressDetail.text = String.localizedStringWithFormat(NSLocalizedString("_login_address_detail_", comment: ""), NCBrandOptions.shared.brand) - + // Login Image loginImage.image = UIImage(named: "arrow.right")?.image(color: textColor, size: 100) - + // brand if NCBrandOptions.shared.disable_request_login_url { baseUrl.text = NCBrandOptions.shared.loginBaseUrl baseUrl.isHidden = true } - + // qrcode qrCode.setImage(UIImage(named: "qrcode")?.image(color: textColor, size: 100), for: .normal) - + // certificate certificate.setImage(UIImage(named: "certificate")?.image(color: textColor, size: 100), for: .normal) certificate.isHidden = true certificate.isEnabled = false - + // navigation if #available(iOS 13.0, *) { let navBarAppearance = UINavigationBarAppearance() @@ -111,55 +111,55 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { self.navigationController?.navigationBar.barTintColor = NCBrandColor.shared.customer } self.navigationController?.navigationBar.tintColor = textColor - + if NCManageDatabase.shared.getAccounts()?.count ?? 0 == 0 { - + } else { - + // Cancel Button - let navigationItemCancel = UIBarButtonItem.init(barButtonSystemItem: .stop, target: self, action: #selector(self.actionCancel)) + let navigationItemCancel = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(self.actionCancel)) navigationItemCancel.tintColor = textColor - navigationItem.leftBarButtonItem = navigationItemCancel + navigationItem.leftBarButtonItem = navigationItemCancel } - + self.navigationController?.navigationBar.setValue(true, forKey: "hidesShadow") view.backgroundColor = NCBrandColor.shared.customer - + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + appDelegate.timerErrorNetworking?.invalidate() } - + override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) appDelegate.startTimerErrorNetworking() } - + // MARK: - TextField - + func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() actionButtonLogin(self) return false } - + func textFieldDidBeginEditing(_ textField: UITextField) { - + self.activeTextField = textField } - + // MARK: - Keyboard notification - - @objc internal func keyboardWillShow(_ notification : Notification?) { - + + @objc internal func keyboardWillShow(_ notification: Notification?) { + activeTextfieldDiff = 0 - + if let info = notification?.userInfo, let centerObject = self.activeTextField.superview?.convert(self.activeTextField.center, to: nil) { let frameEndUserInfoKey = UIResponder.keyboardFrameEndUserInfoKey @@ -172,11 +172,11 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } } } - + @objc func keyboardWillHide(_ notification: Notification) { imageBrandConstraintY.constant -= activeTextfieldDiff } - + // MARK: - Action @objc func actionCancel() { @@ -184,11 +184,11 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } @IBAction func actionButtonLogin(_ sender: Any) { - + guard var url = baseUrl.text?.trimmingCharacters(in: .whitespacesAndNewlines) else { return } if url.hasSuffix("/") { url = String(url.dropLast()) } if url.count == 0 { return } - + // Check whether baseUrl contain protocol. If not add https:// by default. if url.hasPrefix("https") == false && url.hasPrefix("http") == false { url = "https://" + url @@ -196,87 +196,87 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { self.baseUrl.text = url isUrlValid(url: url) } - + @IBAction func actionQRCode(_ sender: Any) { - - let qrCode = NCLoginQRCode.init(delegate: self) + + let qrCode = NCLoginQRCode(delegate: self) qrCode.scan() } - + @IBAction func actionCertificate(_ sender: Any) { - + } - + // MARK: - Login func isUrlValid(url: String) { - + loginButton.isEnabled = false - - NCCommunication.shared.getServerStatus(serverUrl: url) { (serverProductName, serverVersion, versionMajor, versionMinor, versionMicro, extendedSupport, errorCode ,errorDescription) in - + + NCCommunication.shared.getServerStatus(serverUrl: url) { _, _, versionMajor, _, _, _, errorCode, errorDescription in + if errorCode == 0 { - + if let host = URL(string: url)?.host { NCNetworking.shared.writeCertificate(host: host) } - - NCCommunication.shared.getLoginFlowV2(serverUrl: url) { (token, endpoint, login, errorCode, errorDescription) in - + + NCCommunication.shared.getLoginFlowV2(serverUrl: url) { token, endpoint, login, errorCode, _ in + self.loginButton.isEnabled = true - + // Login Flow V2 if errorCode == 0 && NCBrandOptions.shared.use_loginflowv2 && token != nil && endpoint != nil && login != nil { - + if let loginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb { - + loginWeb.urlBase = url loginWeb.loginFlowV2Available = true loginWeb.loginFlowV2Token = token! loginWeb.loginFlowV2Endpoint = endpoint! loginWeb.loginFlowV2Login = login! - + self.navigationController?.pushViewController(loginWeb, animated: true) } - + // Login Flow } else if versionMajor >= NCGlobal.shared.nextcloudVersion12 { - + if let loginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb { - + loginWeb.urlBase = url self.navigationController?.pushViewController(loginWeb, animated: true) } - + // NO Login flow available } else if versionMajor < NCGlobal.shared.nextcloudVersion12 { - + let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_webflow_not_available_", comment: ""), preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { action in })) - + alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) + self.present(alertController, animated: true, completion: { }) } } - + } else { - + self.loginButton.isEnabled = true - + if errorCode == NSURLErrorServerCertificateUntrusted { - + let alertController = UIAlertController(title: NSLocalizedString("_ssl_certificate_untrusted_", comment: ""), message: NSLocalizedString("_connect_server_anyway_", comment: ""), preferredStyle: .alert) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { action in + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { _ in if let host = URL(string: url)?.host { NCNetworking.shared.writeCertificate(host: host) } })) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in })) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { action in + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { _ in })) + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { _ in if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() as? UINavigationController { let viewController = navigationController.topViewController as! NCViewCertificateDetails if let host = URL(string: url)?.host { @@ -285,126 +285,123 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { self.present(navigationController, animated: true) } })) - + self.present(alertController, animated: true) - + } else { - + let alertController = UIAlertController(title: NSLocalizedString("_connection_error_", comment: ""), message: errorDescription, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { action in })) - + alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) + self.present(alertController, animated: true, completion: { }) } } } } - + // MARK: - QRCode func dismissQRCode(_ value: String?, metadataType: String?) { - + guard var value = value else { return } - + let protocolLogin = NCBrandOptions.shared.webLoginAutenticationProtocol + "login/" - + if value.hasPrefix(protocolLogin) && value.contains("user:") && value.contains("password:") && value.contains("server:") { - + value = value.replacingOccurrences(of: protocolLogin, with: "") let valueArray = value.components(separatedBy: "&") if valueArray.count == 3 { - + let user = valueArray[0].replacingOccurrences(of: "user:", with: "") let password = valueArray[1].replacingOccurrences(of: "password:", with: "") let urlBase = valueArray[2].replacingOccurrences(of: "server:", with: "") let webDAV = NCUtilityFileSystem.shared.getWebDAV(account: appDelegate.account) let serverUrl = urlBase + "/" + webDAV - + loginButton.isEnabled = false - - NCCommunication.shared.checkServer(serverUrl: serverUrl) { (errorCode, errorDescription) in - + + NCCommunication.shared.checkServer(serverUrl: serverUrl) { errorCode, errorDescription in + self.loginButton.isEnabled = true self.standardLogin(url: urlBase, user: user, password: password, errorCode: errorCode, errorDescription: errorDescription) } } } } - + func standardLogin(url: String, user: String, password: String, errorCode: Int, errorDescription: String) { - + if errorCode == 0 { - + if let host = URL(string: url)?.host { NCNetworking.shared.writeCertificate(host: host) } - + let account = user + " " + url - + if NCManageDatabase.shared.getAccounts() == nil { NCUtility.shared.removeAllSettings() } - - // Clear certificate error - NCNetworking.shared.certificatesError = nil - + NCManageDatabase.shared.deleteAccount(account) NCManageDatabase.shared.addAccount(account, urlBase: url, user: user, password: password) - + if let activeAccount = NCManageDatabase.shared.setAccountActive(account) { appDelegate.settingAccount(activeAccount.account, urlBase: activeAccount.urlBase, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account)) } - + if CCUtility.getIntro() { - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterInitialize) self.dismiss(animated: true) - + } else { - + CCUtility.setIntro(true) - + if self.presentingViewController == nil { - + let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() viewController?.modalPresentationStyle = .fullScreen NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterInitialize) self.appDelegate.window?.rootViewController = viewController self.appDelegate.window?.makeKey() - + } else { - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterInitialize) self.dismiss(animated: true) } } - + } else if errorCode == NSURLErrorServerCertificateUntrusted { - + let alertController = UIAlertController(title: NSLocalizedString("_ssl_certificate_untrusted_", comment: ""), message: NSLocalizedString("_connect_server_anyway_", comment: ""), preferredStyle: .alert) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { action in + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { _ in if let host = URL(string: url)?.host { NCNetworking.shared.writeCertificate(host: host) } })) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in })) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { action in + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { _ in })) + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { _ in if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() { self.present(navigationController, animated: true) } })) - + self.present(alertController, animated: true) - + } else { - + let message = NSLocalizedString("_not_possible_connect_to_server_", comment: "") + ".\n" + errorDescription let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: message, preferredStyle: .alert) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { action in })) + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) self.present(alertController, animated: true, completion: { }) } diff --git a/iOSClient/Login/NCLoginNavigationController.swift b/iOSClient/Login/NCLoginNavigationController.swift new file mode 100644 index 000000000..6774bb1e1 --- /dev/null +++ b/iOSClient/Login/NCLoginNavigationController.swift @@ -0,0 +1,28 @@ +// +// NCLoginNavigationController.swift +// Nextcloud +// +// Created by Marino Faggiana on 30/11/21. +// 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 Foundation +import UIKit + +class NCLoginNavigationController: UINavigationController { +} diff --git a/iOSClient/Login/NCLoginQRCode.swift b/iOSClient/Login/NCLoginQRCode.swift index 6e2192caa..c5da54712 100644 --- a/iOSClient/Login/NCLoginQRCode.swift +++ b/iOSClient/Login/NCLoginQRCode.swift @@ -29,11 +29,11 @@ import QRCodeReader } class NCLoginQRCode: NSObject, QRCodeReaderViewControllerDelegate { - + lazy var reader: QRCodeReader = QRCodeReader() - + weak var delegate: UIViewController? - + lazy var readerVC: QRCodeReaderViewController = { let builder = QRCodeReaderViewControllerBuilder { $0.reader = QRCodeReader(metadataObjectTypes: [.qr], captureDevicePosition: .back) @@ -41,73 +41,73 @@ class NCLoginQRCode: NSObject, QRCodeReaderViewControllerDelegate { $0.preferredStatusBarStyle = .lightContent $0.showOverlayView = true $0.rectOfInterest = CGRect(x: 0.2, y: 0.2, width: 0.6, height: 0.6) - + $0.reader.stopScanningWhenCodeIsFound = false } - + return QRCodeReaderViewController(builder: builder) }() override init() { - + } - + @objc public init(delegate: UIViewController) { self.delegate = delegate } - + @objc func scan() { guard checkScanPermissions() else { return } - + readerVC.modalPresentationStyle = .formSheet readerVC.delegate = self - - readerVC.completionBlock = { (result: QRCodeReaderResult?) in + + readerVC.completionBlock = { (_: QRCodeReaderResult?) in self.readerVC.dismiss(animated: true, completion: nil) } - + delegate?.present(readerVC, animated: true, completion: nil) } - + private func checkScanPermissions() -> Bool { do { return try QRCodeReader.supportsMetadataObjectTypes() } catch let error as NSError { let alert: UIAlertController - + switch error.code { case -11852: alert = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_qrcode_not_authorized_", comment: ""), preferredStyle: .alert) - - alert.addAction(UIAlertAction(title: NSLocalizedString("_settings_", comment: ""), style: .default, handler: { (_) in + + alert.addAction(UIAlertAction(title: NSLocalizedString("_settings_", comment: ""), style: .default, handler: { _ in DispatchQueue.main.async { if let settingsURL = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil) } } })) - + alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil)) default: alert = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_qrcode_not_supported_", comment: ""), preferredStyle: .alert) alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .cancel, handler: nil)) } - + delegate?.present(alert, animated: true, completion: nil) - + return false } } - + func reader(_ reader: QRCodeReaderViewController, didScanResult result: QRCodeReaderResult) { reader.stopScanning() - + (self.delegate as? NCLoginQRCodeDelegate)?.dismissQRCode(result.value, metadataType: result.metadataType) } - + func readerDidCancel(_ reader: QRCodeReaderViewController) { reader.stopScanning() - + (self.delegate as? NCLoginQRCodeDelegate)?.dismissQRCode(nil, metadataType: nil) } } diff --git a/iOSClient/Login/NCLoginWeb.swift b/iOSClient/Login/NCLoginWeb.swift index 128ba7030..334de625f 100644 --- a/iOSClient/Login/NCLoginWeb.swift +++ b/iOSClient/Login/NCLoginWeb.swift @@ -27,176 +27,180 @@ import NCCommunication import FloatingPanel class NCLoginWeb: UIViewController { - + var activityIndicator: UIActivityIndicatorView! var webView: WKWebView? let appDelegate = UIApplication.shared.delegate as! AppDelegate @objc var urlBase = "" - + @objc var loginFlowV2Available = false @objc var loginFlowV2Token = "" @objc var loginFlowV2Endpoint = "" @objc var loginFlowV2Login = "" - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + let accountCount = NCManageDatabase.shared.getAccounts()?.count ?? 0 - + if NCBrandOptions.shared.use_login_web_personalized && accountCount > 0 { - navigationItem.leftBarButtonItem = UIBarButtonItem.init(barButtonSystemItem: .stop, target: self, action: #selector(self.closeView(sender:))) + navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(self.closeView(sender:))) } - + if accountCount > 0 { - navigationItem.rightBarButtonItem = UIBarButtonItem.init(image: UIImage(named: "users")!.image(color: NCBrandColor.shared.label, size: 35), style: .plain, target: self, action: #selector(self.changeUser(sender:))) + navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "users")!.image(color: NCBrandColor.shared.label, size: 35), style: .plain, target: self, action: #selector(self.changeUser(sender:))) } - + let config = WKWebViewConfiguration() config.websiteDataStore = WKWebsiteDataStore.nonPersistent() webView = WKWebView(frame: CGRect.zero, configuration: config) webView!.navigationDelegate = self view.addSubview(webView!) - + webView!.translatesAutoresizingMaskIntoConstraints = false webView!.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true webView!.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true webView!.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true webView!.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true - + // ADD end point for Web Flow if urlBase != NCBrandOptions.shared.linkloginPreferredProviders { if loginFlowV2Available { urlBase = loginFlowV2Login } else { - urlBase = urlBase + "/index.php/login/flow" + urlBase += "/index.php/login/flow" } } - + activityIndicator = UIActivityIndicatorView(style: .gray) activityIndicator.center = self.view.center activityIndicator.startAnimating() self.view.addSubview(activityIndicator) - + if let url = URL(string: urlBase) { loadWebPage(webView: webView!, url: url) } else { NCContentPresenter.shared.messageNotification("_error_", description: "_login_url_error_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError, priority: .max) } } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + // Stop timer error network appDelegate.timerErrorNetworking?.invalidate() } - + override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) - + // Start timer error network appDelegate.startTimerErrorNetworking() } - - func loadWebPage(webView: WKWebView, url: URL) { - + + func loadWebPage(webView: WKWebView, url: URL) { + let language = NSLocale.preferredLanguages[0] as String var request = URLRequest(url: url) - let deviceName = UIDevice.current.name - let userAgent = deviceName + " " + "(iOS Files)" - + + if let deviceName = "\(UIDevice.current.name) (\(NCBrandOptions.shared.brand) iOS)".cString(using: .utf8), + let deviceUserAgent = String(cString: deviceName, encoding: .ascii) { + webView.customUserAgent = deviceUserAgent + } else { + webView.customUserAgent = CCUtility.getUserAgent() + } + request.addValue("true", forHTTPHeaderField: "OCS-APIRequest") request.addValue(language, forHTTPHeaderField: "Accept-Language") - - webView.customUserAgent = userAgent + webView.load(request) } - + @objc func closeView(sender: UIBarButtonItem) { self.dismiss(animated: true, completion: nil) } - + @objc func changeUser(sender: UIBarButtonItem) { toggleMenu() } } extension NCLoginWeb: WKNavigationDelegate { - + func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { - + guard let url = webView.url else { return } - + let urlString: String = url.absoluteString.lowercased() - + // prevent http redirection if urlBase.lowercased().hasPrefix("https://") && urlString.lowercased().hasPrefix("http://") { let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_prevent_http_redirection_", comment: ""), preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { action in + alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in _ = self.navigationController?.popViewController(animated: true) })) self.present(alertController, animated: true) return } - - if (urlString.hasPrefix(NCBrandOptions.shared.webLoginAutenticationProtocol) == true && urlString.contains("login") == true) { - + + if urlString.hasPrefix(NCBrandOptions.shared.webLoginAutenticationProtocol) == true && urlString.contains("login") == true { + var server: String = "" var user: String = "" var password: String = "" - + let keyValue = url.path.components(separatedBy: "&") for value in keyValue { if value.contains("server:") { server = value } if value.contains("user:") { user = value } if value.contains("password:") { password = value } } - + if server != "" && user != "" && password != "" { - + let server: String = server.replacingOccurrences(of: "/server:", with: "") let username: String = user.replacingOccurrences(of: "user:", with: "").replacingOccurrences(of: "+", with: " ") let password: String = password.replacingOccurrences(of: "password:", with: "") - + createAccount(server: server, username: username, password: password) } } } - + func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { - + } - + func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { - + var errorMessage = error.localizedDescription - + for (key, value) in (error as NSError).userInfo { let message = "\(key) \(value)\n" - errorMessage = errorMessage + message + errorMessage += message } - + let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: errorMessage, preferredStyle: .alert) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { action in })) - + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) + self.present(alertController, animated: true) } - + func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if let serverTrust = challenge.protectionSpace.serverTrust { completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust)) } else { - completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil); + completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil) } } - + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { - + decisionHandler(.allow) /* TEST NOT GOOD DON'T WORKS @@ -231,18 +235,18 @@ extension NCLoginWeb: WKNavigationDelegate { webView.load(request) */ } - + func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - print("didStartProvisionalNavigation"); + print("didStartProvisionalNavigation") } - + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { activityIndicator.stopAnimating() - print("didFinishProvisionalNavigation"); - + print("didFinishProvisionalNavigation") + if loginFlowV2Available { DispatchQueue.main.asyncAfter(deadline: .now() + 1) { - NCCommunication.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { (server, loginName, appPassword, errorCode, errorDescription) in + NCCommunication.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, errorCode, _ in if errorCode == 0 && server != nil && loginName != nil && appPassword != nil { self.createAccount(server: server!, username: loginName!, password: appPassword!) } @@ -250,49 +254,46 @@ extension NCLoginWeb: WKNavigationDelegate { } } } - - //MARK: - + + // MARK: - func createAccount(server: String, username: String, password: String) { - + var urlBase = server - + // Normalized - if (urlBase.last == "/") { + if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) } - + // Create account let account: String = "\(username) \(urlBase)" - + // NO account found, clear all if NCManageDatabase.shared.getAccounts() == nil { NCUtility.shared.removeAllSettings() } - // Clear certificate error - NCNetworking.shared.certificatesError = nil - // Add new account NCManageDatabase.shared.deleteAccount(account) NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: username, password: password) - + guard let tableAccount = NCManageDatabase.shared.setAccountActive(account) else { self.dismiss(animated: true, completion: nil) return } - + appDelegate.settingAccount(account, urlBase: urlBase, user: username, userId: tableAccount.userId, password: password) - - if (CCUtility.getIntro()) { - + + if CCUtility.getIntro() { + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterInitialize) self.dismiss(animated: true) - + } else { - + CCUtility.setIntro(true) - if (self.presentingViewController == nil) { + if self.presentingViewController == nil { if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() { viewController.modalPresentationStyle = .fullScreen NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterInitialize) diff --git a/iOSClient/Main/Account Request/NCAccountRequest.swift b/iOSClient/Main/Account Request/NCAccountRequest.swift index 2f1f846ca..5036dca16 100644 --- a/iOSClient/Main/Account Request/NCAccountRequest.swift +++ b/iOSClient/Main/Account Request/NCAccountRequest.swift @@ -24,7 +24,7 @@ import UIKit import NCCommunication -public protocol NCAccountRequestDelegate { +public protocol NCAccountRequestDelegate: AnyObject { func accountRequestAddAccount() func accountRequestChangeAccount(account: String) } @@ -41,28 +41,28 @@ class NCAccountRequest: UIViewController { @IBOutlet weak var closeButton: UIButton! @IBOutlet weak var tableView: UITableView! @IBOutlet weak var progressView: UIProgressView! - + public var accounts: [tableAccount] = [] public var activeAccount: tableAccount? public let heightCell: CGFloat = 60 public var enableTimerProgress: Bool = true public var enableAddAccount: Bool = false public var dismissDidEnterBackground: Bool = false - public var delegate: NCAccountRequestDelegate? + public weak var delegate: NCAccountRequestDelegate? private var timer: Timer? private var time: Float = 0 private let secondsAutoDismiss: Float = 3 - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + titleLabel.text = NSLocalizedString("_account_select_", comment: "") closeButton.setImage(NCUtility.shared.loadImage(named: "xmark", color: NCBrandColor.shared.label), for: .normal) - + tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 1)) tableView.separatorStyle = UITableViewCell.SeparatorStyle.none @@ -73,70 +73,70 @@ class NCAccountRequest: UIViewController { } else { progressView.isHidden = true } - + NotificationCenter.default.addObserver(self, selector: #selector(startTimer), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidEnterBackground), object: nil) - + changeTheming() } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + let visibleCells = tableView.visibleCells var numAccounts = accounts.count if enableAddAccount { numAccounts += 1 } - + if visibleCells.count == numAccounts { tableView.isScrollEnabled = false } } - + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - + timer?.invalidate() } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - + changeTheming() } - + // MARK: - Theming - + @objc func changeTheming() { - + view.backgroundColor = NCBrandColor.shared.secondarySystemBackground tableView.backgroundColor = NCBrandColor.shared.secondarySystemBackground - + tableView.reloadData() } - + // MARK: - Action - + @IBAction func actionClose(_ sender: UIButton) { dismiss(animated: true) } - + // MARK: - NotificationCenter @objc func applicationDidEnterBackground() { - + if dismissDidEnterBackground { dismiss(animated: false) } } // MARK: - Progress - + @objc func startTimer() { - + if enableTimerProgress { time = 0 timer?.invalidate() @@ -146,9 +146,9 @@ class NCAccountRequest: UIViewController { progressView.isHidden = true } } - + @objc func updateProgress() { - + time += 0.1 if time >= secondsAutoDismiss { dismiss(animated: true) @@ -159,36 +159,36 @@ class NCAccountRequest: UIViewController { } extension NCAccountRequest: UITableViewDelegate { - + func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { - + timer?.invalidate() progressView.progress = 0 } - + func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { if decelerate { // startTimer() } } - + func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { // startTimer() } - + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return heightCell } - + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - + if indexPath.row == accounts.count { - + dismiss(animated: true) delegate?.accountRequestAddAccount() - + } else { - + let account = accounts[indexPath.row] if account.account != activeAccount?.account { dismiss(animated: true) { @@ -202,7 +202,7 @@ extension NCAccountRequest: UITableViewDelegate { } extension NCAccountRequest: UITableViewDataSource { - + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if enableAddAccount { return accounts.count + 1 @@ -210,12 +210,12 @@ extension NCAccountRequest: UITableViewDataSource { return accounts.count } } - + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.backgroundColor = tableView.backgroundColor - + let avatarImage = cell.viewWithTag(10) as? UIImageView let userLabel = cell.viewWithTag(20) as? UILabel let urlLabel = cell.viewWithTag(30) as? UILabel @@ -223,9 +223,9 @@ extension NCAccountRequest: UITableViewDataSource { userLabel?.text = "" urlLabel?.text = "" - + if indexPath.row == accounts.count { - + avatarImage?.image = NCUtility.shared.loadImage(named: "plus").image(color: .systemBlue, size: 15) avatarImage?.contentMode = .center userLabel?.text = NSLocalizedString("_add_account_", comment: "") @@ -233,7 +233,7 @@ extension NCAccountRequest: UITableViewDataSource { userLabel?.font = UIFont.systemFont(ofSize: 15) } else { - + let account = accounts[indexPath.row] avatarImage?.image = NCUtility.shared.loadUserImage( @@ -254,7 +254,7 @@ extension NCAccountRequest: UITableViewDataSource { activeImage?.image = nil } } - + return cell } } diff --git a/iOSClient/Main/AudioRecorder/NCAudioRecorderViewController.swift b/iOSClient/Main/AudioRecorder/NCAudioRecorderViewController.swift index eecc55730..487ea6c26 100644 --- a/iOSClient/Main/AudioRecorder/NCAudioRecorderViewController.swift +++ b/iOSClient/Main/AudioRecorder/NCAudioRecorderViewController.swift @@ -28,59 +28,58 @@ import UIKit import AVFoundation import QuartzCore -@objc protocol NCAudioRecorderViewControllerDelegate : AnyObject { +@objc protocol NCAudioRecorderViewControllerDelegate: AnyObject { func didFinishRecording(_ viewController: NCAudioRecorderViewController, fileName: String) func didFinishWithoutRecording(_ viewController: NCAudioRecorderViewController, fileName: String) } -class NCAudioRecorderViewController: UIViewController , NCAudioRecorderDelegate { - +class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate { + open weak var delegate: NCAudioRecorderViewControllerDelegate? var recording: NCAudioRecorder! var recordDuration: TimeInterval = 0 var fileName: String = "" - let appDelegate = UIApplication.shared.delegate as! AppDelegate @IBOutlet weak var contentContainerView: UIView! @IBOutlet weak var durationLabel: UILabel! @IBOutlet weak var startStopLabel: UILabel! @IBOutlet weak var voiceRecordHUD: VoiceRecordHUD! - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + voiceRecordHUD.update(0.0) durationLabel.text = "" startStopLabel.text = NSLocalizedString("_voice_memo_start_", comment: "") - + changeTheming() } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - + changeTheming() } - + // MARK: - Colors - + func changeTheming() { - + view.backgroundColor = .clear contentContainerView.backgroundColor = UIColor.lightGray voiceRecordHUD.fillColor = UIColor.green } - + // MARK: - Action - + @IBAction func touchViewController() { - + if recording.state == .record { startStop() } else { @@ -89,21 +88,21 @@ class NCAudioRecorderViewController: UIViewController , NCAudioRecorderDelegate } } } - + @IBAction func startStop() { - + if recording.state == .record { - + recordDuration = 0 recording.stop() voiceRecordHUD.update(0.0) - + dismiss(animated: true) { self.delegate?.didFinishRecording(self, fileName: self.fileName) } - + } else { - + recordDuration = 0 do { try recording.record() @@ -113,11 +112,11 @@ class NCAudioRecorderViewController: UIViewController , NCAudioRecorderDelegate } } } - + // MARK: - Code - + func createRecorder(fileName: String) { - + self.fileName = fileName recording = NCAudioRecorder(to: fileName) recording.delegate = self @@ -131,27 +130,27 @@ class NCAudioRecorderViewController: UIViewController , NCAudioRecorderDelegate } } } - + func audioMeterDidUpdate(_ db: Float) { - - //print("db level: %f", db) - + + // print("db level: %f", db) + self.recording.recorder?.updateMeters() let ALPHA = 0.05 let peakPower = pow(10, (ALPHA * Double((self.recording.recorder?.peakPower(forChannel: 0))!))) var rate: Double = 0.0 - if (peakPower <= 0.2) { + if peakPower <= 0.2 { rate = 0.2 - } else if (peakPower > 0.9) { + } else if peakPower > 0.9 { rate = 1.0 } else { rate = peakPower } - + voiceRecordHUD.update(CGFloat(rate)) voiceRecordHUD.fillColor = UIColor.green recordDuration += 1 - durationLabel.text = String.init().formatSecondsToString(recordDuration/60) + durationLabel.text = String().formatSecondsToString(recordDuration/60) } } @@ -159,24 +158,24 @@ class NCAudioRecorderViewController: UIViewController , NCAudioRecorderDelegate @objc optional func audioMeterDidUpdate(_ dB: Float) } -open class NCAudioRecorder : NSObject { - +open class NCAudioRecorder: NSObject { + @objc public enum State: Int { case none, record, play } - + static var directory: String { return NSTemporaryDirectory() } - + open weak var delegate: NCAudioRecorderDelegate? open fileprivate(set) var url: URL open fileprivate(set) var state: State = .none - + open var bitRate = 192000 open var sampleRate = 44100.0 open var channels = 1 - + var recorder: AVAudioRecorder? fileprivate var player: AVAudioPlayer? fileprivate var link: CADisplayLink? @@ -184,13 +183,13 @@ open class NCAudioRecorder : NSObject { var metering: Bool { return delegate?.responds(to: #selector(NCAudioRecorderDelegate.audioMeterDidUpdate(_:))) == true } - + // MARK: - Initializers - + public init(to: String) { url = URL(fileURLWithPath: NCAudioRecorder.directory).appendingPathComponent(to) super.init() - + do { try AVAudioSession.sharedInstance().setCategory(.playAndRecord) try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.PortOverride.speaker) @@ -199,50 +198,50 @@ open class NCAudioRecorder : NSObject { print(error) } } - + deinit { print("deinit NCAudioRecorder") - + do { try AVAudioSession.sharedInstance().setActive(false) } catch { print(error) } } - + // MARK: - Record - + open func prepare() throws { - + let settings: [String: AnyObject] = [ - AVFormatIDKey : NSNumber(value: Int32(kAudioFormatAppleLossless) as Int32), + AVFormatIDKey: NSNumber(value: Int32(kAudioFormatAppleLossless) as Int32), AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue as AnyObject, AVEncoderBitRateKey: bitRate as AnyObject, AVNumberOfChannelsKey: channels as AnyObject, AVSampleRateKey: sampleRate as AnyObject ] - + recorder = try AVAudioRecorder(url: url, settings: settings) recorder?.prepareToRecord() recorder?.delegate = delegate recorder?.isMeteringEnabled = metering } - + open func record() throws { - + if recorder == nil { try prepare() } - + self.state = .record if self.metering { self.startMetering() } self.recorder?.record() } - + open func stop() { - + switch state { case .play: player?.stop() @@ -254,30 +253,30 @@ open class NCAudioRecorder : NSObject { default: break } - + state = .none } - + // MARK: - Metering - + @objc func updateMeter() { guard let recorder = recorder else { return } - + recorder.updateMeters() - + let dB = recorder.averagePower(forChannel: 0) - + delegate?.audioMeterDidUpdate?(dB) } - + fileprivate func startMetering() { - + link = CADisplayLink(target: self, selector: #selector(NCAudioRecorder.updateMeter)) link?.add(to: RunLoop.current, forMode: RunLoop.Mode.common) } - + fileprivate func stopMetering() { - + link?.invalidate() link = nil } @@ -286,48 +285,48 @@ open class NCAudioRecorder : NSObject { @IBDesignable class VoiceRecordHUD: UIView { @IBInspectable var rate: CGFloat = 0.0 - + @IBInspectable var fillColor: UIColor = UIColor.green { didSet { setNeedsDisplay() } } - + var image: UIImage! { didSet { setNeedsDisplay() } } - + // MARK: - View Life Cycle override init(frame: CGRect) { super.init(frame: frame) image = UIImage(named: "microphone") } - + required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) image = UIImage(named: "microphone") } - + func update(_ rate: CGFloat) { self.rate = rate setNeedsDisplay() } - + override func draw(_ rect: CGRect) { let context = UIGraphicsGetCurrentContext() context?.translateBy(x: 0, y: bounds.size.height) context?.scaleBy(x: 1, y: -1) - + context?.draw(image.cgImage!, in: bounds) context?.clip(to: bounds, mask: image.cgImage!) - + context?.setFillColor(fillColor.cgColor.components!) context?.fill(CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height * rate)) } - + override func prepareForInterfaceBuilder() { let bundle = Bundle(for: type(of: self)) image = UIImage(named: "microphone", in: bundle, compatibleWith: self.traitCollection) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index bf70128c7..3b58091c7 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -24,8 +24,8 @@ import UIKit import NCCommunication -class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate, NCListCellDelegate, NCGridCellDelegate, NCSectionHeaderMenuDelegate, UIAdaptivePresentationControllerDelegate, NCEmptyDataSetDelegate, UIContextMenuInteractionDelegate, NCAccountRequestDelegate, NCBackgroundImageColorDelegate { - +class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate, NCListCellDelegate, NCGridCellDelegate, NCSectionHeaderMenuDelegate, UIAdaptivePresentationControllerDelegate, NCEmptyDataSetDelegate, UIContextMenuInteractionDelegate, NCAccountRequestDelegate, NCBackgroundImageColorDelegate { + @IBOutlet weak var collectionView: UICollectionView! let appDelegate = UIApplication.shared.delegate as! AppDelegate @@ -59,11 +59,11 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS private var timerInputSearch: Timer? internal var literalSearch: String? internal var isSearching: Bool = false - + internal var isReloadDataSourceNetworkInProgress: Bool = false - + private var pushed: Bool = false - + // DECLARE internal var layoutKey = "" internal var titleCurrentFolder = "" @@ -71,18 +71,18 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS internal var emptyImage: UIImage? internal var emptyTitle: String = "" internal var emptyDescription: String = "" - + // MARK: - View Life Cycle required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } - + override func viewDidLoad() { super.viewDidLoad() - + self.navigationController?.presentationController?.delegate = self - + collectionView.alwaysBounceVertical = true if enableSearchBar { @@ -94,51 +94,51 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS navigationItem.searchController = searchController navigationItem.hidesSearchBarWhenScrolling = false } - + // Cell - collectionView.register(UINib.init(nibName: "NCListCell", bundle: nil), forCellWithReuseIdentifier: "listCell") - collectionView.register(UINib.init(nibName: "NCGridCell", bundle: nil), forCellWithReuseIdentifier: "gridCell") - collectionView.register(UINib.init(nibName: "NCTransferCell", bundle: nil), forCellWithReuseIdentifier: "transferCell") + collectionView.register(UINib(nibName: "NCListCell", bundle: nil), forCellWithReuseIdentifier: "listCell") + collectionView.register(UINib(nibName: "NCGridCell", bundle: nil), forCellWithReuseIdentifier: "gridCell") + collectionView.register(UINib(nibName: "NCTransferCell", bundle: nil), forCellWithReuseIdentifier: "transferCell") // Header - collectionView.register(UINib.init(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu") - + collectionView.register(UINib(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu") + // Footer - collectionView.register(UINib.init(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter") - + collectionView.register(UINib(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter") + listLayout = NCListLayout() gridLayout = NCGridLayout() - + // Refresh Control collectionView.addSubview(refreshControl) refreshControl.action(for: .valueChanged) { _ in self.reloadDataSourceNetwork(forced: true) } - + // Empty - emptyDataSet = NCEmptyDataSet.init(view: collectionView, offset: headerHeight, delegate: self) - + emptyDataSet = NCEmptyDataSet(view: collectionView, offset: headerHeight, delegate: self) + // Long Press on CollectionView let longPressedGesture = UILongPressGestureRecognizer(target: self, action: #selector(longPressCollecationView(_:))) longPressedGesture.minimumPressDuration = 0.5 longPressedGesture.delegate = self longPressedGesture.delaysTouchesBegan = true collectionView.addGestureRecognizer(longPressedGesture) - + // Notification - + NotificationCenter.default.addObserver(self, selector: #selector(initialize), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil) changeTheming() } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // ACTIVE appDelegate.activeViewController = self - + // 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) @@ -146,7 +146,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSource(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSource), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSourceNetworkForced(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced), 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) NotificationCenter.default.addObserver(self, selector: #selector(copyFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterCopyFile), object: nil) @@ -157,43 +157,43 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS NotificationCenter.default.addObserver(self, selector: #selector(downloadStartFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadStartFile), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(downloadedFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(downloadCancelFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadCancelFile), object: nil) - + 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(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) - + NotificationCenter.default.addObserver(self, selector: #selector(triggerProgressTask(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask), object: nil) + if serverUrl == "" { appDelegate.activeServerUrl = NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) } else { appDelegate.activeServerUrl = serverUrl } - + navigationController?.navigationBar.prefersLargeTitles = true navigationController?.setNavigationBarHidden(false, animated: true) setNavigationItem() - + changeTheming() reloadDataSource() } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + reloadDataSourceNetwork() } - + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterCloseRichWorkspaceWebView), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadAvatar), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSource), 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) @@ -213,95 +213,91 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS pushed = false } - + func presentationControllerDidDismiss( _ presentationController: UIPresentationController) { let viewController = presentationController.presentedViewController if viewController is NCViewerRichWorkspaceWebView { closeRichWorkspaceWebView() - } else if viewController is UINavigationController { - if (viewController as! UINavigationController).topViewController is NCFileViewInFolder { - appDelegate.activeFileViewInFolder = nil - } } } - + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) - + coordinator.animate(alongsideTransition: nil) { _ in self.collectionView?.collectionViewLayout.invalidateLayout() } } - + override var canBecomeFirstResponder: Bool { return true } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - + changeTheming() } - + // MARK: - NotificationCenter @objc func initialize() { - + if appDelegate.account == "" { return } - + // Search if searchController?.isActive ?? false { searchController?.isActive = false } - + // Select if isEditMode { isEditMode = !isEditMode selectOcId.removeAll() } - + if self.view?.window != nil { if serverUrl == "" { appDelegate.activeServerUrl = NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) } else { appDelegate.activeServerUrl = serverUrl } - + appDelegate.listFilesVC.removeAll() appDelegate.listFavoriteVC.removeAll() appDelegate.listOfflineVC.removeAll() } - + if serverUrl != "" { self.navigationController?.popToRootViewController(animated: false) } - + setNavigationItem() reloadDataSource() changeTheming() } - + @objc func changeTheming() { - + view.backgroundColor = NCBrandColor.shared.systemBackground collectionView.backgroundColor = NCBrandColor.shared.systemBackground refreshControl.tintColor = .gray - + layoutForView = NCUtility.shared.getLayoutForView(key: layoutKey, serverUrl: serverUrl) gridLayout.itemForLine = CGFloat(layoutForView?.itemForLine ?? 3) - + if layoutForView?.layout == NCGlobal.shared.layoutList { collectionView?.collectionViewLayout = listLayout } else { collectionView?.collectionViewLayout = gridLayout } - + // IMAGE BACKGROUND if layoutForView?.imageBackgroud != "" { let imagePath = CCUtility.getDirectoryGroup().appendingPathComponent(NCGlobal.shared.appBackground).path + "/" + layoutForView!.imageBackgroud do { - let data = try Data.init(contentsOf: URL(fileURLWithPath: imagePath)) - if let image = UIImage.init(data: data) { + let data = try Data(contentsOf: URL(fileURLWithPath: imagePath)) + if let image = UIImage(data: data) { backgroundImageView.image = image backgroundImageView.contentMode = .scaleToFill collectionView.backgroundView = backgroundImageView @@ -311,33 +307,33 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS backgroundImageView.image = nil collectionView.backgroundView = nil } - + // COLOR BACKGROUND let activeAccount = NCManageDatabase.shared.getActiveAccount() if traitCollection.userInterfaceStyle == .dark { if activeAccount?.darkColorBackground != "" { - collectionView.backgroundColor = UIColor.init(hex: activeAccount?.darkColorBackground ?? "") + collectionView.backgroundColor = UIColor(hex: activeAccount?.darkColorBackground ?? "") } else { collectionView.backgroundColor = NCBrandColor.shared.systemBackground } } else { if activeAccount?.lightColorBackground != "" { - collectionView.backgroundColor = UIColor.init(hex: activeAccount?.lightColorBackground ?? "") + collectionView.backgroundColor = UIColor(hex: activeAccount?.lightColorBackground ?? "") } else { collectionView.backgroundColor = NCBrandColor.shared.systemBackground } } - + collectionView.reloadData() } - + @objc func reloadDataSource(_ notification: NSNotification) { - + reloadDataSource() } - + @objc func reloadDataSourceNetworkForced(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let serverUrl = userInfo["serverUrl"] as? String { if serverUrl == self.serverUrl { @@ -348,17 +344,17 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS reloadDataSourceNetwork(forced: true) } } - + @objc func changeStatusFolderE2EE(_ notification: NSNotification) { reloadDataSource() } - + @objc func closeRichWorkspaceWebView() { reloadDataSourceNetwork() } - + @objc func deleteFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let fileNameView = userInfo["fileNameView"] as? String, let onlyLocalCache = userInfo["onlyLocalCache"] as? Bool { if onlyLocalCache { reloadDataSource() @@ -369,16 +365,16 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS let indexPath = IndexPath(row: row, section: 0) collectionView?.performBatchUpdates({ collectionView?.deleteItems(at: [indexPath]) - }, completion: { (_) in + }, completion: { _ in self.collectionView?.reloadData() }) } } } } - + @objc func moveFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let serverUrlFrom = userInfo["serverUrlFrom"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { // DEL if serverUrlFrom == serverUrl && metadata.account == appDelegate.account { @@ -386,7 +382,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS let indexPath = IndexPath(row: row, section: 0) collectionView?.performBatchUpdates({ collectionView?.deleteItems(at: [indexPath]) - }, completion: { (_) in + }, completion: { _ in self.collectionView?.reloadData() }) } @@ -396,30 +392,30 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS let indexPath = IndexPath(row: row, section: 0) collectionView?.performBatchUpdates({ collectionView?.insertItems(at: [indexPath]) - }, completion: { (_) in + }, completion: { _ in self.collectionView?.reloadData() }) } } } } - + @objc func copyFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let serverUrlTo = userInfo["serverUrlTo"] as? String { if serverUrlTo == self.serverUrl { reloadDataSource() } } } - + @objc func renameFile(_ notification: NSNotification) { - + reloadDataSource() } - + @objc func createFolder(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { if metadata.serverUrl == serverUrl && metadata.account == appDelegate.account { pushMetadata(metadata) @@ -428,18 +424,18 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS reloadDataSourceNetwork() } } - + @objc func favoriteFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { if dataSource.getIndexMetadata(ocId: metadata.ocId) != nil { reloadDataSource() } } } - + @objc func downloadStartFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { if let row = dataSource.reloadMetadata(ocId: metadata.ocId) { let indexPath = IndexPath(row: row, section: 0) @@ -449,9 +445,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } } - + @objc func downloadedFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let _ = userInfo["errorCode"] as? Int, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { if let row = dataSource.reloadMetadata(ocId: metadata.ocId) { let indexPath = IndexPath(row: row, section: 0) @@ -461,9 +457,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } } - + @objc func downloadCancelFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { if let row = dataSource.reloadMetadata(ocId: metadata.ocId) { let indexPath = IndexPath(row: row, section: 0) @@ -473,9 +469,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } } - + @objc func uploadStartFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { if metadata.serverUrl == serverUrl && metadata.account == appDelegate.account { dataSource.addMetadata(metadata) @@ -483,9 +479,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } } - + @objc func uploadedFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let ocIdTemp = userInfo["ocIdTemp"] as? String, let _ = userInfo["errorCode"] as? Int, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { if metadata.serverUrl == serverUrl && metadata.account == appDelegate.account { dataSource.reloadMetadata(ocId: metadata.ocId, ocIdTemp: ocIdTemp) @@ -493,11 +489,11 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } } - + @objc func uploadCancelFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let serverUrl = userInfo["serverUrl"] as? String, let account = userInfo["account"] as? String { - + if serverUrl == self.serverUrl && account == appDelegate.account { if let row = dataSource.deleteMetadata(ocId: ocId) { let indexPath = IndexPath(row: row, section: 0) @@ -505,7 +501,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS if indexPath.section < (collectionView?.numberOfSections ?? 0) && indexPath.row < (collectionView?.numberOfItems(inSection: indexPath.section) ?? 0) { collectionView?.deleteItems(at: [indexPath]) } - }, completion: { (_) in + }, completion: { _ in self.collectionView?.reloadData() }) } else { @@ -514,13 +510,13 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } } - + @objc func triggerProgressTask(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let progressNumber = userInfo["progress"] as? NSNumber, let totalBytes = userInfo["totalBytes"] as? Int64, let totalBytesExpected = userInfo["totalBytesExpected"] as? Int64, let ocId = userInfo["ocId"] as? String { - + let status = userInfo["status"] as? Int ?? NCGlobal.shared.metadataStatusNormal - + if let index = dataSource.getIndexMetadata(ocId: ocId) { if let cell = collectionView?.cellForItem(at: IndexPath(row: index, section: 0)) { if cell is NCListCell { @@ -579,23 +575,23 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } // MARK: - Layout - + @objc func setNavigationItem() { - + if isEditMode { - - navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage.init(named: "navigationMore"), style: .plain, target: self, action:#selector(tapSelectMenu(sender:))) + + navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "navigationMore"), style: .plain, target: self, action: #selector(tapSelectMenu(sender:))) navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: .plain, target: self, action: #selector(tapSelect(sender:))) navigationItem.title = NSLocalizedString("_selected_", comment: "") + " : \(selectOcId.count)" + " / \(dataSource.metadatas.count)" - + } else { - + navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_select_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(tapSelect(sender:))) navigationItem.leftBarButtonItem = nil navigationItem.title = titleCurrentFolder - + // PROFILE BUTTON - + if layoutKey == NCGlobal.shared.layoutViewFiles { let activeAccount = NCManageDatabase.shared.getActiveAccount() @@ -606,9 +602,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS let button = UIButton(type: .custom) button.setImage(image, for: .normal) - + if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) { - + var titleButton = " " if getNavigationTitle() == activeAccount?.alias { @@ -620,16 +616,16 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS button.setTitle(titleButton, for: .normal) button.setTitleColor(.systemBlue, for: .normal) } - + button.semanticContentAttribute = .forceLeftToRight button.sizeToFit() button.action(for: .touchUpInside) { _ in - + let accounts = NCManageDatabase.shared.getAllAccountOrderAlias() if accounts.count > 0 { - + if let vcAccountRequest = UIStoryboard(name: "NCAccountRequest", bundle: nil).instantiateInitialViewController() as? NCAccountRequest { - + vcAccountRequest.activeAccount = NCManageDatabase.shared.getActiveAccount() vcAccountRequest.accounts = accounts vcAccountRequest.enableTimerProgress = false @@ -640,9 +636,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS let screenHeighMax = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/5) let numberCell = accounts.count + 1 let height = min(CGFloat(numberCell * Int(vcAccountRequest.heightCell) + 45), screenHeighMax) - + let popup = NCPopupViewController(contentController: vcAccountRequest, popupWidth: 300, popupHeight: height) - + UIApplication.shared.keyWindow?.rootViewController?.present(popup, animated: true) } } @@ -652,7 +648,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } } - + func getNavigationTitle() -> String { let activeAccount = NCManageDatabase.shared.getActiveAccount() guard let userAlias = activeAccount?.alias, !userAlias.isEmpty else { @@ -660,30 +656,30 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } return userAlias } - + // MARK: - BackgroundImageColor Delegate - + func colorPickerCancel() { changeTheming() } - + func colorPickerWillChange(color: UIColor) { collectionView.backgroundColor = color } - + func colorPickerDidChange(lightColor: String, darkColor: String) { NCManageDatabase.shared.setAccountColorFiles(lightColorBackground: lightColor, darkColorBackground: darkColor) - + changeTheming() } - + // MARK: - Empty - + func emptyDataSetView(_ view: NCEmptyView) { - + if searchController?.isActive ?? false { - view.emptyImage.image = UIImage.init(named: "search")?.image(color: .gray, size: UIScreen.main.bounds.width) + view.emptyImage.image = UIImage(named: "search")?.image(color: .gray, size: UIScreen.main.bounds.width) if isReloadDataSourceNetworkInProgress { view.emptyTitle.text = NSLocalizedString("_search_in_progress_", comment: "") } else { @@ -691,7 +687,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } view.emptyDescription.text = NSLocalizedString("_search_instruction_", comment: "") } else if isReloadDataSourceNetworkInProgress { - view.emptyImage.image = UIImage.init(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width) + view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width) view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "") view.emptyDescription.text = "" } else { @@ -700,15 +696,15 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS view.emptyTitle.text = NSLocalizedString(emptyTitle, comment: "") view.emptyDescription.text = NSLocalizedString(emptyDescription, comment: "") } else { - view.emptyImage.image = UIImage.init(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width) + view.emptyImage.image = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width) view.emptyTitle.text = NSLocalizedString("_files_no_files_", comment: "") view.emptyDescription.text = NSLocalizedString("_no_file_pull_down_", comment: "") } } } - + // MARK: - SEARCH - + func updateSearchResults(for searchController: UISearchController) { timerInputSearch?.invalidate() @@ -716,57 +712,57 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS literalSearch = searchController.searchBar.text collectionView?.reloadData() } - + func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) { - + isSearching = true metadatasSource.removeAll() reloadDataSource() } - + func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { - + isSearching = false literalSearch = "" reloadDataSource() } - + // MARK: - TAP EVENT - + @objc func tapSelect(sender: Any) { - + isEditMode = !isEditMode - + selectOcId.removeAll() setNavigationItem() - + self.collectionView.reloadData() } - + func accountRequestChangeAccount(account: String) { NCManageDatabase.shared.setAccountActive(account) if let activeAccount = NCManageDatabase.shared.getActiveAccount() { - + NCOperationQueue.shared.cancelAllQueue() NCNetworking.shared.cancelAllTask() - + appDelegate.settingAccount(activeAccount.account, urlBase: activeAccount.urlBase, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account)) - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterInitialize) } } - + func accountRequestAddAccount() { appDelegate.openLogin(viewController: self, selector: NCGlobal.shared.introLogin, openLoginWeb: false) } - + func tapSwitchHeader(sender: Any) { - + if collectionView.collectionViewLayout == gridLayout { // list layout UIView.animate(withDuration: 0.0, animations: { self.collectionView.collectionViewLayout.invalidateLayout() - self.collectionView.setCollectionViewLayout(self.listLayout, animated: false, completion: { (_) in + self.collectionView.setCollectionViewLayout(self.listLayout, animated: false, completion: { _ in self.collectionView.reloadData() }) }) @@ -776,7 +772,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS // grid layout UIView.animate(withDuration: 0.0, animations: { self.collectionView.collectionViewLayout.invalidateLayout() - self.collectionView.setCollectionViewLayout(self.gridLayout, animated: false, completion: { (_) in + self.collectionView.setCollectionViewLayout(self.gridLayout, animated: false, completion: { _ in self.collectionView.reloadData() }) }) @@ -784,35 +780,35 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS NCUtility.shared.setLayoutForView(key: layoutKey, serverUrl: serverUrl, layout: layoutForView?.layout) } } - + func tapOrderHeader(sender: Any) { - + let sortMenu = NCSortMenu() sortMenu.toggleMenu(viewController: self, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) } - + @objc func tapSelectMenu(sender: Any) { - + toggleMenuSelect() } - + func tapMoreHeader(sender: Any) { } - + func tapMoreListItem(with objectId: String, namedButtonMore: String, image: UIImage?, sender: Any) { - + tapMoreGridItem(with: objectId, namedButtonMore: namedButtonMore, image: image, sender: sender) } - + func tapShareListItem(with objectId: String, sender: Any) { - + if isEditMode { return } guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(objectId) else { return } - - NCFunctionCenter.shared.openShare(ViewController: self, metadata: metadata, indexPage: .sharing) + + NCFunctionCenter.shared.openShare(viewController: self, metadata: metadata, indexPage: .sharing) } - + func tapMoreGridItem(with objectId: String, namedButtonMore: String, image: UIImage?, sender: Any) { - + if isEditMode { return } guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(objectId) else { return } @@ -823,34 +819,34 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS NCNetworking.shared.cancelTransferMetadata(metadata) { } } } - + func tapRichWorkspace(sender: Any) { - + if let navigationController = UIStoryboard(name: "NCViewerRichWorkspace", bundle: nil).instantiateInitialViewController() as? UINavigationController { if let viewerRichWorkspace = navigationController.topViewController as? NCViewerRichWorkspace { viewerRichWorkspace.richWorkspaceText = richWorkspaceText ?? "" viewerRichWorkspace.serverUrl = serverUrl - + navigationController.modalPresentationStyle = .fullScreen self.present(navigationController, animated: true, completion: nil) } } } - + func longPressListItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer) { } - + func longPressGridItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer) { } - + func longPressMoreListItem(with objectId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) { } - + func longPressMoreGridItem(with objectId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) { } - + @objc func longPressCollecationView(_ gestureRecognizer: UILongPressGestureRecognizer) { - + openMenuItems(with: nil, gestureRecognizer: gestureRecognizer) /* if #available(iOS 13.0, *) { @@ -860,121 +856,121 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } */ } - + @available(iOS 13.0, *) func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? { - + return UIContextMenuConfiguration(identifier: nil, previewProvider: { - + return nil - - }, actionProvider: { suggestedActions in - - //let share = UIAction(title: "Share Pupper", image: UIImage(systemName: "square.and.arrow.up")) { action in - //} - //return UIMenu(title: "Main Menu", children: [share]) + + }, actionProvider: { _ in + + // let share = UIAction(title: "Share Pupper", image: UIImage(systemName: "square.and.arrow.up")) { action in + // } + // return UIMenu(title: "Main Menu", children: [share]) return nil }) } - + func openMenuItems(with objectId: String?, gestureRecognizer: UILongPressGestureRecognizer) { - + if gestureRecognizer.state != .began { return } - + var listMenuItems: [UIMenuItem] = [] let touchPoint = gestureRecognizer.location(in: collectionView) - + becomeFirstResponder() - + if serverUrl != "" { - listMenuItems.append(UIMenuItem.init(title: NSLocalizedString("_paste_file_", comment: ""), action: #selector(pasteFilesMenu))) + listMenuItems.append(UIMenuItem(title: NSLocalizedString("_paste_file_", comment: ""), action: #selector(pasteFilesMenu))) } if #available(iOS 13.0, *) { if !NCBrandOptions.shared.disable_background_color { - listMenuItems.append(UIMenuItem.init(title: NSLocalizedString("_background_", comment: ""), action: #selector(backgroundFilesMenu))) + listMenuItems.append(UIMenuItem(title: NSLocalizedString("_background_", comment: ""), action: #selector(backgroundFilesMenu))) } } - + if listMenuItems.count > 0 { UIMenuController.shared.menuItems = listMenuItems UIMenuController.shared.setTargetRect(CGRect(x: touchPoint.x, y: touchPoint.y, width: 0, height: 0), in: collectionView) UIMenuController.shared.setMenuVisible(true, animated: true) } } - + // MARK: - Menu Item - + override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { - - if (#selector(pasteFilesMenu) == action) { + + if #selector(pasteFilesMenu) == action { if UIPasteboard.general.items.count > 0 { return true } } - - if (#selector(backgroundFilesMenu) == action) { + + if #selector(backgroundFilesMenu) == action { return true } - + return false } - + @objc func pasteFilesMenu() { NCFunctionCenter.shared.pastePasteboard(serverUrl: serverUrl) } - + @objc func backgroundFilesMenu() { - + if let vcBackgroundImageColor = UIStoryboard(name: "NCBackgroundImageColor", bundle: nil).instantiateInitialViewController() as? NCBackgroundImageColor { - + vcBackgroundImageColor.delegate = self vcBackgroundImageColor.setupColor = collectionView.backgroundColor if let activeAccount = NCManageDatabase.shared.getActiveAccount() { vcBackgroundImageColor.lightColor = activeAccount.lightColorBackground vcBackgroundImageColor.darkColor = activeAccount.darkColorBackground } - + let popup = NCPopupViewController(contentController: vcBackgroundImageColor, popupWidth: vcBackgroundImageColor.width, popupHeight: vcBackgroundImageColor.height) popup.backgroundAlpha = 0 - + self.present(popup, animated: true) } } - + // MARK: - DataSource + NC Endpoint - + @objc func reloadDataSource() { - + if appDelegate.account == "" { return } - + // Get richWorkspace Text let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, serverUrl)) richWorkspaceText = directory?.richWorkspace - + // E2EE isEncryptedFolder = CCUtility.isFolderEncrypted(serverUrl, e2eEncrypted: metadataFolder?.e2eEncrypted ?? false, account: appDelegate.account, urlBase: appDelegate.urlBase) // get auto upload folder autoUploadFileName = NCManageDatabase.shared.getAccountAutoUploadFileName() autoUploadDirectory = NCManageDatabase.shared.getAccountAutoUploadDirectory(urlBase: appDelegate.urlBase, account: appDelegate.account) - + // get layout for view layoutForView = NCUtility.shared.getLayoutForView(key: layoutKey, serverUrl: serverUrl) } - + @objc func reloadDataSourceNetwork(forced: Bool = false) { } - + @objc func networkSearch() { - + if appDelegate.account == "" { return } - + if literalSearch?.count ?? 0 > 1 { - + isReloadDataSourceNetworkInProgress = true collectionView?.reloadData() - - NCNetworking.shared.searchFiles(urlBase: appDelegate.urlBase, user: appDelegate.user, literal: literalSearch!) { (account, metadatas, errorCode, errorDescription) in - + + NCNetworking.shared.searchFiles(urlBase: appDelegate.urlBase, user: appDelegate.user, literal: literalSearch!) { _, metadatas, errorCode, _ in + DispatchQueue.main.async { if self.searchController?.isActive ?? false && errorCode == 0 { self.metadatasSource = metadatas! @@ -988,46 +984,46 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS self.refreshControl.endRefreshing() } } - - @objc func networkReadFolder(forced: Bool, completion: @escaping(_ tableDirectory: tableDirectory?, _ metadatas: [tableMetadata]?, _ metadatasUpdate: [tableMetadata]?, _ metadatasDelete: [tableMetadata]?, _ errorCode: Int, _ errorDescription: String)->()) { - + + @objc func networkReadFolder(forced: Bool, completion: @escaping(_ tableDirectory: tableDirectory?, _ metadatas: [tableMetadata]?, _ metadatasUpdate: [tableMetadata]?, _ metadatasDelete: [tableMetadata]?, _ errorCode: Int, _ errorDescription: String) -> Void) { + var tableDirectory: tableDirectory? - - NCNetworking.shared.readFile(serverUrlFileName: serverUrl, account: appDelegate.account) { (account, metadataFolder, errorCode, errorDescription) in - + + NCNetworking.shared.readFile(serverUrlFileName: serverUrl, account: appDelegate.account) { account, metadataFolder, errorCode, errorDescription in + if errorCode == 0 { - + if let metadataFolder = metadataFolder { tableDirectory = NCManageDatabase.shared.setDirectory(richWorkspace: metadataFolder.richWorkspace, serverUrl: self.serverUrl, account: account) } - + if forced || tableDirectory?.etag != metadataFolder?.etag || metadataFolder?.e2eEncrypted ?? false { - - NCNetworking.shared.readFolder(serverUrl: self.serverUrl, account: self.appDelegate.account) { (account, metadataFolder, metadatas, metadatasUpdate, metadatasLocalUpdate, metadatasDelete, errorCode, errorDescription) in - + + NCNetworking.shared.readFolder(serverUrl: self.serverUrl, account: self.appDelegate.account) { account, metadataFolder, metadatas, metadatasUpdate, _, metadatasDelete, errorCode, errorDescription in + if errorCode == 0 { self.metadataFolder = metadataFolder - + // E2EE if let metadataFolder = metadataFolder { if metadataFolder.e2eEncrypted && CCUtility.isEnd(toEndEnabled: self.appDelegate.account) { - - NCCommunication.shared.getE2EEMetadata(fileId: metadataFolder.ocId, e2eToken: nil) { (account, e2eMetadata, errorCode, errorDescription) in - + + NCCommunication.shared.getE2EEMetadata(fileId: metadataFolder.ocId, e2eToken: nil) { account, e2eMetadata, errorCode, errorDescription in + if errorCode == 0 && e2eMetadata != nil { - + if !NCEndToEndMetadata.shared.decoderMetadata(e2eMetadata!, privateKey: CCUtility.getEndToEndPrivateKey(account), serverUrl: self.serverUrl, account: account, urlBase: self.appDelegate.urlBase) { - + NCContentPresenter.shared.messageNotification("_error_e2ee_", description: "_e2e_error_decode_metadata_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorDecodeMetadata) } else { self.reloadDataSource() } - + } else if errorCode != NCGlobal.shared.errorResourceNotFound { - + NCContentPresenter.shared.messageNotification("_error_e2ee_", description: "_e2e_error_decode_metadata_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorDecodeMetadata) } - + completion(tableDirectory, metadatas, metadatasUpdate, metadatasDelete, errorCode, errorDescription) } } else { @@ -1048,139 +1044,139 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } } - - // MARK: - Push metadata - + + // MARK: - Push metadata + func pushMetadata(_ metadata: tableMetadata) { - + guard let serverUrlPush = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName) else { return } appDelegate.activeMetadata = metadata - + // FILES if layoutKey == NCGlobal.shared.layoutViewFiles && !pushed { - + if let viewController = appDelegate.listFilesVC[serverUrlPush] { - + if viewController.isViewLoaded { pushViewController(viewController: viewController) } - + } else { - - if let viewController:NCFiles = UIStoryboard(name: "NCFiles", bundle: nil).instantiateInitialViewController() as? NCFiles { - + + if let viewController: NCFiles = UIStoryboard(name: "NCFiles", bundle: nil).instantiateInitialViewController() as? NCFiles { + viewController.isRoot = false viewController.serverUrl = serverUrlPush viewController.titleCurrentFolder = metadata.fileNameView - + appDelegate.listFilesVC[serverUrlPush] = viewController - + pushViewController(viewController: viewController) } } } - + // FAVORITE if layoutKey == NCGlobal.shared.layoutViewFavorite && !pushed { - + if let viewController = appDelegate.listFavoriteVC[serverUrlPush] { - + if viewController.isViewLoaded { pushViewController(viewController: viewController) } } else { - - if let viewController:NCFavorite = UIStoryboard(name: "NCFavorite", bundle: nil).instantiateInitialViewController() as? NCFavorite { - + + if let viewController: NCFavorite = UIStoryboard(name: "NCFavorite", bundle: nil).instantiateInitialViewController() as? NCFavorite { + viewController.serverUrl = serverUrlPush viewController.titleCurrentFolder = metadata.fileNameView - + appDelegate.listFavoriteVC[serverUrlPush] = viewController - + pushViewController(viewController: viewController) } } } - + // OFFLINE if layoutKey == NCGlobal.shared.layoutViewOffline && !pushed { - + if let viewController = appDelegate.listOfflineVC[serverUrlPush] { - + if viewController.isViewLoaded { pushViewController(viewController: viewController) } - + } else { - - if let viewController:NCOffline = UIStoryboard(name: "NCOffline", bundle: nil).instantiateInitialViewController() as? NCOffline { - + + if let viewController: NCOffline = UIStoryboard(name: "NCOffline", bundle: nil).instantiateInitialViewController() as? NCOffline { + viewController.serverUrl = serverUrlPush viewController.titleCurrentFolder = metadata.fileNameView - + appDelegate.listOfflineVC[serverUrlPush] = viewController - + pushViewController(viewController: viewController) } } } - + // RECENT ( for push use Files ... he he he ) if layoutKey == NCGlobal.shared.layoutViewRecent && !pushed { - + if let viewController = appDelegate.listFilesVC[serverUrlPush] { - + if viewController.isViewLoaded { pushViewController(viewController: viewController) } - + } else { - - if let viewController:NCFiles = UIStoryboard(name: "NCFiles", bundle: nil).instantiateInitialViewController() as? NCFiles { - + + if let viewController: NCFiles = UIStoryboard(name: "NCFiles", bundle: nil).instantiateInitialViewController() as? NCFiles { + viewController.isRoot = false viewController.serverUrl = serverUrlPush viewController.titleCurrentFolder = metadata.fileNameView - + appDelegate.listFilesVC[serverUrlPush] = viewController - + pushViewController(viewController: viewController) } } } - - //VIEW IN FOLDER + + // VIEW IN FOLDER if layoutKey == NCGlobal.shared.layoutViewViewInFolder && !pushed { - - if let viewController:NCFileViewInFolder = UIStoryboard(name: "NCFileViewInFolder", bundle: nil).instantiateInitialViewController() as? NCFileViewInFolder { - + + if let viewController: NCFileViewInFolder = UIStoryboard(name: "NCFileViewInFolder", bundle: nil).instantiateInitialViewController() as? NCFileViewInFolder { + viewController.serverUrl = serverUrlPush viewController.titleCurrentFolder = metadata.fileNameView - + pushViewController(viewController: viewController) } } - + // SHARES ( for push use Files ... he he he ) if layoutKey == NCGlobal.shared.layoutViewShares && !pushed { - + if let viewController = appDelegate.listFilesVC[serverUrlPush] { - + if viewController.isViewLoaded { pushViewController(viewController: viewController) } - + } else { - - if let viewController:NCFiles = UIStoryboard(name: "NCFiles", bundle: nil).instantiateInitialViewController() as? NCFiles { - + + if let viewController: NCFiles = UIStoryboard(name: "NCFiles", bundle: nil).instantiateInitialViewController() as? NCFiles { + viewController.isRoot = false viewController.serverUrl = serverUrlPush viewController.titleCurrentFolder = metadata.fileNameView - + appDelegate.listFilesVC[serverUrlPush] = viewController - + pushViewController(viewController: viewController) } } @@ -1193,10 +1189,10 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS extension NCCollectionViewCommon: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - + guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else { return } appDelegate.activeMetadata = metadata - + if isEditMode { if let index = selectOcId.firstIndex(of: metadata.ocId) { selectOcId.remove(at: index) @@ -1207,20 +1203,20 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { self.navigationItem.title = NSLocalizedString("_selected_", comment: "") + " : \(selectOcId.count)" + " / \(dataSource.metadatas.count)" return } - + if metadata.e2eEncrypted && !CCUtility.isEnd(toEndEnabled: appDelegate.account) { NCContentPresenter.shared.messageNotification("_info_", description: "_e2e_goto_settings_for_enable_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorE2EENotEnabled) return } - + if metadata.directory { - + pushMetadata(metadata) - } else { + } else if !(self is NCFileViewInFolder) { let imageIcon = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) - + if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue { var metadatas: [tableMetadata] = [] for metadata in dataSource.metadatas { @@ -1231,33 +1227,33 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { NCViewer.shared.view(viewController: self, metadata: metadata, metadatas: metadatas, imageIcon: imageIcon) return } - + if CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { NCViewer.shared.view(viewController: self, metadata: metadata, metadatas: [metadata], imageIcon: imageIcon) } else if NCCommunication.shared.isNetworkReachable() { - NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadFileView) { (_) in } + NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadFileView) { _ in } } else { NCContentPresenter.shared.messageNotification("_info_", description: "_go_online_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorOffline) } } } - + func pushViewController(viewController: UIViewController) { if pushed { return } - + pushed = true navigationController?.pushViewController(viewController, animated: true) } - + func collectionViewSelectAll() { - selectOcId = metadatasSource.map({ $0.ocId }) + selectOcId = dataSource.metadatas.map({ $0.ocId }) navigationItem.title = NSLocalizedString("_selected_", comment: "") + " : \(selectOcId.count)" + " / \(dataSource.metadatas.count)" collectionView.reloadData() } - + @available(iOS 13.0, *) func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { - + if isEditMode { return nil } guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else { return nil } let identifier = indexPath as NSCopying @@ -1268,17 +1264,17 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { } else if cell is NCGridCell { image = (cell as! NCGridCell).imageItem.image } - + return UIContextMenuConfiguration(identifier: identifier, previewProvider: { - + return NCViewerProviderContextMenu(metadata: metadata, image: image) - - }, actionProvider: { suggestedActions in - + + }, actionProvider: { _ in + return NCFunctionCenter.shared.contextMenuConfiguration(ocId: metadata.ocId, viewController: self, enableDeleteLocal: true, enableViewInFolder: false, image: image) }) } - + @available(iOS 13.0, *) func collectionView(_ collectionView: UICollectionView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) { animator.addCompletion { @@ -1293,40 +1289,40 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { extension NCCollectionViewCommon: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - + if kind == UICollectionView.elementKindSectionHeader { - + let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderMenu", for: indexPath) as! NCSectionHeaderMenu self.header = header - + if collectionView.collectionViewLayout == gridLayout { - header.buttonSwitch.setImage(UIImage.init(named: "switchList")!.image(color: NCBrandColor.shared.gray, size: 50), for: .normal) + header.buttonSwitch.setImage(UIImage(named: "switchList")!.image(color: NCBrandColor.shared.gray, size: 50), for: .normal) } else { - header.buttonSwitch.setImage(UIImage.init(named: "switchGrid")!.image(color: NCBrandColor.shared.gray, size: 50), for: .normal) + header.buttonSwitch.setImage(UIImage(named: "switchGrid")!.image(color: NCBrandColor.shared.gray, size: 50), for: .normal) } - + header.delegate = self header.setStatusButton(count: dataSource.metadatas.count) header.setTitleSorted(datasourceTitleButton: layoutForView?.titleButtonHeader ?? "") header.viewRichWorkspaceHeightConstraint.constant = headerRichWorkspaceHeight header.setRichWorkspaceText(richWorkspaceText: richWorkspaceText) - + return header - + } else { - + let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as! NCSectionFooter - + let info = dataSource.getFilesInformation() footer.setTitleLabel(directories: info.directories, files: info.files, size: info.size ) - + return footer } } - + func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else { return } - + // Thumbnail if !metadata.directory { if FileManager().fileExists(atPath: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) { @@ -1335,7 +1331,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { NCOperationQueue.shared.downloadThumbnail(metadata: metadata, placeholder: true, cell: cell, view: collectionView) } } - + // Avatar if metadata.ownerId.count > 0, metadata.ownerId != appDelegate.userId, @@ -1345,23 +1341,23 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { NCOperationQueue.shared.downloadAvatar(user: metadata.ownerId, dispalyName: metadata.ownerDisplayName, fileName: fileName, cell: cell, view: collectionView) } } - + func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { - + } - + func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } - + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { let numberItems = dataSource.numberOfItems() emptyDataSet?.numberOfItemsInSection(numberItems, section: section) return numberItems } - + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - + guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else { if layoutForView?.layout == NCGlobal.shared.layoutList { return collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! NCListCell @@ -1369,28 +1365,28 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { return collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as! NCGridCell } } - + var tableShare: tableShare? var isShare = false var isMounted = false - + if metadataFolder != nil { isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !metadataFolder!.permissions.contains(NCGlobal.shared.permissionShared) isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !metadataFolder!.permissions.contains(NCGlobal.shared.permissionMounted) } - + if dataSource.metadataShare[metadata.ocId] != nil { tableShare = dataSource.metadataShare[metadata.ocId] } - + // // LAYOUT LIST // if layoutForView?.layout == NCGlobal.shared.layoutList { - + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! NCListCell cell.delegate = self - + cell.fileObjectId = metadata.ocId cell.fileUser = metadata.ownerId if isSearching { @@ -1404,17 +1400,17 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { cell.labelTitle.textColor = NCBrandColor.shared.label cell.labelInfo.text = CCUtility.dateDiff(metadata.date as Date) + " · " + CCUtility.transformedSize(metadata.size) cell.labelInfo.textColor = NCBrandColor.shared.systemGray - + cell.imageSelect.image = nil cell.imageStatus.image = nil cell.imageLocal.image = nil cell.imageFavorite.image = nil cell.imageShared.image = nil cell.imageMore.image = nil - + cell.imageItem.image = nil cell.imageItem.backgroundColor = nil - + // Progress var progress: Float = 0.0 var totalBytes: Int64 = 0 @@ -1429,16 +1425,16 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { cell.progressView.isHidden = true cell.progressView.progress = 0.0 } - + if metadata.directory { - + if metadata.e2eEncrypted { cell.imageItem.image = NCBrandColor.cacheImages.folderEncrypted } else if isShare { cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe - } else if (tableShare != nil && tableShare?.shareType != 3) { + } else if tableShare != nil && tableShare?.shareType != 3 { cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe - } else if (tableShare != nil && tableShare?.shareType == 3) { + } else if tableShare != nil && tableShare?.shareType == 3 { cell.imageItem.image = NCBrandColor.cacheImages.folderPublic } else if metadata.mountType == "group" { cell.imageItem.image = NCBrandColor.cacheImages.folderGroup @@ -1449,17 +1445,17 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { } else { cell.imageItem.image = NCBrandColor.cacheImages.folder } - + let lockServerUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName)! let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, lockServerUrl)) - + // Local image: offline if tableDirectory != nil && tableDirectory!.offline { cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag } - + } else { - + // image local if dataSource.metadataOffLine.contains(metadata.ocId) { cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag @@ -1467,18 +1463,18 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { cell.imageLocal.image = NCBrandColor.cacheImages.local } } - + // image Favorite if metadata.favorite { cell.imageFavorite.image = NCBrandColor.cacheImages.favorite } - + // Share image - if (isShare) { + if isShare { cell.imageShared.image = NCBrandColor.cacheImages.shared - } else if (tableShare != nil && tableShare?.shareType == 3) { + } else if tableShare != nil && tableShare?.shareType == 3 { cell.imageShared.image = NCBrandColor.cacheImages.shareByLink - } else if (tableShare != nil && tableShare?.shareType != 3) { + } else if tableShare != nil && tableShare?.shareType != 3 { cell.imageShared.image = NCBrandColor.cacheImages.shared } else { cell.imageShared.image = NCBrandColor.cacheImages.canShare @@ -1486,13 +1482,13 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { if appDelegate.account != metadata.account { cell.imageShared.image = NCBrandColor.cacheImages.shared } - + if metadata.status == NCGlobal.shared.metadataStatusInDownload || metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusInUpload || metadata.status == NCGlobal.shared.metadataStatusUploading { cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop) } else { cell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCBrandColor.cacheImages.buttonMore) } - + // Write status on Label Info switch metadata.status { case NCGlobal.shared.metadataStatusWaitDownload: @@ -1523,26 +1519,26 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { default: break } - + // Live Photo if metadata.livePhoto { cell.imageStatus.image = NCBrandColor.cacheImages.livePhoto } - + // E2EE if metadata.e2eEncrypted || isEncryptedFolder { cell.hideButtonShare(true) } else { cell.hideButtonShare(false) } - + // Remove last separator if collectionView.numberOfItems(inSection: indexPath.section) == indexPath.row + 1 { cell.separator.isHidden = true } else { cell.separator.isHidden = false } - + // Edit mode if isEditMode { cell.selectMode(true) @@ -1554,42 +1550,42 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { } else { cell.selectMode(false) } - + // Disable Share Button if appDelegate.disableSharesView { cell.hideButtonShare(true) } - + return cell } - + // // LAYOUT GRID // if layoutForView?.layout == NCGlobal.shared.layoutGrid { - + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as! NCGridCell cell.delegate = self - + cell.fileObjectId = metadata.ocId cell.fileUser = metadata.ownerId cell.labelTitle.text = metadata.fileNameView cell.labelTitle.textColor = NCBrandColor.shared.label - + cell.imageSelect.image = nil cell.imageStatus.image = nil cell.imageLocal.image = nil cell.imageFavorite.image = nil - + cell.imageItem.image = nil cell.imageItem.backgroundColor = nil - + // Progress var progress: Float = 0.0 if let progressType = appDelegate.listProgress[metadata.ocId] { progress = progressType.progress } - + if metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusUploading { cell.progressView.isHidden = false cell.progressView.progress = progress @@ -1599,14 +1595,14 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { } if metadata.directory { - + if metadata.e2eEncrypted { cell.imageItem.image = NCBrandColor.cacheImages.folderEncrypted } else if isShare { cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe - } else if (tableShare != nil && tableShare!.shareType != 3) { + } else if tableShare != nil && tableShare!.shareType != 3 { cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe - } else if (tableShare != nil && tableShare!.shareType == 3) { + } else if tableShare != nil && tableShare!.shareType == 3 { cell.imageItem.image = NCBrandColor.cacheImages.folderPublic } else if metadata.mountType == "group" { cell.imageItem.image = NCBrandColor.cacheImages.folderGroup @@ -1617,17 +1613,17 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { } else { cell.imageItem.image = NCBrandColor.cacheImages.folder } - + let lockServerUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName)! let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, lockServerUrl)) - + // Local image: offline if tableDirectory != nil && tableDirectory!.offline { cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag } - + } else { - + // image Local if dataSource.metadataOffLine.contains(metadata.ocId) { cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag @@ -1635,24 +1631,24 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { cell.imageLocal.image = NCBrandColor.cacheImages.local } } - + // image Favorite if metadata.favorite { cell.imageFavorite.image = NCBrandColor.cacheImages.favorite } - + // Transfer if metadata.status == NCGlobal.shared.metadataStatusInDownload || metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusInUpload || metadata.status == NCGlobal.shared.metadataStatusUploading { cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop) } else { cell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCBrandColor.cacheImages.buttonMore) } - + // Live Photo if metadata.livePhoto { cell.imageStatus.image = NCBrandColor.cacheImages.livePhoto } - + // Edit mode if isEditMode { cell.selectMode(true) @@ -1664,10 +1660,10 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { } else { cell.selectMode(false) } - + return cell } - + return collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as! NCGridCell } } @@ -1675,19 +1671,19 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { extension NCCollectionViewCommon: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { - + headerRichWorkspaceHeight = 0 - + if let richWorkspaceText = richWorkspaceText { let trimmed = richWorkspaceText.trimmingCharacters(in: .whitespaces) if trimmed.count > 0 && !isSearching { headerRichWorkspaceHeight = UIScreen.main.bounds.size.height / 4 } - } - + } + return CGSize(width: collectionView.frame.width, height: headerHeight + headerRichWorkspaceHeight) } - + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.width, height: footerHeight) } diff --git a/iOSClient/Main/Collection Common/NCGridCell.swift b/iOSClient/Main/Collection Common/NCGridCell.swift index 3d540587c..ced3d5e93 100644 --- a/iOSClient/Main/Collection Common/NCGridCell.swift +++ b/iOSClient/Main/Collection Common/NCGridCell.swift @@ -24,7 +24,7 @@ import UIKit class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProtocol { - + @IBOutlet weak var imageItem: UIImageView! @IBOutlet weak var imageSelect: UIImageView! @IBOutlet weak var imageStatus: UIImageView! @@ -38,7 +38,7 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto private var objectId = "" private var user = "" - var delegate: NCGridCellDelegate? + weak var delegate: NCGridCellDelegate? var namedButtonMore = "" var fileAvatarImageView: UIImageView? { @@ -67,13 +67,13 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto user = newValue ?? "" } } - + override func awakeFromNib() { super.awakeFromNib() - + imageItem.layer.cornerRadius = 6 imageItem.layer.masksToBounds = true - + imageVisualEffect.layer.cornerRadius = 6 imageVisualEffect.clipsToBounds = true imageVisualEffect.alpha = 0.5 @@ -81,46 +81,46 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto progressView.tintColor = NCBrandColor.shared.brandElement progressView.transform = CGAffineTransform(scaleX: 1.0, y: 0.5) progressView.trackTintColor = .clear - + let longPressedGesture = UILongPressGestureRecognizer(target: self, action: #selector(longPress(gestureRecognizer:))) longPressedGesture.minimumPressDuration = 0.5 longPressedGesture.delegate = self longPressedGesture.delaysTouchesBegan = true self.addGestureRecognizer(longPressedGesture) - + let longPressedGestureMore = UILongPressGestureRecognizer(target: self, action: #selector(longPressInsideMore(gestureRecognizer:))) longPressedGestureMore.minimumPressDuration = 0.5 longPressedGestureMore.delegate = self longPressedGestureMore.delaysTouchesBegan = true - buttonMore.addGestureRecognizer(longPressedGestureMore) + buttonMore.addGestureRecognizer(longPressedGestureMore) } - + override func prepareForReuse() { super.prepareForReuse() imageItem.backgroundColor = nil } - + @IBAction func touchUpInsideMore(_ sender: Any) { delegate?.tapMoreGridItem(with: objectId, namedButtonMore: namedButtonMore, image: imageItem.image, sender: sender) } - + @objc func longPressInsideMore(gestureRecognizer: UILongPressGestureRecognizer) { delegate?.longPressMoreGridItem(with: objectId, namedButtonMore: namedButtonMore, gestureRecognizer: gestureRecognizer) } - + @objc func longPress(gestureRecognizer: UILongPressGestureRecognizer) { delegate?.longPressGridItem(with: objectId, gestureRecognizer: gestureRecognizer) } - + func setButtonMore(named: String, image: UIImage) { namedButtonMore = named buttonMore.setImage(image, for: .normal) } - + func hideButtonMore(_ status: Bool) { buttonMore.isHidden = status } - + func selectMode(_ status: Bool) { if status { imageSelect.isHidden = false @@ -129,7 +129,7 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto imageVisualEffect.isHidden = true } } - + func selected(_ status: Bool) { if status { if traitCollection.userInterfaceStyle == .dark { @@ -148,7 +148,7 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto } } -protocol NCGridCellDelegate { +protocol NCGridCellDelegate: AnyObject { func tapMoreGridItem(with objectId: String, namedButtonMore: String, image: UIImage?, sender: Any) func longPressMoreGridItem(with objectId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) func longPressGridItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer) @@ -164,7 +164,7 @@ extension NCGridCellDelegate { // MARK: - Grid Layout class NCGridLayout: UICollectionViewFlowLayout { - + var heightLabelPlusButton: CGFloat = 45 var marginLeftRight: CGFloat = 6 var itemForLine: CGFloat = 3 @@ -174,36 +174,36 @@ class NCGridLayout: UICollectionViewFlowLayout { override init() { super.init() - + sectionHeadersPinToVisibleBounds = false - + minimumInteritemSpacing = 1 minimumLineSpacing = marginLeftRight - + self.scrollDirection = .vertical - self.sectionInset = UIEdgeInsets(top: 10, left: marginLeftRight, bottom: 0, right: marginLeftRight) + self.sectionInset = UIEdgeInsets(top: 10, 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 { - + if collectionView.frame.width < 400 { itemForLine = 3 } else { itemForLine = collectionView.frame.width / itemWidthDefault } - + let itemWidth: CGFloat = (collectionView.frame.width - marginLeftRight * 2 - marginLeftRight * (itemForLine - 1)) / itemForLine let itemHeight: CGFloat = itemWidth + heightLabelPlusButton - + return CGSize(width: itemWidth, height: itemHeight) } - + // Default fallback return CGSize(width: itemWidthDefault, height: itemWidthDefault) } @@ -211,7 +211,7 @@ class NCGridLayout: UICollectionViewFlowLayout { super.itemSize = newValue } } - + override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint { return proposedContentOffset } diff --git a/iOSClient/Main/Collection Common/NCListCell.swift b/iOSClient/Main/Collection Common/NCListCell.swift index 7c4eec5ea..9e0266f65 100755 --- a/iOSClient/Main/Collection Common/NCListCell.swift +++ b/iOSClient/Main/Collection Common/NCListCell.swift @@ -24,7 +24,7 @@ import UIKit class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProtocol { - + @IBOutlet weak var imageItem: UIImageView! @IBOutlet weak var imageItemLeftConstraint: NSLayoutConstraint! @IBOutlet weak var imageSelect: UIImageView! @@ -44,7 +44,7 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto private var objectId = "" private var user = "" - var delegate: NCListCellDelegate? + weak var delegate: NCListCellDelegate? var namedButtonMore = "" var fileAvatarImageView: UIImageView? { @@ -60,7 +60,7 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto objectId = newValue ?? "" } } - var filePreviewImageView : UIImageView? { + var filePreviewImageView: UIImageView? { get { return imageItem } @@ -73,13 +73,13 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto user = newValue ?? "" } } - + override func awakeFromNib() { super.awakeFromNib() - + imageItem.layer.cornerRadius = 6 imageItem.layer.masksToBounds = true - + progressView.tintColor = NCBrandColor.shared.brandElement progressView.transform = CGAffineTransform(scaleX: 1.0, y: 0.5) progressView.trackTintColor = .clear @@ -89,53 +89,53 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto longPressedGesture.delegate = self longPressedGesture.delaysTouchesBegan = true self.addGestureRecognizer(longPressedGesture) - + let longPressedGestureMore = UILongPressGestureRecognizer(target: self, action: #selector(longPressInsideMore(gestureRecognizer:))) longPressedGestureMore.minimumPressDuration = 0.5 longPressedGestureMore.delegate = self longPressedGestureMore.delaysTouchesBegan = true buttonMore.addGestureRecognizer(longPressedGestureMore) - + separator.backgroundColor = NCBrandColor.shared.separator separatorHeightConstraint.constant = 0.5 } - + override func prepareForReuse() { super.prepareForReuse() imageItem.backgroundColor = nil } - + @IBAction func touchUpInsideShare(_ sender: Any) { delegate?.tapShareListItem(with: objectId, sender: sender) } - + @IBAction func touchUpInsideMore(_ sender: Any) { delegate?.tapMoreListItem(with: objectId, namedButtonMore: namedButtonMore, image: imageItem.image, sender: sender) } - + @objc func longPressInsideMore(gestureRecognizer: UILongPressGestureRecognizer) { delegate?.longPressMoreListItem(with: objectId, namedButtonMore: namedButtonMore, gestureRecognizer: gestureRecognizer) } - + @objc func longPress(gestureRecognizer: UILongPressGestureRecognizer) { delegate?.longPressListItem(with: objectId, gestureRecognizer: gestureRecognizer) } - + func setButtonMore(named: String, image: UIImage) { namedButtonMore = named imageMore.image = image } - + func hideButtonMore(_ status: Bool) { imageMore.isHidden = status buttonMore.isHidden = status } - + func hideButtonShare(_ status: Bool) { imageShared.isHidden = status buttonShared.isHidden = status } - + func selectMode(_ status: Bool) { if status { imageItemLeftConstraint.constant = 45 @@ -146,7 +146,7 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto backgroundView = nil } } - + func selected(_ status: Bool) { if status { var blurEffect: UIVisualEffect? @@ -173,7 +173,7 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto } } -protocol NCListCellDelegate { +protocol NCListCellDelegate: AnyObject { func tapShareListItem(with objectId: String, sender: Any) func tapMoreListItem(with objectId: String, namedButtonMore: String, image: UIImage?, sender: Any) func longPressMoreListItem(with objectId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) @@ -191,34 +191,34 @@ extension NCListCellDelegate { // MARK: - List Layout class NCListLayout: UICollectionViewFlowLayout { - + var itemHeight: CGFloat = 60 - + // MARK: - View Life Cycle override init() { super.init() - + sectionHeadersPinToVisibleBounds = false - + minimumInteritemSpacing = 0 minimumLineSpacing = 1 - + self.scrollDirection = .vertical self.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) } - + 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 return CGSize(width: itemWidth, height: self.itemHeight) } - + // Default fallback return CGSize(width: 100, height: 100) } @@ -226,7 +226,7 @@ class NCListLayout: UICollectionViewFlowLayout { super.itemSize = newValue } } - + override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint { return proposedContentOffset } diff --git a/iOSClient/Main/Create cloud/NCCreateFormUploadAssets.swift b/iOSClient/Main/Create cloud/NCCreateFormUploadAssets.swift index 67bd924fc..287f3fcfc 100644 --- a/iOSClient/Main/Create cloud/NCCreateFormUploadAssets.swift +++ b/iOSClient/Main/Create cloud/NCCreateFormUploadAssets.swift @@ -24,32 +24,34 @@ import UIKit import Queuer import NCCommunication +import XLForm +import Photos -protocol createFormUploadAssetsDelegate { +protocol createFormUploadAssetsDelegate: AnyObject { func dismissFormUploadAssets() } class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate { - + var serverUrl: String = "" var titleServerUrl: String? var assets: [PHAsset] = [] var cryptated: Bool = false var session: String = "" - var delegate: createFormUploadAssetsDelegate? + weak var delegate: createFormUploadAssetsDelegate? let requestOptions = PHImageRequestOptions() var imagePreview: UIImage? - let targetSizeImagePreview = CGSize(width:100, height: 100) + let targetSizeImagePreview = CGSize(width: 100, height: 100) let appDelegate = UIApplication.shared.delegate as! AppDelegate - + var cellBackgoundColor = NCBrandColor.shared.secondarySystemGroupedBackground - + // MARK: - View Life Cycle convenience init(serverUrl: String, assets: [PHAsset], cryptated: Bool, session: String, delegate: createFormUploadAssetsDelegate?) { - + self.init() - + if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) { titleServerUrl = "/" } else { @@ -59,80 +61,79 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate { } else { titleServerUrl = (serverUrl as NSString).lastPathComponent } } else { titleServerUrl = (serverUrl as NSString).lastPathComponent } } - + self.serverUrl = serverUrl self.assets = assets self.cryptated = cryptated self.session = session self.delegate = delegate - + requestOptions.resizeMode = PHImageRequestOptionsResizeMode.exact requestOptions.deliveryMode = PHImageRequestOptionsDeliveryMode.highQualityFormat requestOptions.isSynchronous = true } - + override func viewDidLoad() { - + super.viewDidLoad() - + self.title = NSLocalizedString("_upload_photos_videos_", comment: "") - + self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(cancel)) self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_save_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(save)) - + self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none - + if assets.count == 1 && assets[0].mediaType == PHAssetMediaType.image { - PHImageManager.default().requestImage(for: assets[0], targetSize: targetSizeImagePreview, contentMode: PHImageContentMode.aspectFill, options: requestOptions, resultHandler: { (image, info) in + PHImageManager.default().requestImage(for: assets[0], targetSize: targetSizeImagePreview, contentMode: PHImageContentMode.aspectFill, options: requestOptions, resultHandler: { image, _ in self.imagePreview = image }) } - + changeTheming() - + initializeForm() reloadForm() } - - override func viewWillDisappear(_ animated: Bool) - { + + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - + self.delegate?.dismissFormUploadAssets() } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - + changeTheming() } - + // MARK: - Theming - + func changeTheming() { - + view.backgroundColor = NCBrandColor.shared.systemGroupedBackground tableView.backgroundColor = NCBrandColor.shared.systemGroupedBackground cellBackgoundColor = NCBrandColor.shared.secondarySystemGroupedBackground - + tableView.reloadData() } - - //MARK: XLForm - + + // MARK: XLForm + func initializeForm() { - - let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + + let form: XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow - - var section : XLFormSectionDescriptor - var row : XLFormRowDescriptor - + + var section: XLFormSectionDescriptor + var row: XLFormRowDescriptor + // Section: Destination Folder - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_save_path_", comment: "")) form.addFormSection(section) - + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: XLFormRowDescriptorTypeButton, title: self.titleServerUrl) row.action.formSelector = #selector(changeDestinationFolder(_:)) row.cellConfig["backgroundColor"] = cellBackgoundColor @@ -141,9 +142,9 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate { row.cellConfig["textLabel.textAlignment"] = NSTextAlignment.right.rawValue row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label - + section.addFormRow(row) - + // User folder Autoupload row = XLFormRowDescriptor(tag: "useFolderAutoUpload", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_use_folder_auto_upload_", comment: "")) row.value = 0 @@ -151,9 +152,9 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate { row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label - + section.addFormRow(row) - + // Use Sub folder row = XLFormRowDescriptor(tag: "useSubFolder", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_autoupload_create_subfolder_", comment: "")) let activeAccount = NCManageDatabase.shared.getActiveAccount() @@ -163,30 +164,30 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate { row.value = 0 } row.hidden = "$\("useFolderAutoUpload") == 0" - + row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label - + section.addFormRow(row) // Section Mode filename - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_mode_filename_", comment: "")) form.addFormSection(section) - + // Maintain the original fileName - + row = XLFormRowDescriptor(tag: "maintainOriginalFileName", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_maintain_original_filename_", comment: "")) row.value = CCUtility.getOriginalFileName(NCGlobal.shared.keyFileNameOriginal) row.cellConfig["backgroundColor"] = cellBackgoundColor row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label - + section.addFormRow(row) - + // Add File Name Type - + row = XLFormRowDescriptor(tag: "addFileNameType", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_add_filenametype_", comment: "")) row.value = CCUtility.getFileNameType(NCGlobal.shared.keyFileNameType) row.hidden = "$\("maintainOriginalFileName") == 1" @@ -194,16 +195,16 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate { row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label - + section.addFormRow(row) - + // Section: Rename File Name - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_filename_", comment: "")) form.addFormSection(section) - + row = XLFormRowDescriptor(tag: "maskFileName", rowType: XLFormRowDescriptorTypeText, title: (NSLocalizedString("_filename_", comment: ""))) - let fileNameMask : String = CCUtility.getFileNameMask(NCGlobal.shared.keyFileNameMask) + let fileNameMask: String = CCUtility.getFileNameMask(NCGlobal.shared.keyFileNameMask) if fileNameMask.count > 0 { row.value = fileNameMask } @@ -212,15 +213,15 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate { row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label - + row.cellConfig["textField.textAlignment"] = NSTextAlignment.right.rawValue row.cellConfig["textField.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textField.textColor"] = NCBrandColor.shared.label section.addFormRow(row) - + // Section: Preview File Name - + row = XLFormRowDescriptor(tag: "previewFileName", rowType: XLFormRowDescriptorTypeTextView, title: "") row.height = 180 row.disabled = true @@ -231,114 +232,109 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate { row.cellConfig["textView.textColor"] = NCBrandColor.shared.label section.addFormRow(row) - + self.form = form } - + override func formRowDescriptorValueHasChanged(_ formRow: XLFormRowDescriptor!, oldValue: Any!, newValue: Any!) { - + super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue) - + if formRow.tag == "useFolderAutoUpload" { - + if (formRow.value! as AnyObject).boolValue == true { - - let buttonDestinationFolder : XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! + + let buttonDestinationFolder: XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! buttonDestinationFolder.hidden = true - - } else{ - - let buttonDestinationFolder : XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! + + } else { + + let buttonDestinationFolder: XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! buttonDestinationFolder.hidden = false } - } - else if formRow.tag == "useSubFolder" { - + } else if formRow.tag == "useSubFolder" { + if (formRow.value! as AnyObject).boolValue == true { - - } else{ - + + } else { + } - } - else if formRow.tag == "maintainOriginalFileName" { + } else if formRow.tag == "maintainOriginalFileName" { CCUtility.setOriginalFileName((formRow.value! as AnyObject).boolValue, key: NCGlobal.shared.keyFileNameOriginal) self.reloadForm() - } - else if formRow.tag == "addFileNameType" { + } else if formRow.tag == "addFileNameType" { CCUtility.setFileNameType((formRow.value! as AnyObject).boolValue, key: NCGlobal.shared.keyFileNameType) self.reloadForm() - } - else if formRow.tag == "maskFileName" { - + } else if formRow.tag == "maskFileName" { + let fileName = formRow.value as? String - + self.form.delegate = nil - + if let fileName = fileName { formRow.value = CCUtility.removeForbiddenCharactersServer(fileName) } - + self.form.delegate = self - - let previewFileName : XLFormRowDescriptor = self.form.formRow(withTag: "previewFileName")! + + let previewFileName: XLFormRowDescriptor = self.form.formRow(withTag: "previewFileName")! previewFileName.value = self.previewFileName(valueRename: formRow.value as? String) - + // reload cell if fileName != nil { - + if newValue as! String != formRow.value as! String { - + self.reloadFormRow(formRow) - + NCContentPresenter.shared.messageNotification("_info_", description: "_forbidden_characters_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorCharactersForbidden) } } - + self.reloadFormRow(previewFileName) } } - + func reloadForm() { - + self.form.delegate = nil - - let buttonDestinationFolder : XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! + + let buttonDestinationFolder: XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! buttonDestinationFolder.title = self.titleServerUrl - - let maskFileName : XLFormRowDescriptor = self.form.formRow(withTag: "maskFileName")! - let previewFileName : XLFormRowDescriptor = self.form.formRow(withTag: "previewFileName")! + + let maskFileName: XLFormRowDescriptor = self.form.formRow(withTag: "maskFileName")! + let previewFileName: XLFormRowDescriptor = self.form.formRow(withTag: "previewFileName")! previewFileName.value = self.previewFileName(valueRename: maskFileName.value as? String) - + self.tableView.reloadData() self.form.delegate = self } - + // MARK: - Action - + func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) { - + if serverUrl != nil { - + self.serverUrl = serverUrl! - + if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) { self.titleServerUrl = "/" } else { - if let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account - , self.serverUrl)) { + if let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, self.serverUrl)) { if let metadata = NCManageDatabase.shared.getMetadataFromOcId(tableDirectory.ocId) { titleServerUrl = metadata.fileNameView } else { titleServerUrl = (self.serverUrl as NSString).lastPathComponent } - } else { titleServerUrl = (self.serverUrl as NSString).lastPathComponent } + } else { titleServerUrl = (self.serverUrl as NSString).lastPathComponent } } - + // Update - let row : XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! + let row: XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! row.title = self.titleServerUrl self.updateFormRow(row) } } - + /* func save() { @@ -358,11 +354,11 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate { }) } */ - + @objc func save() { - + DispatchQueue.global().async { - + let useFolderPhotoRow: XLFormRowDescriptor = self.form.formRow(withTag: "useFolderAutoUpload")! let useSubFolderRow: XLFormRowDescriptor = self.form.formRow(withTag: "useSubFolder")! var useSubFolder: Bool = false @@ -374,7 +370,7 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate { self.serverUrl = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: self.appDelegate.urlBase, account: self.appDelegate.account) useSubFolder = (useSubFolderRow.value! as AnyObject).boolValue } - + let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: self.appDelegate.urlBase, account: self.appDelegate.account) if autoUploadPath == self.serverUrl { if !NCNetworking.shared.createFolder(assets: self.assets, selector: NCGlobal.shared.selectorUploadFile, useSubFolder: useSubFolder, account: self.appDelegate.account, urlBase: self.appDelegate.urlBase) { @@ -384,59 +380,59 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate { } for asset in self.assets { - + var serverUrl = self.serverUrl var livePhoto: Bool = false let fileName = CCUtility.createFileName(asset.value(forKey: "filename") as? String, fileDate: asset.creationDate, fileType: asset.mediaType, keyFileName: NCGlobal.shared.keyFileNameMask, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: false)! let assetDate = asset.creationDate ?? Date() let dateFormatter = DateFormatter() - + // Detect LivePhoto Upload if asset.mediaSubtypes.contains(.photoLive) && CCUtility.getLivePhoto() { livePhoto = true - } - + } + // Create serverUrl if use sub folder if useSubFolder { - + dateFormatter.dateFormat = "yyyy" let yearString = dateFormatter.string(from: assetDate) - + dateFormatter.dateFormat = "MM" let monthString = dateFormatter.string(from: assetDate) - + serverUrl = autoUploadPath + "/" + yearString + "/" + monthString } - + // Check if is in upload let isRecordInSessions = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@ AND session != ''", self.appDelegate.account, serverUrl, fileName), sorted: "fileName", ascending: false) if isRecordInSessions.count > 0 { continue } - + let metadataForUpload = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: fileName, fileNameView: fileName, ocId: NSUUID().uuidString, serverUrl: serverUrl, urlBase: self.appDelegate.urlBase, url: "", contentType: "", livePhoto: livePhoto) - + metadataForUpload.assetLocalIdentifier = asset.localIdentifier metadataForUpload.session = self.session metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile metadataForUpload.size = NCUtilityFileSystem.shared.getFileSize(asset: asset) metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload - + if livePhoto { - + let fileNameMove = (fileName as NSString).deletingPathExtension + ".mov" let ocId = NSUUID().uuidString let filePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameMove)! - + let semaphore = Semaphore() - CCUtility.extractLivePhotoAsset(asset, filePath: filePath) { (url) in + CCUtility.extractLivePhotoAsset(asset, filePath: filePath) { url in if let url = url { let fileSize = NCUtilityFileSystem.shared.getFileSize(filePath: url.path) - let metadataMOVForUpload = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: fileNameMove, fileNameView: fileNameMove, ocId:ocId, serverUrl: serverUrl, urlBase: self.appDelegate.urlBase, url: "", contentType: "", livePhoto: livePhoto) + let metadataMOVForUpload = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: fileNameMove, fileNameView: fileNameMove, ocId: ocId, serverUrl: serverUrl, urlBase: self.appDelegate.urlBase, url: "", contentType: "", livePhoto: livePhoto) metadataForUpload.livePhoto = true metadataMOVForUpload.livePhoto = true - + metadataMOVForUpload.session = self.session metadataMOVForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile metadataMOVForUpload.size = fileSize @@ -449,94 +445,94 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate { } semaphore.wait() } - + if NCManageDatabase.shared.getMetadataConflict(account: self.appDelegate.account, serverUrl: serverUrl, fileName: fileName) != nil { metadatasUploadInConflict.append(metadataForUpload) } else { metadatasNOConflict.append(metadataForUpload) } } - + // Verify if file(s) exists if metadatasUploadInConflict.count > 0 { - + DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) { - if let conflict = UIStoryboard.init(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict { - + if let conflict = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict { + conflict.serverUrl = self.serverUrl conflict.metadatasNOConflict = metadatasNOConflict conflict.metadatasMOV = metadatasMOV conflict.metadatasUploadInConflict = metadatasUploadInConflict - + self.appDelegate.window?.rootViewController?.present(conflict, animated: true, completion: nil) } } - + } else { - + self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: metadatasNOConflict) - self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: metadatasMOV) + self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: metadatasMOV) } - + DispatchQueue.main.async {self.dismiss(animated: true, completion: nil) } } } - + @objc func cancel() { - + self.dismiss(animated: true, completion: nil) } - + // MARK: - Utility - - func previewFileName(valueRename : String?) -> String { - + + func previewFileName(valueRename: String?) -> String { + var returnString: String = "" let asset = assets[0] - - if (CCUtility.getOriginalFileName(NCGlobal.shared.keyFileNameOriginal)) { - + + if CCUtility.getOriginalFileName(NCGlobal.shared.keyFileNameOriginal) { + return (NSLocalizedString("_filename_", comment: "") + ": " + (asset.value(forKey: "filename") as! String)) - + } else if let valueRename = valueRename { - + let valueRenameTrimming = valueRename.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) - + if valueRenameTrimming.count > 0 { - + self.form.delegate = nil CCUtility.setFileNameMask(valueRename, key: NCGlobal.shared.keyFileNameMask) self.form.delegate = self - + returnString = CCUtility.createFileName(asset.value(forKey: "filename") as! String?, fileDate: asset.creationDate, fileType: asset.mediaType, keyFileName: NCGlobal.shared.keyFileNameMask, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: false) - + } else { - + CCUtility.setFileNameMask("", key: NCGlobal.shared.keyFileNameMask) returnString = CCUtility.createFileName(asset.value(forKey: "filename") as! String?, fileDate: asset.creationDate, fileType: asset.mediaType, keyFileName: nil, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: false) } - + } else { - + CCUtility.setFileNameMask("", key: NCGlobal.shared.keyFileNameMask) returnString = CCUtility.createFileName(asset.value(forKey: "filename") as! String?, fileDate: asset.creationDate, fileType: asset.mediaType, keyFileName: nil, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: false) } - + return String(format: NSLocalizedString("_preview_filename_", comment: ""), "MM, MMM, DD, YY, YYYY, HH, hh, mm, ss, ampm") + ":" + "\n\n" + returnString } - + @objc func changeDestinationFolder(_ sender: XLFormRowDescriptor) { - + self.deselectFormRow(sender) - + let storyboard = UIStoryboard(name: "NCSelect", bundle: nil) let navigationController = storyboard.instantiateInitialViewController() as! UINavigationController let viewController = navigationController.topViewController as! NCSelect - + viewController.delegate = self viewController.typeOfCommandView = .selectCreateFolder viewController.includeDirectoryE2EEncryption = true - + self.present(navigationController, animated: true, completion: nil) } } diff --git a/iOSClient/Main/Create cloud/NCCreateFormUploadConflict.swift b/iOSClient/Main/Create cloud/NCCreateFormUploadConflict.swift index 83b86db4f..b354b3b80 100644 --- a/iOSClient/Main/Create cloud/NCCreateFormUploadConflict.swift +++ b/iOSClient/Main/Create cloud/NCCreateFormUploadConflict.swift @@ -49,7 +49,7 @@ extension NCCreateFormUploadConflictDelegate { @IBOutlet weak var viewButton: UIView! @IBOutlet weak var buttonCancel: UIButton! @IBOutlet weak var buttonContinue: UIButton! - + @objc var metadatasNOConflict: [tableMetadata] @objc var metadatasUploadInConflict: [tableMetadata] @objc var metadatasMOV: [tableMetadata] @@ -57,7 +57,7 @@ extension NCCreateFormUploadConflictDelegate { @objc weak var delegate: NCCreateFormUploadConflictDelegate? @objc var alwaysNewFileNameNumber: Bool = false @objc var textLabelDetailNewFile: String? - + let appDelegate = UIApplication.shared.delegate as! AppDelegate var metadatasConflictNewFiles: [String] = [] var metadatasConflictAlreadyExistingFiles: [String] = [] @@ -72,17 +72,17 @@ extension NCCreateFormUploadConflictDelegate { self.metadatasUploadInConflict = [] super.init(coder: aDecoder) } - + override func viewDidLoad() { super.viewDidLoad() - + tableView.dataSource = self tableView.delegate = self tableView.allowsSelection = false tableView.tableFooterView = UIView() - - tableView.register(UINib.init(nibName: "NCCreateFormUploadConflictCell", bundle: nil), forCellReuseIdentifier: "Cell") - + + tableView.register(UINib(nibName: "NCCreateFormUploadConflictCell", bundle: nil), forCellReuseIdentifier: "Cell") + if metadatasUploadInConflict.count == 1 { labelTitle.text = String(metadatasUploadInConflict.count) + " " + NSLocalizedString("_file_conflict_num_", comment: "") labelSubTitle.text = NSLocalizedString("_file_conflict_desc_", comment: "") @@ -94,14 +94,14 @@ extension NCCreateFormUploadConflictDelegate { labelNewFiles.text = NSLocalizedString("_file_conflict_new_", comment: "") labelAlreadyExistingFiles.text = NSLocalizedString("_file_conflict_exists_", comment: "") } - + switchNewFiles.isOn = false switchAlreadyExistingFiles.isOn = false - + buttonCancel.layer.cornerRadius = 20 buttonCancel.layer.masksToBounds = true buttonCancel.setTitle(NSLocalizedString("_cancel_", comment: ""), for: .normal) - + buttonContinue.layer.cornerRadius = 20 buttonContinue.layer.masksToBounds = true buttonContinue.setTitle(NSLocalizedString("_continue_", comment: ""), for: .normal) @@ -113,34 +113,34 @@ extension NCCreateFormUploadConflictDelegate { blurView.frame = view.bounds blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(blurView) - + changeTheming() DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { self.conflictDialog(fileCount: self.metadatasUploadInConflict.count) } } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - + changeTheming() } - + // MARK: - Theming - - func changeTheming(){ - + + func changeTheming() { + view.backgroundColor = NCBrandColor.shared.systemGroupedBackground tableView.backgroundColor = NCBrandColor.shared.systemGroupedBackground viewSwitch.backgroundColor = NCBrandColor.shared.systemGroupedBackground viewButton.backgroundColor = NCBrandColor.shared.systemGroupedBackground } - + // MARK: - ConflictDialog - + func conflictDialog(fileCount: Int) { - + var tile = "" var titleReplace = "" var titleKeep = "" @@ -154,41 +154,41 @@ extension NCCreateFormUploadConflictDelegate { titleReplace = NSLocalizedString("_replace_all_action_title_", comment: "") titleKeep = NSLocalizedString("_keep_both_for_all_action_title_", comment: "") } - + let conflictAlert = UIAlertController(title: tile, message: "", preferredStyle: .alert) // REPLACE conflictAlert.addAction(UIAlertAction(title: titleReplace, style: .default, handler: { action in - + for metadata in self.metadatasUploadInConflict { self.metadatasNOConflict.append(metadata) } - + self.buttonContinueTouch(action) })) - + // KEEP BOTH conflictAlert.addAction(UIAlertAction(title: titleKeep, style: .default, handler: { action in - + for metadata in self.metadatasUploadInConflict { self.metadatasConflictNewFiles.append(metadata.ocId) self.metadatasConflictAlreadyExistingFiles.append(metadata.ocId) } - + self.buttonContinueTouch(action) })) - - conflictAlert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_keep_existing_action_title_", comment: ""), style: .cancel, handler: { (_) in + + conflictAlert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_keep_existing_action_title_", comment: ""), style: .cancel, handler: { _ in self.dismiss(animated: true, completion: nil) })) - - conflictAlert.addAction(UIAlertAction(title: NSLocalizedString("_more_action_title_", comment: ""), style: .default, handler: { (_) in + + conflictAlert.addAction(UIAlertAction(title: NSLocalizedString("_more_action_title_", comment: ""), style: .default, handler: { _ in self.blurView.removeFromSuperview() })) - + self.present(conflictAlert, animated: true, completion: nil) } - + // MARK: - Action @IBAction func valueChangedSwitchNewFiles(_ sender: Any) { @@ -199,56 +199,56 @@ extension NCCreateFormUploadConflictDelegate { metadatasConflictNewFiles.append(metadata.ocId) } } - + verifySwith() } - + @IBAction func valueChangedSwitchAlreadyExistingFiles(_ sender: Any) { metadatasConflictAlreadyExistingFiles.removeAll() - + if switchAlreadyExistingFiles.isOn { for metadata in metadatasUploadInConflict { metadatasConflictAlreadyExistingFiles.append(metadata.ocId) } } - + verifySwith() } - + func verifySwith() { - + if alwaysNewFileNameNumber && switchNewFiles.isOn { metadatasConflictNewFiles.removeAll() metadatasConflictAlreadyExistingFiles.removeAll() - + for metadata in metadatasUploadInConflict { metadatasConflictNewFiles.append(metadata.ocId) } for metadata in metadatasUploadInConflict { metadatasConflictAlreadyExistingFiles.append(metadata.ocId) } - + switchAlreadyExistingFiles.isOn = true NCContentPresenter.shared.messageNotification("_info_", description: "_file_not_rewite_doc_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorInternalError) } - + tableView.reloadData() canContinue() } - + @IBAction func buttonCancelTouch(_ sender: Any) { - + delegate?.dismissCreateFormUploadConflict(metadatas: nil) dismiss(animated: true) } - + @IBAction func buttonContinueTouch(_ sender: Any) { - + for metadata in metadatasUploadInConflict { - + // keep both if metadatasConflictNewFiles.contains(metadata.ocId) && metadatasConflictAlreadyExistingFiles.contains(metadata.ocId) { - + let fileNameMOV = (metadata.fileNameView as NSString).deletingPathExtension + ".mov" var fileName = metadata.fileNameView let fileNameExtension = (fileName as NSString).pathExtension.lowercased() @@ -258,44 +258,44 @@ extension NCCreateFormUploadConflictDelegate { } let oldPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView) let newFileName = NCUtilityFileSystem.shared.createFileName(fileName, serverUrl: metadata.serverUrl, account: metadata.account) - + metadata.ocId = UUID().uuidString metadata.fileName = newFileName metadata.fileNameView = newFileName - + // This is not an asset - [file] if metadata.assetLocalIdentifier == "" { let newPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: newFileName) CCUtility.moveFile(atPath: oldPath, toPath: newPath) } - + metadatasNOConflict.append(metadata) - + // MOV (Live Photo) if let metadataMOV = self.metadatasMOV.first(where: { $0.fileName == fileNameMOV }) { - + let oldPath = CCUtility.getDirectoryProviderStorageOcId(metadataMOV.ocId, fileNameView: metadataMOV.fileNameView) let newFileNameMOV = (newFileName as NSString).deletingPathExtension + ".mov" - + metadataMOV.ocId = UUID().uuidString metadataMOV.fileName = newFileNameMOV metadataMOV.fileNameView = newFileNameMOV - + let newPath = CCUtility.getDirectoryProviderStorageOcId(metadataMOV.ocId, fileNameView: newFileNameMOV) CCUtility.moveFile(atPath: oldPath, toPath: newPath) } - + // overwrite } else if metadatasConflictNewFiles.contains(metadata.ocId) { - + metadatasNOConflict.append(metadata) - + // remove (MOV) } else if metadatasConflictAlreadyExistingFiles.contains(metadata.ocId) { - + let fileNameMOV = (metadata.fileNameView as NSString).deletingPathExtension + ".mov" var index = 0 - + for metadataMOV in metadatasMOV { if metadataMOV.fileNameView == fileNameMOV { metadatasMOV.remove(at: index) @@ -303,20 +303,20 @@ extension NCCreateFormUploadConflictDelegate { } index += 1 } - + } else { print("error") } } - + metadatasNOConflict.append(contentsOf: metadatasMOV) - + if delegate != nil { delegate?.dismissCreateFormUploadConflict(metadatas: metadatasNOConflict) } else { appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: metadatasNOConflict) } - + dismiss(animated: true) } } @@ -324,7 +324,7 @@ extension NCCreateFormUploadConflictDelegate { // MARK: - UITableViewDelegate extension NCCreateFormUploadConflict: UITableViewDelegate { - + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { if metadatasUploadInConflict.count == 1 { return 250 @@ -337,21 +337,21 @@ extension NCCreateFormUploadConflict: UITableViewDelegate { // MARK: - UITableViewDataSource extension NCCreateFormUploadConflict: UITableViewDataSource { - + func numberOfSections(in tableView: UITableView) -> Int { return 1 } - + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return metadatasUploadInConflict.count } - + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - + if let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? NCCreateFormUploadConflictCell { - + cell.backgroundColor = tableView.backgroundColor - + let metadataNewFile = metadatasUploadInConflict[indexPath.row] cell.ocId = metadataNewFile.ocId @@ -361,50 +361,50 @@ extension NCCreateFormUploadConflict: UITableViewDataSource { cell.labelDetailNewFile.text = "" // -----> Already Existing File - + guard let metadataAlreadyExists = NCManageDatabase.shared.getMetadataConflict(account: metadataNewFile.account, serverUrl: metadataNewFile.serverUrl, fileName: metadataNewFile.fileNameView) else { return UITableViewCell() } if FileManager().fileExists(atPath: CCUtility.getDirectoryProviderStorageIconOcId(metadataAlreadyExists.ocId, etag: metadataAlreadyExists.etag)) { cell.imageAlreadyExistingFile.image = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(metadataAlreadyExists.ocId, etag: metadataAlreadyExists.etag)) } else if FileManager().fileExists(atPath: CCUtility.getDirectoryProviderStorageOcId(metadataAlreadyExists.ocId, fileNameView: metadataAlreadyExists.fileNameView)) && metadataAlreadyExists.contentType == "application/pdf" { - + let url = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadataAlreadyExists.ocId, fileNameView: metadataAlreadyExists.fileNameView)) if let image = NCUtility.shared.pdfThumbnail(url: url) { cell.imageAlreadyExistingFile.image = image } else { - cell.imageAlreadyExistingFile.image = UIImage.init(named: metadataAlreadyExists.iconName) + cell.imageAlreadyExistingFile.image = UIImage(named: metadataAlreadyExists.iconName) } - + } else { if metadataAlreadyExists.iconName.count > 0 { - cell.imageAlreadyExistingFile.image = UIImage.init(named: metadataAlreadyExists.iconName) + cell.imageAlreadyExistingFile.image = UIImage(named: metadataAlreadyExists.iconName) } else { - cell.imageAlreadyExistingFile.image = UIImage.init(named: "file") + cell.imageAlreadyExistingFile.image = UIImage(named: "file") } } cell.labelDetailAlreadyExistingFile.text = CCUtility.dateDiff(metadataAlreadyExists.date as Date) + "\n" + CCUtility.transformedSize(metadataAlreadyExists.size) - + if metadatasConflictAlreadyExistingFiles.contains(metadataNewFile.ocId) { cell.switchAlreadyExistingFile.isOn = true } else { cell.switchAlreadyExistingFile.isOn = false } - + // -----> New File - + if metadataNewFile.iconName.count > 0 { - cell.imageNewFile.image = UIImage.init(named: metadataNewFile.iconName) + cell.imageNewFile.image = UIImage(named: metadataNewFile.iconName) } else { - cell.imageNewFile.image = UIImage.init(named: "file") + cell.imageNewFile.image = UIImage(named: "file") } let filePathNewFile = CCUtility.getDirectoryProviderStorageOcId(metadataNewFile.ocId, fileNameView: metadataNewFile.fileNameView)! if metadataNewFile.assetLocalIdentifier.count > 0 { - + let result = PHAsset.fetchAssets(withLocalIdentifiers: [metadataNewFile.assetLocalIdentifier], options: nil) let date = result.firstObject!.modificationDate let mediaType = result.firstObject!.mediaType - + if let fileNamePath = self.fileNamesPath[metadataNewFile.fileNameView] { - + do { if mediaType == PHAssetMediaType.image { let data = try Data(contentsOf: URL(fileURLWithPath: fileNamePath)) @@ -416,26 +416,26 @@ extension NCCreateFormUploadConflict: UITableViewDataSource { cell.imageNewFile.image = image } } - + let fileDictionary = try FileManager.default.attributesOfItem(atPath: fileNamePath) let fileSize = fileDictionary[FileAttributeKey.size] as! Int64 - + cell.labelDetailNewFile.text = CCUtility.dateDiff(date) + "\n" + CCUtility.transformedSize(fileSize) - + } catch { print("Error: \(error)") } - + } else { - - CCUtility.extractImageVideoFromAssetLocalIdentifier(forUpload: metadataNewFile, notification: false) { (metadataNew, fileNamePath) in - + + CCUtility.extractImageVideoFromAssetLocalIdentifier(forUpload: metadataNewFile, notification: false) { metadataNew, fileNamePath in + if metadataNew != nil { self.fileNamesPath[metadataNewFile.fileNameView] = fileNamePath! - + do { - + let fileDictionary = try FileManager.default.attributesOfItem(atPath: fileNamePath!) let fileSize = fileDictionary[FileAttributeKey.size] as! Int64 - + if mediaType == PHAssetMediaType.image { let data = try Data(contentsOf: URL(fileURLWithPath: fileNamePath!)) if let image = UIImage(data: data) { @@ -446,16 +446,16 @@ extension NCCreateFormUploadConflict: UITableViewDataSource { cell.imageNewFile.image = image } } - + cell.labelDetailNewFile.text = CCUtility.dateDiff(date) + "\n" + CCUtility.transformedSize(fileSize) - + } catch { print("Error: \(error)") } } } } - + } else if FileManager().fileExists(atPath: filePathNewFile) { - + do { if metadataNewFile.classFile == NCCommunicationCommon.typeClassFile.image.rawValue { let data = try Data(contentsOf: URL(fileURLWithPath: filePathNewFile)) @@ -463,39 +463,39 @@ extension NCCreateFormUploadConflict: UITableViewDataSource { cell.imageNewFile.image = image } } - + let fileDictionary = try FileManager.default.attributesOfItem(atPath: filePathNewFile) let fileSize = fileDictionary[FileAttributeKey.size] as! Int64 - + cell.labelDetailNewFile.text = CCUtility.dateDiff(metadataNewFile.date as Date) + "\n" + CCUtility.transformedSize(fileSize) - + } catch { print("Error: \(error)") } - + } else { - + CCUtility.dateDiff(metadataNewFile.date as Date) } - + if metadatasConflictNewFiles.contains(metadataNewFile.ocId) { cell.switchNewFile.isOn = true } else { cell.switchNewFile.isOn = false } - + // Hide switch if only one if metadatasUploadInConflict.count == 1 { cell.switchAlreadyExistingFile.isHidden = true cell.switchNewFile.isHidden = true } - + // text label new file if textLabelDetailNewFile != nil { cell.labelDetailNewFile.text = textLabelDetailNewFile! + "\n" } - + return cell } - + return UITableViewCell() } } @@ -503,7 +503,7 @@ extension NCCreateFormUploadConflict: UITableViewDataSource { // MARK: - NCCreateFormUploadConflictCellDelegate extension NCCreateFormUploadConflict: NCCreateFormUploadConflictCellDelegate { - + func valueChangedSwitchNewFile(with ocId: String, isOn: Bool) { if let index = metadatasConflictNewFiles.firstIndex(of: ocId) { metadatasConflictNewFiles.remove(at: index) @@ -516,10 +516,10 @@ extension NCCreateFormUploadConflict: NCCreateFormUploadConflictCellDelegate { } else { switchNewFiles.isOn = false } - + canContinue() } - + func valueChangedSwitchAlreadyExistingFile(with ocId: String, isOn: Bool) { if let index = metadatasConflictAlreadyExistingFiles.firstIndex(of: ocId) { metadatasConflictAlreadyExistingFiles.remove(at: index) @@ -532,19 +532,19 @@ extension NCCreateFormUploadConflict: NCCreateFormUploadConflictCellDelegate { } else { switchAlreadyExistingFiles.isOn = false } - + canContinue() } - + func canContinue() { var result = true - + for metadata in metadatasUploadInConflict { if !metadatasConflictNewFiles.contains(metadata.ocId) && !metadatasConflictAlreadyExistingFiles.contains(metadata.ocId) { result = false } } - + if result { buttonContinue.isEnabled = true buttonContinue.setTitleColor(NCBrandColor.shared.label, for: .normal) @@ -554,4 +554,3 @@ extension NCCreateFormUploadConflict: NCCreateFormUploadConflictCellDelegate { } } } - diff --git a/iOSClient/Main/Create cloud/NCCreateFormUploadConflictCell.swift b/iOSClient/Main/Create cloud/NCCreateFormUploadConflictCell.swift index 287444761..1b87eddd8 100644 --- a/iOSClient/Main/Create cloud/NCCreateFormUploadConflictCell.swift +++ b/iOSClient/Main/Create cloud/NCCreateFormUploadConflictCell.swift @@ -24,7 +24,7 @@ import UIKit class NCCreateFormUploadConflictCell: UITableViewCell { - + @IBOutlet weak var labelFileName: UILabel! @IBOutlet weak var imageAlreadyExistingFile: UIImageView! @@ -35,21 +35,21 @@ class NCCreateFormUploadConflictCell: UITableViewCell { @IBOutlet weak var switchAlreadyExistingFile: UISwitch! @IBOutlet weak var switchNewFile: UISwitch! - - var delegate: NCCreateFormUploadConflictCellDelegate? + + weak var delegate: NCCreateFormUploadConflictCellDelegate? var ocId: String = "" @IBAction func valueChangedSwitchNewFile(_ sender: Any) { delegate?.valueChangedSwitchNewFile(with: ocId, isOn: switchNewFile.isOn) } - + @IBAction func valueChangedSwitchAlreadyExistingFile(_ sender: Any) { delegate?.valueChangedSwitchAlreadyExistingFile(with: ocId, isOn: switchAlreadyExistingFile.isOn) } } -protocol NCCreateFormUploadConflictCellDelegate { - +protocol NCCreateFormUploadConflictCellDelegate: AnyObject { + func valueChangedSwitchNewFile(with ocId: String, isOn: Bool) func valueChangedSwitchAlreadyExistingFile(with ocId: String, isOn: Bool) diff --git a/iOSClient/Main/Create cloud/NCCreateFormUploadDocuments.swift b/iOSClient/Main/Create cloud/NCCreateFormUploadDocuments.swift index 872629de0..069314edd 100644 --- a/iOSClient/Main/Create cloud/NCCreateFormUploadDocuments.swift +++ b/iOSClient/Main/Create cloud/NCCreateFormUploadDocuments.swift @@ -23,6 +23,7 @@ import UIKit import NCCommunication +import XLForm // MARK: - @@ -31,7 +32,7 @@ import NCCommunication @IBOutlet weak var indicator: UIActivityIndicatorView! @IBOutlet weak var collectionView: UICollectionView! @IBOutlet weak var collectionViewHeigth: NSLayoutConstraint! - + let appDelegate = UIApplication.shared.delegate as! AppDelegate var editorId = "" @@ -45,108 +46,108 @@ import NCCommunication var titleForm = "" var listOfTemplate: [NCCommunicationEditorTemplates] = [] var selectTemplate: NCCommunicationEditorTemplates? - + // Layout let numItems = 2 let sectionInsets: CGFloat = 10 let highLabelName: CGFloat = 20 - + // MARK: - View Life Cycle - + override func viewDidLoad() { super.viewDidLoad() - + if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) { fileNameFolder = "/" } else { fileNameFolder = (serverUrl as NSString).lastPathComponent } - + self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none - let cancelButton : UIBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(cancel)) - let saveButton : UIBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_save_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(save)) - + let cancelButton: UIBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(cancel)) + let saveButton: UIBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_save_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(save)) + self.navigationItem.leftBarButtonItem = cancelButton self.navigationItem.rightBarButtonItem = saveButton self.navigationItem.rightBarButtonItem?.isEnabled = false - + // title self.title = titleForm - + changeTheming() - + initializeForm() - + // load the templates available getTemplate() } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - + changeTheming() } - + // MARK: - Theming - + func changeTheming() { - + view.backgroundColor = NCBrandColor.shared.systemGroupedBackground collectionView.backgroundColor = NCBrandColor.shared.systemGroupedBackground tableView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground - + tableView.reloadData() collectionView.reloadData() } - + // MARK: - Tableview (XLForm) func initializeForm() { - - let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + + let form: XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow - - var section : XLFormSectionDescriptor - var row : XLFormRowDescriptor - + + var section: XLFormSectionDescriptor + var row: XLFormRowDescriptor + // Section: Destination Folder - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_save_path_", comment: "").uppercased()) form.addFormSection(section) - + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: XLFormRowDescriptorTypeButton, title: fileNameFolder) row.action.formSelector = #selector(changeDestinationFolder(_:)) row.value = fileNameFolder row.cellConfig["backgroundColor"] = tableView.backgroundColor row.cellConfig["imageView.image"] = UIImage(named: "folder")!.image(color: NCBrandColor.shared.brandElement, size: 25) - + row.cellConfig["textLabel.textAlignment"] = NSTextAlignment.right.rawValue row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label section.addFormRow(row) - + // Section: File Name - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_filename_", comment: "").uppercased()) form.addFormSection(section) - + row = XLFormRowDescriptor(tag: "fileName", rowType: XLFormRowDescriptorTypeText, title: NSLocalizedString("_filename_", comment: "")) row.value = fileName row.cellConfig["backgroundColor"] = tableView.backgroundColor - + row.cellConfig["textField.textAlignment"] = NSTextAlignment.right.rawValue row.cellConfig["textField.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textField.textColor"] = NCBrandColor.shared.label - + row.cellConfig["textLabel.textAlignment"] = NSTextAlignment.right.rawValue row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label - + section.addFormRow(row) - + self.form = form } @@ -158,27 +159,27 @@ import NCCommunication } // MARK: - CollectionView - + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return listOfTemplate.count } - + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let itemWidth: CGFloat = (collectionView.frame.width - (sectionInsets * 4) - CGFloat(numItems)) / CGFloat(numItems) let itemHeight: CGFloat = itemWidth + highLabelName - + collectionViewHeigth.constant = itemHeight + sectionInsets - + return CGSize(width: itemWidth, height: itemHeight) } - + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) - + let template = listOfTemplate[indexPath.row] - + // image let imagePreview = cell.viewWithTag(100) as! UIImageView if template.preview != "" { @@ -192,12 +193,12 @@ import NCCommunication getImageFromTemplate(name: template.name, preview: template.preview, indexPath: indexPath) } } - + // name let name = cell.viewWithTag(200) as! UILabel name.text = template.name name.textColor = NCBrandColor.shared.secondarySystemGroupedBackground - + // select let imageSelect = cell.viewWithTag(300) as! UIImageView if selectTemplate != nil && selectTemplate?.name == template.name { @@ -208,165 +209,164 @@ import NCCommunication cell.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground imageSelect.isHidden = true } - + return cell } - + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - + let template = listOfTemplate[indexPath.row] - + selectTemplate = template fileNameExtension = template.ext - + collectionView.reloadData() } - + // MARK: - Action - + func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) { - + guard let serverUrl = serverUrl else { return } - + self.serverUrl = serverUrl if serverUrl == NCUtilityFileSystem.shared.getHomeServer( account: appDelegate.account) { fileNameFolder = "/" } else { fileNameFolder = (serverUrl as NSString).lastPathComponent } - - let buttonDestinationFolder : XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! + + let buttonDestinationFolder: XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! buttonDestinationFolder.title = fileNameFolder - + self.tableView.reloadData() } - + @objc func changeDestinationFolder(_ sender: XLFormRowDescriptor) { - + self.deselectFormRow(sender) - + let storyboard = UIStoryboard(name: "NCSelect", bundle: nil) let navigationController = storyboard.instantiateInitialViewController() as! UINavigationController let viewController = navigationController.topViewController as! NCSelect - + viewController.delegate = self viewController.typeOfCommandView = .selectCreateFolder self.present(navigationController, animated: true, completion: nil) } - + @objc func save() { - + guard let selectTemplate = self.selectTemplate else { return } templateIdentifier = selectTemplate.identifier - let rowFileName : XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! + let rowFileName: XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! guard var fileNameForm = rowFileName.value else { return } - + if fileNameForm as! String == "" { return } else { - + let result = NCCommunicationCommon.shared.getInternalType(fileName: fileNameForm as! String, mimeType: "", directory: false) if NCUtility.shared.isDirectEditing(account: appDelegate.account, contentType: result.mimeType).count == 0 { fileNameForm = (fileNameForm as! NSString).deletingPathExtension + "." + fileNameExtension } - + if NCManageDatabase.shared.getMetadataConflict(account: appDelegate.account, serverUrl: serverUrl, fileName: String(describing: fileNameForm)) != nil { - + let metadataForUpload = NCManageDatabase.shared.createMetadata(account: appDelegate.account, user: appDelegate.user, userId: appDelegate.userId, fileName: String(describing: fileNameForm), fileNameView: String(describing: fileNameForm), ocId: "", serverUrl: serverUrl, urlBase: appDelegate.urlBase, url: "", contentType: "", livePhoto: false) - + guard let conflictViewController = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict else { return } conflictViewController.textLabelDetailNewFile = NSLocalizedString("_now_", comment: "") conflictViewController.alwaysNewFileNameNumber = true conflictViewController.serverUrl = serverUrl conflictViewController.metadatasUploadInConflict = [metadataForUpload] conflictViewController.delegate = self - + self.present(conflictViewController, animated: true, completion: nil) - + } else { - + let fileNamePath = CCUtility.returnFileNamePath(fromFileName: String(describing: fileNameForm), serverUrl: serverUrl, urlBase: appDelegate.urlBase, account: appDelegate.account)! createDocument(fileNamePath: fileNamePath, fileName: String(describing: fileNameForm)) } } } - + func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) { - + if metadatas == nil || metadatas?.count == 0 { - + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { self.cancel() } - + } else { - + let fileName = metadatas![0].fileName let fileNamePath = CCUtility.returnFileNamePath(fromFileName: fileName, serverUrl: serverUrl, urlBase: appDelegate.urlBase, account: appDelegate.account)! - + createDocument(fileNamePath: fileNamePath, fileName: fileName) } } - + func createDocument(fileNamePath: String, fileName: String) { - + if self.editorId == NCGlobal.shared.editorText || self.editorId == NCGlobal.shared.editorOnlyoffice { - + var customUserAgent: String? - + if self.editorId == NCGlobal.shared.editorOnlyoffice { customUserAgent = NCUtility.shared.getCustomUserAgentOnlyOffice() } - - NCCommunication.shared.NCTextCreateFile(fileNamePath: fileNamePath, editorId: editorId, creatorId: creatorId, templateId: templateIdentifier, customUserAgent: customUserAgent) { (account, url, errorCode, errorMessage) in - + + NCCommunication.shared.NCTextCreateFile(fileNamePath: fileNamePath, editorId: editorId, creatorId: creatorId, templateId: templateIdentifier, customUserAgent: customUserAgent) { account, url, errorCode, errorMessage in + if errorCode == 0 && account == self.appDelegate.account { - + if url != nil && url!.count > 0 { let results = NCCommunicationCommon.shared.getInternalType(fileName: fileName, mimeType: "", directory: false) - + self.dismiss(animated: true, completion: { let metadata = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: fileName, fileNameView: fileName, ocId: CCUtility.createRandomString(12), serverUrl: self.serverUrl, urlBase: self.appDelegate.urlBase, url: url ?? "", contentType: results.mimeType, livePhoto: false) - + if let viewController = self.appDelegate.activeViewController { NCViewer.shared.view(viewController: viewController, metadata: metadata, metadatas: [metadata], imageIcon: nil) } }) } - + } else if errorCode != 0 { - NCContentPresenter.shared.messageNotification("_error_", description: errorMessage, delay: NCGlobal.shared.dismissAfterSecond, type:NCContentPresenter.messageType.error, errorCode: errorCode) + NCContentPresenter.shared.messageNotification("_error_", description: errorMessage, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } else { print("[LOG] It has been changed user during networking process, error.") } } } - + if self.editorId == NCGlobal.shared.editorCollabora { - - NCCommunication.shared.createRichdocuments(path: fileNamePath, templateId: templateIdentifier) { (account, url, errorCode, errorDescription) in - + + NCCommunication.shared.createRichdocuments(path: fileNamePath, templateId: templateIdentifier) { account, url, errorCode, errorDescription in + if errorCode == 0 && account == self.appDelegate.account && url != nil { - + self.dismiss(animated: true, completion: { - + let createFileName = (fileName as NSString).deletingPathExtension + "." + self.fileNameExtension let metadata = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: createFileName, fileNameView: createFileName, ocId: CCUtility.createRandomString(12), serverUrl: self.serverUrl, urlBase: self.appDelegate.urlBase, url: url!, contentType: "", livePhoto: false) - + if let viewController = self.appDelegate.activeViewController { NCViewer.shared.view(viewController: viewController, metadata: metadata, metadatas: [metadata], imageIcon: nil) } }) - - + } else if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } else { @@ -375,42 +375,42 @@ import NCCommunication } } } - + @objc func cancel() { - + self.dismiss(animated: true, completion: nil) } - + // MARK: NC API - + func getTemplate() { - + indicator.color = NCBrandColor.shared.brandElement indicator.startAnimating() - + if self.editorId == NCGlobal.shared.editorText || self.editorId == NCGlobal.shared.editorOnlyoffice { - + var customUserAgent: String? if self.editorId == NCGlobal.shared.editorOnlyoffice { customUserAgent = NCUtility.shared.getCustomUserAgentOnlyOffice() } - NCCommunication.shared.NCTextGetListOfTemplates(customUserAgent: customUserAgent) { (account, templates, errorCode, errorMessage) in - + NCCommunication.shared.NCTextGetListOfTemplates(customUserAgent: customUserAgent) { account, templates, errorCode, _ in + self.indicator.stopAnimating() - + if errorCode == 0 && account == self.appDelegate.account { - + for template in templates { - + let temp = NCCommunicationEditorTemplates() - + temp.identifier = template.identifier temp.ext = template.ext temp.name = template.name temp.preview = template.preview - + self.listOfTemplate.append(temp) - + // default: template empty if temp.preview == "" { self.selectTemplate = temp @@ -419,11 +419,11 @@ import NCCommunication } } } - + if self.listOfTemplate.count == 0 { - + let temp = NCCommunicationEditorTemplates() - + temp.identifier = "" if self.editorId == NCGlobal.shared.editorText { temp.ext = "md" @@ -436,40 +436,40 @@ import NCCommunication } temp.name = "Empty" temp.preview = "" - + self.listOfTemplate.append(temp) - + self.selectTemplate = temp self.fileNameExtension = temp.ext self.navigationItem.rightBarButtonItem?.isEnabled = true } - + self.collectionView.reloadData() } - + } - - if self.editorId == NCGlobal.shared.editorCollabora { - - NCCommunication.shared.getTemplatesRichdocuments(typeTemplate: typeTemplate) { (account, templates, errorCode, errorDescription) in - + + if self.editorId == NCGlobal.shared.editorCollabora { + + NCCommunication.shared.getTemplatesRichdocuments(typeTemplate: typeTemplate) { account, templates, errorCode, _ in + self.indicator.stopAnimating() if errorCode == 0 && account == self.appDelegate.account { - + for template in templates! { - + let temp = NCCommunicationEditorTemplates() - + temp.identifier = "\(template.templateId)" temp.delete = template.delete temp.ext = template.ext temp.name = template.name temp.preview = template.preview temp.type = template.type - + self.listOfTemplate.append(temp) - + // default: template empty if temp.preview == "" { self.selectTemplate = temp @@ -478,11 +478,11 @@ import NCCommunication } } } - + if self.listOfTemplate.count == 0 { - + let temp = NCCommunicationEditorTemplates() - + temp.identifier = "" if self.typeTemplate == NCGlobal.shared.templateDocument { temp.ext = "docx" @@ -493,31 +493,31 @@ import NCCommunication } temp.name = "Empty" temp.preview = "" - + self.listOfTemplate.append(temp) - + self.selectTemplate = temp self.fileNameExtension = temp.ext self.navigationItem.rightBarButtonItem?.isEnabled = true } - + self.collectionView.reloadData() } } } - + func getImageFromTemplate(name: String, preview: String, indexPath: IndexPath) { - + let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + name + ".png" - NCCommunication.shared.download(serverUrlFileName: preview, fileNameLocalPath: fileNameLocalPath, requestHandler: { (_) in - - }, taskHandler: { (_) in - - }, progressHandler: { (_) in - - }) { (account, etag, date, lenght, allHeaderFields, error, errorCode, errorDescription) in - + NCCommunication.shared.download(serverUrlFileName: preview, fileNameLocalPath: fileNameLocalPath, requestHandler: { _ in + + }, taskHandler: { _ in + + }, progressHandler: { _ in + + }) { account, _, _, _, _, _, errorCode, _ in + if errorCode == 0 && account == self.appDelegate.account { self.collectionView.reloadItems(at: [indexPath]) } else if errorCode != 0 { diff --git a/iOSClient/Main/Create cloud/NCCreateFormUploadScanDocument.swift b/iOSClient/Main/Create cloud/NCCreateFormUploadScanDocument.swift index d54fa2f6b..42954b67f 100644 --- a/iOSClient/Main/Create cloud/NCCreateFormUploadScanDocument.swift +++ b/iOSClient/Main/Create cloud/NCCreateFormUploadScanDocument.swift @@ -25,10 +25,12 @@ import UIKit import NCCommunication import Vision import VisionKit +import Photos +import XLForm @available(iOS 13.0, *) class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NCCreateFormUploadConflictDelegate { - + let appDelegate = UIApplication.shared.delegate as! AppDelegate enum typeQuality { @@ -37,167 +39,167 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC case high } var quality: typeQuality = .medium - + var serverUrl = "" var titleServerUrl = "" var arrayImages: [UIImage] = [] var fileName = CCUtility.createFileNameDate("scan", extension: "pdf") var password: String = "" var fileType = "PDF" - + var cellBackgoundColor = NCBrandColor.shared.secondarySystemGroupedBackground - + // MARK: - View Life Cycle convenience init(serverUrl: String, arrayImages: [UIImage]) { - + self.init() - + if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) { titleServerUrl = "/" } else { titleServerUrl = (serverUrl as NSString).lastPathComponent } - + self.serverUrl = serverUrl self.arrayImages = arrayImages } - + override func viewDidLoad() { - + super.viewDidLoad() - + self.title = NSLocalizedString("_save_settings_", comment: "") - - let saveButton : UIBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_save_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(save)) + + let saveButton: UIBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_save_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(save)) self.navigationItem.rightBarButtonItem = saveButton - + NCUtility.shared.colorNavigationController(navigationController, backgroundColor: NCBrandColor.shared.systemBackground, titleColor: NCBrandColor.shared.label, tintColor: nil, withoutShadow: false) - + tableView.separatorStyle = UITableViewCell.SeparatorStyle.none // self.tableView.sectionHeaderHeight = 10 // self.tableView.sectionFooterHeight = 10 - + // let row : XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! // let rowCell = row.cell(forForm: self) // rowCell.becomeFirstResponder() - + changeTheming() - + initializeForm() - + let value = CCUtility.getTextRecognitionStatus() - SetTextRecognition(newValue: value) + setTextRecognition(newValue: value) } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - + changeTheming() } - + // MARK: - Theming - + @objc func changeTheming() { - + view.backgroundColor = NCBrandColor.shared.systemGroupedBackground tableView.backgroundColor = NCBrandColor.shared.systemGroupedBackground cellBackgoundColor = NCBrandColor.shared.secondarySystemGroupedBackground - + tableView.reloadData() } - - //MARK: XLForm - + + // MARK: XLForm + func initializeForm() { - - let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + + let form: XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow - - var section : XLFormSectionDescriptor - var row : XLFormRowDescriptor - + + var section: XLFormSectionDescriptor + var row: XLFormRowDescriptor + // Section: Destination Folder - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_save_path_", comment: "")) form.addFormSection(section) - + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: XLFormRowDescriptorTypeButton, title: self.titleServerUrl) row.action.formSelector = #selector(changeDestinationFolder(_:)) row.cellConfig["backgroundColor"] = cellBackgoundColor row.cellConfig["imageView.image"] = UIImage(named: "folder")!.image(color: NCBrandColor.shared.brandElement, size: 25) - + row.cellConfig["textLabel.textAlignment"] = NSTextAlignment.right.rawValue row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label section.addFormRow(row) - + // Section: Quality - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_quality_image_title_", comment: "")) form.addFormSection(section) - + row = XLFormRowDescriptor(tag: "compressionQuality", rowType: XLFormRowDescriptorTypeSlider) row.value = 0.5 row.title = NSLocalizedString("_quality_medium_", comment: "") row.cellConfig["backgroundColor"] = cellBackgoundColor row.cellConfig["slider.minimumTrackTintColor"] = NCBrandColor.shared.brandElement - + row.cellConfig["slider.maximumValue"] = 1 row.cellConfig["slider.minimumValue"] = 0 row.cellConfig["steps"] = 2 - + row.cellConfig["textLabel.textAlignment"] = NSTextAlignment.center.rawValue row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label - + section.addFormRow(row) - + // Section: Password - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_pdf_password_", comment: "")) form.addFormSection(section) - + row = XLFormRowDescriptor(tag: "password", rowType: XLFormRowDescriptorTypePassword, title: NSLocalizedString("_password_", comment: "")) row.cellConfig["backgroundColor"] = cellBackgoundColor row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label - + row.cellConfig["textField.textAlignment"] = NSTextAlignment.right.rawValue row.cellConfig["textField.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textField.textColor"] = NCBrandColor.shared.label - + section.addFormRow(row) - + // Section: Text recognition - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_text_recognition_", comment: "")) form.addFormSection(section) - + row = XLFormRowDescriptor(tag: "textRecognition", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_text_recognition_", comment: "")) row.value = 0 row.cellConfig["backgroundColor"] = cellBackgoundColor - row.cellConfig["imageView.image"] = UIImage(named: "textRecognition")!.image(color: NCBrandColor.shared.brandElement, size: 25) - + row.cellConfig["imageView.image"] = UIImage(named: "textRecognition")!.image(color: NCBrandColor.shared.brandElement, size: 25) + row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label section.addFormRow(row) - + // Section: File - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_file_creation_", comment: "")) form.addFormSection(section) - + row = XLFormRowDescriptor(tag: "filetype", rowType: XLFormRowDescriptorTypeSelectorSegmentedControl, title: NSLocalizedString("_file_type_", comment: "")) if arrayImages.count == 1 { - row.selectorOptions = ["PDF","JPG"] + row.selectorOptions = ["PDF", "JPG"] } else { row.selectorOptions = ["PDF"] } @@ -207,10 +209,9 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC row.cellConfig["tintColor"] = NCBrandColor.shared.brandElement row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label - + section.addFormRow(row) - - + row = XLFormRowDescriptor(tag: "fileName", rowType: XLFormRowDescriptorTypeText, title: NSLocalizedString("_filename_", comment: "")) row.value = self.fileName row.cellConfig["backgroundColor"] = cellBackgoundColor @@ -223,47 +224,47 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC row.cellConfig["textField.textColor"] = NCBrandColor.shared.label section.addFormRow(row) - + self.form = form } - + override func formRowDescriptorValueHasChanged(_ formRow: XLFormRowDescriptor!, oldValue: Any!, newValue: Any!) { - + super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue) - + if formRow.tag == "textRecognition" { - - self.SetTextRecognition(newValue: newValue as! Int) + + self.setTextRecognition(newValue: newValue as! Int) } - + if formRow.tag == "fileName" { - + self.form.delegate = nil - + let fileNameNew = newValue as? String - + if fileNameNew != nil { self.fileName = CCUtility.removeForbiddenCharactersServer(fileNameNew) } else { self.fileName = "" } - + formRow.value = self.fileName - + self.updateFormRow(formRow) - + self.form.delegate = self } - + if formRow.tag == "compressionQuality" { - + self.form.delegate = nil - - //let row : XLFormRowDescriptor = self.form.formRow(withTag: "descriptionQuality")! + + // let row : XLFormRowDescriptor = self.form.formRow(withTag: "descriptionQuality")! let newQuality = newValue as? NSNumber let compressionQuality = (newQuality?.doubleValue)! - - if compressionQuality >= 0.0 && compressionQuality <= 0.3 { + + if compressionQuality >= 0.0 && compressionQuality <= 0.3 { formRow.title = NSLocalizedString("_quality_low_", comment: "") quality = typeQuality.low } else if compressionQuality > 0.3 && compressionQuality <= 0.6 { @@ -273,12 +274,12 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC formRow.title = NSLocalizedString("_quality_high_", comment: "") quality = typeQuality.high } - + self.updateFormRow(formRow) - + self.form.delegate = self } - + if formRow.tag == "password" { let stringPassword = newValue as? String if stringPassword != nil { @@ -287,17 +288,17 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC password = "" } } - + if formRow.tag == "filetype" { fileType = newValue as! String - - let rowFileName : XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! - let rowPassword : XLFormRowDescriptor = self.form.formRow(withTag: "password")! + + let rowFileName: XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! + let rowPassword: XLFormRowDescriptor = self.form.formRow(withTag: "password")! rowFileName.value = createFileName(rowFileName.value as? String) - + self.updateFormRow(rowFileName) - + // rowPassword if fileType == "JPG" || fileType == "TXT" { rowPassword.value = "" @@ -306,13 +307,13 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC } else { rowPassword.disabled = false } - + self.updateFormRow(rowPassword) } } - - func SetTextRecognition(newValue: Int) { - + + func setTextRecognition(newValue: Int) { + let rowCompressionQuality: XLFormRowDescriptor = self.form.formRow(withTag: "compressionQuality")! let rowFileTape: XLFormRowDescriptor = self.form.formRow(withTag: "filetype")! let rowFileName: XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! @@ -320,16 +321,16 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC let rowTextRecognition: XLFormRowDescriptor = self.form.formRow(withTag: "textRecognition")! self.form.delegate = nil - + if newValue == 1 { - rowFileTape.selectorOptions = ["PDF","TXT"] + rowFileTape.selectorOptions = ["PDF", "TXT"] rowFileTape.value = "PDF" fileType = "PDF" rowPassword.disabled = true rowCompressionQuality.disabled = false } else { if arrayImages.count == 1 { - rowFileTape.selectorOptions = ["PDF","JPG"] + rowFileTape.selectorOptions = ["PDF", "JPG"] } else { rowFileTape.selectorOptions = ["PDF"] } @@ -338,136 +339,136 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC rowPassword.disabled = false rowCompressionQuality.disabled = false } - + rowFileName.value = createFileName(rowFileName.value as? String) self.updateFormRow(rowFileName) self.tableView.reloadData() - + CCUtility.setTextRecognitionStatus(newValue) rowTextRecognition.value = newValue - + self.form.delegate = self } - + func createFileName(_ fileName: String?) -> String { - + var name: String = "" var newFileName: String = "" - + if fileName == nil || fileName == "" { name = CCUtility.createFileNameDate("scan", extension: "pdf") ?? "scan.pdf" } else { name = fileName! } - + let ext = (name as NSString).pathExtension.uppercased() - - if (ext == "") { + + if ext == "" { newFileName = name + "." + fileType.lowercased() } else { newFileName = (name as NSString).deletingPathExtension + "." + fileType.lowercased() } - + return newFileName } - + // MARK: - Action - + func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) { - + if serverUrl != nil { - + CCUtility.setDirectoryScanDocuments(serverUrl!) self.serverUrl = serverUrl! - + if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) { self.titleServerUrl = "/" } else { self.titleServerUrl = (serverUrl! as NSString).lastPathComponent } - + // Update - let row : XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! + let row: XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! row.title = self.titleServerUrl self.updateFormRow(row) } } - + @objc func save() { - - let rowFileName : XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! + + let rowFileName: XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! guard let name = rowFileName.value else { return } if name as! String == "" { return } - + let ext = (name as! NSString).pathExtension.uppercased() var fileNameSave = "" - - if (ext == "") { + + if ext == "" { fileNameSave = name as! String + "." + fileType.lowercased() } else { fileNameSave = (name as! NSString).deletingPathExtension + "." + fileType.lowercased() } - - //Create metadata for upload + + // Create metadata for upload let metadataForUpload = NCManageDatabase.shared.createMetadata(account: appDelegate.account, user: appDelegate.user, userId: appDelegate.userId, fileName: fileNameSave, fileNameView: fileNameSave, ocId: UUID().uuidString, serverUrl: serverUrl, urlBase: appDelegate.urlBase, url: "", contentType: "", livePhoto: false) - + metadataForUpload.session = NCNetworking.shared.sessionIdentifierBackground metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload - + if NCManageDatabase.shared.getMetadataConflict(account: appDelegate.account, serverUrl: serverUrl, fileName: fileNameSave) != nil { - + guard let conflictViewController = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict else { return } conflictViewController.textLabelDetailNewFile = NSLocalizedString("_now_", comment: "") conflictViewController.serverUrl = serverUrl conflictViewController.metadatasUploadInConflict = [metadataForUpload] conflictViewController.delegate = self - + self.present(conflictViewController, animated: true, completion: nil) - + } else { - + NCUtility.shared.startActivityIndicator(backgroundView: self.view, blurEffect: true) - + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { self.dismissAndUpload(metadataForUpload) } } } - + func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) { - + if metadatas != nil && metadatas!.count > 0 { - + NCUtility.shared.startActivityIndicator(backgroundView: self.view, blurEffect: true) - + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { self.dismissAndUpload(metadatas![0]) } } } - + func dismissAndUpload(_ metadata: tableMetadata) { - + guard let fileNameGenerateExport = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView) else { NCUtility.shared.stopActivityIndicator() NCContentPresenter.shared.messageNotification("_error_", description: "_error_creation_file_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorCreationFile) return } - + // Text Recognition TXT if fileType == "TXT" && self.form.formRow(withTag: "textRecognition")!.value as! Int == 1 { - + var textFile = "" for image in self.arrayImages { - + let requestHandler = VNImageRequestHandler(cgImage: image.cgImage!, options: [:]) - - let request = VNRecognizeTextRequest { (request, error) in + + let request = VNRecognizeTextRequest { request, _ in guard let observations = request.results as? [VNRecognizedTextObservation] else { NCUtility.shared.stopActivityIndicator() return @@ -476,32 +477,32 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC guard let textLine = observation.topCandidates(1).first else { continue } - + textFile += textLine.string textFile += "\n" } } - + request.recognitionLevel = .accurate request.usesLanguageCorrection = true try? requestHandler.perform([request]) } - + do { - try textFile.write(to: NSURL(fileURLWithPath: fileNameGenerateExport) as URL , atomically: true, encoding: .utf8) + try textFile.write(to: NSURL(fileURLWithPath: fileNameGenerateExport) as URL, atomically: true, encoding: .utf8) } catch { NCUtility.shared.stopActivityIndicator() NCContentPresenter.shared.messageNotification("_error_", description: "_error_creation_file_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorCreationFile) return } } - + if fileType == "PDF" { - + let pdfData = NSMutableData() - + if password.count > 0 { - let info: [AnyHashable: Any] = [kCGPDFContextUserPassword as String : password, kCGPDFContextOwnerPassword as String : password] + let info: [AnyHashable: Any] = [kCGPDFContextUserPassword as String: password, kCGPDFContextOwnerPassword as String: password] UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, info) } else { UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil) @@ -510,21 +511,21 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC #if targetEnvironment(simulator) fontColor = UIColor.red #endif - + for var image in self.arrayImages { - + image = changeCompressionImage(image) - + let bounds = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height) - + if self.form.formRow(withTag: "textRecognition")!.value as! Int == 1 { - + UIGraphicsBeginPDFPageWithInfo(bounds, nil) image.draw(in: bounds) let requestHandler = VNImageRequestHandler(cgImage: image.cgImage!, options: [:]) - - let request = VNRecognizeTextRequest { (request, error) in + + let request = VNRecognizeTextRequest { request, _ in guard let observations = request.results as? [VNRecognizedTextObservation] else { NCUtility.shared.stopActivityIndicator() return @@ -533,7 +534,7 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC guard let textLine = observation.topCandidates(1).first else { continue } - + var t: CGAffineTransform = CGAffineTransform.identity t = t.scaledBy(x: image.size.width, y: -image.size.height) t = t.translatedBy(x: 0, y: -1) @@ -542,41 +543,41 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC let font = UIFont.systemFont(ofSize: rect.size.height, weight: .regular) let attributes = self.bestFittingFont(for: text, in: rect, fontDescriptor: font.fontDescriptor, fontColor: fontColor) - + text.draw(with: rect, options: .usesLineFragmentOrigin, attributes: attributes, context: nil) } } - + request.recognitionLevel = .accurate request.usesLanguageCorrection = true try? requestHandler.perform([request]) - + } else { - + UIGraphicsBeginPDFPageWithInfo(bounds, nil) image.draw(in: bounds) } } - - UIGraphicsEndPDFContext(); - + + UIGraphicsEndPDFContext() + do { try pdfData.write(toFile: fileNameGenerateExport, options: .atomic) } catch { print("error catched") } } - + if fileType == "JPG" { - + let image = changeCompressionImage(self.arrayImages[0]) - + guard let data = image.jpegData(compressionQuality: CGFloat(0.5)) else { NCUtility.shared.stopActivityIndicator() NCContentPresenter.shared.messageNotification("_error_", description: "_error_creation_file_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorCreationFile) return } - + do { try data.write(to: NSURL.fileURL(withPath: fileNameGenerateExport), options: .atomic) } catch { @@ -585,18 +586,18 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC return } } - + NCUtility.shared.stopActivityIndicator() appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: [metadata]) // Request delete all image scanned let alertController = UIAlertController(title: "", message: NSLocalizedString("_delete_all_scanned_images_", comment: ""), preferredStyle: .alert) - - let actionYes = UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (action:UIAlertAction) in - + + let actionYes = UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (_: UIAlertAction) in + let path = CCUtility.getDirectoryScan()! - + do { let filePaths = try FileManager.default.contentsOfDirectory(atPath: path) for filePath in filePaths { @@ -605,41 +606,41 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC } catch let error as NSError { print("Error: \(error.debugDescription)") } - + self.dismiss(animated: true, completion: nil) } - - let actionNo = UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (action:UIAlertAction) in + + let actionNo = UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (_: UIAlertAction) in self.dismiss(animated: true, completion: nil) } - + alertController.addAction(actionYes) alertController.addAction(actionNo) - self.present(alertController, animated: true, completion:nil) + self.present(alertController, animated: true, completion: nil) } - + func cancel() { - + self.dismiss(animated: true, completion: nil) } - + @objc func changeDestinationFolder(_ sender: XLFormRowDescriptor) { - + self.deselectFormRow(sender) - + let storyboard = UIStoryboard(name: "NCSelect", bundle: nil) let navigationController = storyboard.instantiateInitialViewController() as! UINavigationController let viewController = navigationController.topViewController as! NCSelect - + viewController.delegate = self viewController.typeOfCommandView = .selectCreateFolder viewController.includeDirectoryE2EEncryption = true - + self.present(navigationController, animated: true, completion: nil) } - + func changeCompressionImage(_ image: UIImage) -> UIImage { - + var compressionQuality: CGFloat = 0.5 var baseHeight: Float = 595.2 // A4 var baseWidth: Float = 841.8 // A4 @@ -658,7 +659,7 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC baseWidth *= 4 compressionQuality = 0.9 } - + var newHeight = Float(image.size.height) var newWidth = Float(image.size.width) var imgRatio: Float = newWidth / newHeight @@ -669,18 +670,16 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC imgRatio = baseHeight / newHeight newWidth = imgRatio * newWidth newHeight = baseHeight - } - else if imgRatio > baseRatio { + } else if imgRatio > baseRatio { imgRatio = baseWidth / newWidth newHeight = imgRatio * newHeight newWidth = baseWidth - } - else { + } else { newHeight = baseHeight newWidth = baseWidth } } - + let rect = CGRect(x: 0.0, y: 0.0, width: CGFloat(newWidth), height: CGFloat(newHeight)) UIGraphicsBeginImageContext(rect.size) image.draw(in: rect) @@ -689,34 +688,34 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC UIGraphicsEndImageContext() return UIImage(data: imageData!) ?? image } - + func bestFittingFont(for text: String, in bounds: CGRect, fontDescriptor: UIFontDescriptor, fontColor: UIColor) -> [NSAttributedString.Key: Any] { - + let constrainingDimension = min(bounds.width, bounds.height) let properBounds = CGRect(origin: .zero, size: bounds.size) var attributes: [NSAttributedString.Key: Any] = [:] - + let infiniteBounds = CGSize(width: CGFloat.infinity, height: CGFloat.infinity) var bestFontSize: CGFloat = constrainingDimension - + // Search font (H) for fontSize in stride(from: bestFontSize, through: 0, by: -1) { let newFont = UIFont(descriptor: fontDescriptor, size: fontSize) attributes[.font] = newFont - + let currentFrame = text.boundingRect(with: infiniteBounds, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: attributes, context: nil) - + if properBounds.contains(currentFrame) { bestFontSize = fontSize break } } - + // Search kern (W) let font = UIFont(descriptor: fontDescriptor, size: bestFontSize) - attributes = [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: fontColor, NSAttributedString.Key.kern: 0] as [NSAttributedString.Key : Any] + attributes = [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: fontColor, NSAttributedString.Key.kern: 0] as [NSAttributedString.Key: Any] for kern in stride(from: 0, through: 100, by: 0.1) { - let attributesTmp = [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: fontColor, NSAttributedString.Key.kern: kern] as [NSAttributedString.Key : Any] + let attributesTmp = [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: fontColor, NSAttributedString.Key.kern: kern] as [NSAttributedString.Key: Any] let size = text.size(withAttributes: attributesTmp).width if size <= bounds.width { attributes = attributesTmp @@ -724,36 +723,35 @@ class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NC break } } - + return attributes } } @available(iOS 13.0, *) -class NCCreateScanDocument : NSObject, VNDocumentCameraViewControllerDelegate { +class NCCreateScanDocument: NSObject, VNDocumentCameraViewControllerDelegate { @objc static let shared: NCCreateScanDocument = { let instance = NCCreateScanDocument() return instance }() - - let appDelegate = UIApplication.shared.delegate as! AppDelegate + var viewController: UIViewController? - + func openScannerDocument(viewController: UIViewController) { - + self.viewController = viewController - + guard VNDocumentCameraViewController.isSupported else { return } - + let controller = VNDocumentCameraViewController() controller.delegate = self self.viewController?.present(controller, animated: true) } - + func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) { - + for pageNumber in 0..<scan.pageCount { let fileName = CCUtility.createFileName("scan.png", fileDate: Date(), fileType: PHAssetMediaType.image, keyFileName: NCGlobal.shared.keyFileNameMask, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: true)! let fileNamePath = CCUtility.getDirectoryScan() + "/" + fileName @@ -762,22 +760,21 @@ class NCCreateScanDocument : NSObject, VNDocumentCameraViewControllerDelegate { try image.pngData()?.write(to: NSURL.fileURL(withPath: fileNamePath)) } catch { } } - + controller.dismiss(animated: true) { if self.viewController is DragDropViewController { (self.viewController as! DragDropViewController).loadImage() } else { let storyboard = UIStoryboard(name: "Scan", bundle: nil) let controller = storyboard.instantiateInitialViewController()! - + controller.modalPresentationStyle = UIModalPresentationStyle.pageSheet self.viewController?.present(controller, animated: true, completion: nil) } } } - + func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) { controller.dismiss(animated: true, completion: nil) } } - diff --git a/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift b/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift index 1f53fca6e..a262b4dc8 100644 --- a/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift +++ b/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift @@ -25,7 +25,7 @@ import UIKit import NCCommunication class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAudioPlayerDelegate, NCCreateFormUploadConflictDelegate { - + @IBOutlet weak var buttonPlayStop: UIButton! @IBOutlet weak var labelTimer: UILabel! @IBOutlet weak var labelDuration: UILabel! @@ -39,7 +39,7 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud private var fileNamePath = "" private var durationPlayer: TimeInterval = 0 private var counterSecondPlayer: TimeInterval = 0 - + private var audioPlayer: AVAudioPlayer! private var timer = Timer() @@ -49,74 +49,74 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud override func viewDidLoad() { super.viewDidLoad() - + self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(cancel)) self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_save_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(save)) - + self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none // title self.title = NSLocalizedString("_voice_memo_title_", comment: "") - + // Button Play Stop buttonPlayStop.setImage(UIImage(named: "audioPlay")!.image(color: NCBrandColor.shared.gray, size: 100), for: .normal) - + // Progress view progressView.progress = 0 progressView.progressTintColor = .green progressView.trackTintColor = UIColor(red: 247.0/255.0, green: 247.0/255.0, blue: 247.0/255.0, alpha: 1.0) - + labelTimer.textColor = NCBrandColor.shared.label labelDuration.textColor = NCBrandColor.shared.label - + changeTheming() - + initializeForm() } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + updateTimerUI() } - + override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) - + if audioPlayer.isPlaying { stop() } } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - + changeTheming() } - + // MARK: - Theming - + @objc func changeTheming() { - + view.backgroundColor = NCBrandColor.shared.systemGroupedBackground tableView.backgroundColor = NCBrandColor.shared.systemGroupedBackground cellBackgoundColor = NCBrandColor.shared.secondarySystemGroupedBackground - + tableView.reloadData() } - + public func setup(serverUrl: String, fileNamePath: String, fileName: String) { - + if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) { titleServerUrl = "/" } else { titleServerUrl = (serverUrl as NSString).lastPathComponent } - + self.fileName = fileName self.serverUrl = serverUrl self.fileNamePath = fileNamePath - + // player do { try audioPlayer = AVAudioPlayer(contentsOf: URL(fileURLWithPath: fileNamePath)) @@ -127,39 +127,39 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud buttonPlayStop.isEnabled = false } } - - //MARK: XLForm + + // MARK: XLForm func initializeForm() { - - let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + + let form: XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow - - var section : XLFormSectionDescriptor - var row : XLFormRowDescriptor - + + var section: XLFormSectionDescriptor + var row: XLFormRowDescriptor + // Section: Destination Folder - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_save_path_", comment: "").uppercased()) form.addFormSection(section) - + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: XLFormRowDescriptorTypeButton, title: self.titleServerUrl) row.action.formSelector = #selector(changeDestinationFolder(_:)) row.cellConfig["backgroundColor"] = cellBackgoundColor row.cellConfig["imageView.image"] = UIImage(named: "folder")!.image(color: NCBrandColor.shared.brandElement, size: 25) - + row.cellConfig["textLabel.textAlignment"] = NSTextAlignment.right.rawValue row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label - + section.addFormRow(row) - + // Section: File Name - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_filename_", comment: "").uppercased()) form.addFormSection(section) - + row = XLFormRowDescriptor(tag: "fileName", rowType: XLFormRowDescriptorTypeText, title: NSLocalizedString("_filename_", comment: "")) row.value = self.fileName row.cellConfig["backgroundColor"] = cellBackgoundColor @@ -170,32 +170,32 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud row.cellConfig["textField.textAlignment"] = NSTextAlignment.right.rawValue row.cellConfig["textField.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textField.textColor"] = NCBrandColor.shared.label - + section.addFormRow(row) self.form = form } - + override func formRowDescriptorValueHasChanged(_ formRow: XLFormRowDescriptor!, oldValue: Any!, newValue: Any!) { - + super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue) - + if formRow.tag == "fileName" { - + self.form.delegate = nil - + if let fileNameNew = formRow.value { self.fileName = CCUtility.removeForbiddenCharactersServer(fileNameNew as? String) } - + formRow.value = self.fileName self.updateFormRow(formRow) - + self.form.delegate = self } } - - //MARK: TableViewDelegate + + // MARK: TableViewDelegate override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { let header: UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView @@ -203,161 +203,160 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud header.textLabel?.textColor = .gray header.tintColor = cellBackgoundColor } - + // MARK: - Action - + func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) { - + if serverUrl != nil { - + self.serverUrl = serverUrl! - + if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) { self.titleServerUrl = "/" } else { self.titleServerUrl = (serverUrl! as NSString).lastPathComponent } - + // Update - let row : XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! + let row: XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! row.title = self.titleServerUrl self.updateFormRow(row) } } - + @objc func save() { - - let rowFileName : XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! + + let rowFileName: XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! guard let name = rowFileName.value else { return } let ext = (name as! NSString).pathExtension.uppercased() var fileNameSave = "" - - if (ext == "") { + + if ext == "" { fileNameSave = name as! String + ".m4a" } else { fileNameSave = (name as! NSString).deletingPathExtension + ".m4a" } - - 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: "", livePhoto: false) - + + 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: "", livePhoto: false) + metadataForUpload.session = NCNetworking.shared.sessionIdentifierBackground metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload - + if NCManageDatabase.shared.getMetadataConflict(account: appDelegate.account, serverUrl: serverUrl, fileName: fileNameSave) != nil { - + guard let conflictViewController = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict else { return } conflictViewController.textLabelDetailNewFile = NSLocalizedString("_now_", comment: "") conflictViewController.serverUrl = serverUrl conflictViewController.metadatasUploadInConflict = [metadataForUpload] conflictViewController.delegate = self - + self.present(conflictViewController, animated: true, completion: nil) - + } else { - + dismissAndUpload(metadataForUpload) } } - + func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) { - + if metadatas != nil && metadatas!.count > 0 { - + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { self.dismissAndUpload(metadatas![0]) } } } - + func dismissAndUpload(_ metadata: tableMetadata) { - + CCUtility.copyFile(atPath: self.fileNamePath, toPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)) - + appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: [metadata]) self.dismiss(animated: true, completion: nil) } - + @objc func cancel() { - + try? FileManager.default.removeItem(atPath: fileNamePath) self.dismiss(animated: true, completion: nil) } - + @objc func changeDestinationFolder(_ sender: XLFormRowDescriptor) { - + self.deselectFormRow(sender) - + let storyboard = UIStoryboard(name: "NCSelect", bundle: nil) let navigationController = storyboard.instantiateInitialViewController() as! UINavigationController let viewController = navigationController.topViewController as! NCSelect - + viewController.delegate = self viewController.typeOfCommandView = .selectCreateFolder viewController.includeDirectoryE2EEncryption = true - + self.present(navigationController, animated: true, completion: nil) } - - //MARK: Player - Timer + + // MARK: Player - Timer func updateTimerUI() { - labelTimer.text = String.init().formatSecondsToString(counterSecondPlayer) - labelDuration.text = String.init().formatSecondsToString(durationPlayer) + labelTimer.text = String().formatSecondsToString(counterSecondPlayer) + labelDuration.text = String().formatSecondsToString(durationPlayer) progressView.progress = Float(counterSecondPlayer / durationPlayer) } - + @objc func updateTimer() { counterSecondPlayer += 1 updateTimerUI() } - + @IBAction func playStop(_ sender: Any) { if audioPlayer.isPlaying { - + stop() - + } else { - + start() } } - + func start() { - + audioPlayer.prepareToPlay() audioPlayer.play() - + timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true) - + buttonPlayStop.setImage(UIImage(named: "stop")!.image(color: NCBrandColor.shared.gray, size: 100), for: .normal) } - + func stop() { - + audioPlayer.currentTime = 0.0 audioPlayer.stop() - + timer.invalidate() counterSecondPlayer = 0 progressView.progress = 0 updateTimerUI() - + buttonPlayStop.setImage(UIImage(named: "audioPlay")!.image(color: NCBrandColor.shared.gray, size: 100), for: .normal) } - + func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { - + timer.invalidate() counterSecondPlayer = 0 progressView.progress = 0 updateTimerUI() - + buttonPlayStop.setImage(UIImage(named: "audioPlay")!.image(color: NCBrandColor.shared.gray, size: 100), for: .normal) } } - diff --git a/iOSClient/Main/Create cloud/NCCreateMenuAdd.swift b/iOSClient/Main/Create cloud/NCCreateMenuAdd.swift index e3386e79e..d0b0a6e8f 100644 --- a/iOSClient/Main/Create cloud/NCCreateMenuAdd.swift +++ b/iOSClient/Main/Create cloud/NCCreateMenuAdd.swift @@ -25,64 +25,64 @@ import Foundation import Sheeeeeeeeet class NCCreateMenuAdd: NSObject { - - let appDelegate = UIApplication.shared.delegate as! AppDelegate + + weak var appDelegate = UIApplication.shared.delegate as! AppDelegate var isNextcloudTextAvailable = false - - @objc init(viewController: UIViewController, view : UIView) { + + @objc init(viewController: UIViewController, view: UIView) { super.init() if self.appDelegate.reachability.isReachable() && NCBrandBeta.shared.directEditing && NCManageDatabase.sharedInstance.getDirectEditingCreators(account: self.appDelegate.activeAccount) != nil { isNextcloudTextAvailable = true } - + var items = [MenuItem]() ActionSheetTableView.appearance().backgroundColor = NCBrandColor.sharedInstance.backgroundForm ActionSheetTableView.appearance().separatorColor = NCBrandColor.sharedInstance.separator ActionSheetItemCell.appearance().backgroundColor = NCBrandColor.sharedInstance.backgroundForm ActionSheetItemCell.appearance().titleColor = NCBrandColor.sharedInstance.textView - - items.append(MenuItem(title: NSLocalizedString("_upload_photos_videos_", comment: ""), value: 10, image: CCGraphics.changeThemingColorImage(UIImage.init(named: "file_photo"), width: 50, height: 50, color: NCBrandColor.sharedInstance.icon))) - - items.append(MenuItem(title: NSLocalizedString("_upload_file_", comment: ""), value: 20, image: CCGraphics.changeThemingColorImage(UIImage.init(named: "file"), width: 50, height: 50, color: NCBrandColor.sharedInstance.icon))) - + + items.append(MenuItem(title: NSLocalizedString("_upload_photos_videos_", comment: ""), value: 10, image: CCGraphics.changeThemingColorImage(UIImage(named: "file_photo"), width: 50, height: 50, color: NCBrandColor.sharedInstance.icon))) + + items.append(MenuItem(title: NSLocalizedString("_upload_file_", comment: ""), value: 20, image: CCGraphics.changeThemingColorImage(UIImage(named: "file"), width: 50, height: 50, color: NCBrandColor.sharedInstance.icon))) + if NCBrandOptions.sharedInstance.use_imi_viewer { - items.append(MenuItem(title: NSLocalizedString("_im_create_new_file", tableName: "IMLocalizable", bundle: Bundle.main, value: "", comment: ""), value: 21, image: CCGraphics.scale(UIImage.init(named: "imagemeter"), to: CGSize(width: 25, height: 25), isAspectRation: true))) + items.append(MenuItem(title: NSLocalizedString("_im_create_new_file", tableName: "IMLocalizable", bundle: Bundle.main, value: "", comment: ""), value: 21, image: CCGraphics.scale(UIImage(named: "imagemeter"), to: CGSize(width: 25, height: 25), isAspectRation: true))) } - + if isNextcloudTextAvailable { - items.append(MenuItem(title: NSLocalizedString("_create_nextcloudtext_document_", comment: ""), value: 31, image: CCGraphics.changeThemingColorImage(UIImage.init(named: "file_txt"), width: 50, height: 50, color: NCBrandColor.sharedInstance.icon))) + items.append(MenuItem(title: NSLocalizedString("_create_nextcloudtext_document_", comment: ""), value: 31, image: CCGraphics.changeThemingColorImage(UIImage(named: "file_txt"), width: 50, height: 50, color: NCBrandColor.sharedInstance.icon))) } else { - items.append(MenuItem(title: NSLocalizedString("_upload_file_text_", comment: ""), value: 30, image: CCGraphics.changeThemingColorImage(UIImage.init(named: "file_txt"), width: 50, height: 50, color: NCBrandColor.sharedInstance.icon))) + items.append(MenuItem(title: NSLocalizedString("_upload_file_text_", comment: ""), value: 30, image: CCGraphics.changeThemingColorImage(UIImage(named: "file_txt"), width: 50, height: 50, color: NCBrandColor.sharedInstance.icon))) } - + #if !targetEnvironment(simulator) if #available(iOS 11.0, *) { - items.append(MenuItem(title: NSLocalizedString("_scans_document_", comment: ""), value: 40, image: CCGraphics.changeThemingColorImage(UIImage.init(named: "scan"), width: 50, height: 50, color: NCBrandColor.sharedInstance.icon))) + items.append(MenuItem(title: NSLocalizedString("_scans_document_", comment: ""), value: 40, image: CCGraphics.changeThemingColorImage(UIImage(named: "scan"), width: 50, height: 50, color: NCBrandColor.sharedInstance.icon))) } #endif - - items.append(MenuItem(title: NSLocalizedString("_create_voice_memo_", comment: ""), value: 50, image: CCGraphics.changeThemingColorImage(UIImage.init(named: "microphone"), width: 50, height: 50, color: NCBrandColor.sharedInstance.icon))) - items.append(MenuItem(title: NSLocalizedString("_create_folder_", comment: ""), value: 60, image: CCGraphics.changeThemingColorImage(UIImage.init(named: "folder"), width: 50, height: 50, color: NCBrandColor.sharedInstance.brandElement))) - + items.append(MenuItem(title: NSLocalizedString("_create_voice_memo_", comment: ""), value: 50, image: CCGraphics.changeThemingColorImage(UIImage(named: "microphone"), width: 50, height: 50, color: NCBrandColor.sharedInstance.icon))) + + items.append(MenuItem(title: NSLocalizedString("_create_folder_", comment: ""), value: 60, image: CCGraphics.changeThemingColorImage(UIImage(named: "folder"), width: 50, height: 50, color: NCBrandColor.sharedInstance.brandElement))) + if let richdocumentsMimetypes = NCManageDatabase.sharedInstance.getRichdocumentsMimetypes(account: appDelegate.activeAccount) { if richdocumentsMimetypes.count > 0 { - items.append(MenuItem(title: NSLocalizedString("_create_new_document_", comment: ""), value: 70, image: UIImage.init(named: "create_file_document"))) + items.append(MenuItem(title: NSLocalizedString("_create_new_document_", comment: ""), value: 70, image: UIImage(named: "create_file_document"))) items.append(MenuItem(title: NSLocalizedString("_create_new_spreadsheet_", comment: ""), value: 80, image: UIImage(named: "create_file_xls"))) items.append(MenuItem(title: NSLocalizedString("_create_new_presentation_", comment: ""), value: 90, image: UIImage(named: "create_file_ppt"))) } } - + items.append(CancelButton(title: NSLocalizedString("_cancel_", comment: ""))) - - let actionSheet = ActionSheet(menu: Menu(items: items), action: { (shhet, item) in + + let actionSheet = ActionSheet(menu: Menu(items: items), action: { _, item in if item.value as? Int == 10 { self.appDelegate.activeMain.openAssetsPickerController() } if item.value as? Int == 20 { self.appDelegate.activeMain.openImportDocumentPicker() } if item.value as? Int == 21 { - _ = IMCreate.init(serverUrl: self.appDelegate.activeMain.serverUrl) + _ = IMCreate(serverUrl: self.appDelegate.activeMain.serverUrl) } if item.value as? Int == 30 { let storyboard = UIStoryboard(name: "NCText", bundle: nil) @@ -95,12 +95,12 @@ class NCCreateMenuAdd: NSObject { return } navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet - + let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments viewController.typeTemplate = k_template_document viewController.serverUrl = self.appDelegate.activeMain.serverUrl viewController.titleForm = NSLocalizedString("_create_nextcloudtext_document_", comment: "") - + self.appDelegate.window.rootViewController?.present(navigationController, animated: true, completion: nil) } if item.value as? Int == 40 { @@ -108,22 +108,22 @@ class NCCreateMenuAdd: NSObject { NCCreateScanDocument.sharedInstance.openScannerDocument(viewController: self.appDelegate.activeMain) } } - + if item.value as? Int == 50 { NCMainCommon.sharedInstance.startAudioRecorder() } - + if item.value as? Int == 60 { self.appDelegate.activeMain.createFolder() } - + if item.value as? Int == 70 { guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController() else { return } navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet - + let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments viewController.typeTemplate = k_template_document viewController.serverUrl = self.appDelegate.activeMain.serverUrl viewController.titleForm = NSLocalizedString("_create_new_document_", comment: "") - + self.appDelegate.window.rootViewController?.present(navigationController, animated: true, completion: nil) } if item.value as? Int == 80 { @@ -131,12 +131,12 @@ class NCCreateMenuAdd: NSObject { return } navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet - + let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments viewController.typeTemplate = k_template_spreadsheet viewController.serverUrl = self.appDelegate.activeMain.serverUrl viewController.titleForm = NSLocalizedString("_create_new_spreadsheet_", comment: "") - + self.appDelegate.window.rootViewController?.present(navigationController, animated: true, completion: nil) } if item.value as? Int == 90 { @@ -144,19 +144,19 @@ class NCCreateMenuAdd: NSObject { return } navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet - + let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments viewController.typeTemplate = k_template_presentation viewController.serverUrl = self.appDelegate.activeMain.serverUrl viewController.titleForm = NSLocalizedString("_create_new_presentation_", comment: "") - + self.appDelegate.window.rootViewController?.present(navigationController, animated: true, completion: nil) } - + if item is CancelButton { print("Cancel buttons has the value `true`") } }) - + actionSheet.present(in: viewController, from: view) - + } } diff --git a/iOSClient/Main/NCCellProtocol.swift b/iOSClient/Main/NCCellProtocol.swift index 88f223364..21f2fa7f9 100644 --- a/iOSClient/Main/NCCellProtocol.swift +++ b/iOSClient/Main/NCCellProtocol.swift @@ -29,4 +29,3 @@ protocol NCCellProtocol { var filePreviewImageView: UIImageView? { get } var fileUser: String? { get } } - diff --git a/iOSClient/Main/NCFunctionCenter.swift b/iOSClient/Main/NCFunctionCenter.swift index 82549b115..5ec47ed59 100644 --- a/iOSClient/Main/NCFunctionCenter.swift +++ b/iOSClient/Main/NCFunctionCenter.swift @@ -29,31 +29,31 @@ import IHProgressHUD @objc class NCFunctionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelectDelegate { @objc public static let shared: NCFunctionCenter = { let instance = NCFunctionCenter() - + NotificationCenter.default.addObserver(instance, selector: #selector(downloadedFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile), object: nil) NotificationCenter.default.addObserver(instance, selector: #selector(uploadedFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile), object: nil) - + return instance }() - + let appDelegate = UIApplication.shared.delegate as! AppDelegate var viewerQuickLook: NCViewerQuickLook? var documentController: UIDocumentInteractionController? - - //MARK: - Download + + // MARK: - Download @objc func downloadedFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let selector = userInfo["selector"] as? String, let errorCode = userInfo["errorCode"] as? Int, let errorDescription = userInfo["errorDescription"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - + if metadata.account != appDelegate.account { return } - + if errorCode == 0 { - + switch selector { case NCGlobal.shared.selectorLoadFileQuickLook: - + let fileNamePath = NSTemporaryDirectory() + metadata.fileNameView CCUtility.copyFile(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView), toPath: fileNamePath) @@ -61,120 +61,120 @@ import IHProgressHUD if #available(iOS 13.0, *) { editingMode = true } - + let viewerQuickLook = NCViewerQuickLook(with: URL(fileURLWithPath: fileNamePath), editingMode: editingMode, metadata: metadata) let navigationController = UINavigationController(rootViewController: viewerQuickLook) navigationController.modalPresentationStyle = .overFullScreen - + self.appDelegate.window?.rootViewController?.present(navigationController, animated: true) - + case NCGlobal.shared.selectorLoadFileView: - + if UIApplication.shared.applicationState == UIApplication.State.active { - + if metadata.contentType.contains("opendocument") && !NCUtility.shared.isRichDocument(metadata) { - + self.openDocumentController(metadata: metadata) - + } else if metadata.classFile == NCCommunicationCommon.typeClassFile.compress.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.unknow.rawValue { self.openDocumentController(metadata: metadata) - + } else { - + if let viewController = self.appDelegate.activeViewController { let imageIcon = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) NCViewer.shared.view(viewController: viewController, metadata: metadata, metadatas: [metadata], imageIcon: imageIcon) } } } - + case NCGlobal.shared.selectorOpenIn: - + if UIApplication.shared.applicationState == UIApplication.State.active { - + self.openDocumentController(metadata: metadata) } - + case NCGlobal.shared.selectorLoadCopy: - + copyPasteboard() - + case NCGlobal.shared.selectorLoadOffline: - + NCManageDatabase.shared.setLocalFile(ocId: metadata.ocId, offline: true) - + case NCGlobal.shared.selectorPrint: - + printDocument(metadata: metadata) - + case NCGlobal.shared.selectorSaveAlbum: - + saveAlbum(metadata: metadata) - + case NCGlobal.shared.selectorSaveBackground: - + saveBackground(metadata: metadata) - + case NCGlobal.shared.selectorSaveAlbumLivePhotoIMG, NCGlobal.shared.selectorSaveAlbumLivePhotoMOV: - + var metadata = metadata var metadataMOV = metadata guard let metadataTMP = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) else { break } - + if selector == NCGlobal.shared.selectorSaveAlbumLivePhotoIMG { metadataMOV = metadataTMP } - + if selector == NCGlobal.shared.selectorSaveAlbumLivePhotoMOV { metadata = metadataTMP } - + if CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) && CCUtility.fileProviderStorageExists(metadataMOV.ocId, fileNameView: metadataMOV.fileNameView) { saveLivePhotoToDisk(metadata: metadata, metadataMov: metadataMOV) } - + case NCGlobal.shared.selectorSaveAsScan: - + saveAsScan(metadata: metadata) - + case NCGlobal.shared.selectorOpenDetail: - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterOpenMediaDetail, userInfo: ["ocId":metadata.ocId]) - + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterOpenMediaDetail, userInfo: ["ocId": metadata.ocId]) + default: - + break } - + } else { - + // File do not exists on server, remove in local - if (errorCode == NCGlobal.shared.errorResourceNotFound || errorCode == NCGlobal.shared.errorBadServerResponse) { - + if errorCode == NCGlobal.shared.errorResourceNotFound || errorCode == NCGlobal.shared.errorBadServerResponse { + do { try FileManager.default.removeItem(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)) } catch { } - + NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) NCManageDatabase.shared.deleteLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) - + } else { - + NCContentPresenter.shared.messageNotification("_download_file_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) } } } } } - - //MARK: - Upload + + // MARK: - Upload @objc func uploadedFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let errorCode = userInfo["errorCode"] as? Int, let errorDescription = userInfo["errorDescription"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - + if metadata.account == appDelegate.account { if errorCode != 0 { if errorCode != -999 && errorDescription != "" { @@ -185,50 +185,50 @@ import IHProgressHUD } } } - + // MARK: - - func openShare(ViewController: UIViewController, metadata: tableMetadata, indexPage: NCGlobal.NCSharePagingIndex) { - + func openShare(viewController: UIViewController, metadata: tableMetadata, indexPage: NCGlobal.NCSharePagingIndex) { + let shareNavigationController = UIStoryboard(name: "NCShare", bundle: nil).instantiateInitialViewController() as! UINavigationController let shareViewController = shareNavigationController.topViewController as! NCSharePaging - + shareViewController.metadata = metadata shareViewController.indexPage = indexPage - + shareNavigationController.modalPresentationStyle = .formSheet - ViewController.present(shareNavigationController, animated: true, completion: nil) + viewController.present(shareNavigationController, animated: true, completion: nil) } - + // MARK: - - + func openDownload(metadata: tableMetadata, selector: String) { - + if CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": selector, "errorCode": 0, "errorDescription": "" ]) - + } else { - - NCNetworking.shared.download(metadata: metadata, selector: selector) { (_) in } + + NCNetworking.shared.download(metadata: metadata, selector: selector) { _ in } } } - + // MARK: - Open in ... - + func openDocumentController(metadata: tableMetadata) { - + guard let mainTabBar = self.appDelegate.mainTabBar else { return } let fileURL = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)) - + documentController = UIDocumentInteractionController(url: fileURL) documentController?.presentOptionsMenu(from: mainTabBar.menuRect, in: mainTabBar, animated: true) } - + func openActivityViewController(selectOcId: [String]) { - + NCUtility.shared.startActivityIndicator(backgroundView: nil, blurEffect: true) - + var error: Int = 0 var items: [Any] = [] @@ -253,47 +253,47 @@ import IHProgressHUD } } if error == 0 && items.count > 0 { - + guard let mainTabBar = self.appDelegate.mainTabBar else { return } - - let activityViewController = UIActivityViewController.init(activityItems: items, applicationActivities: nil) + + let activityViewController = UIActivityViewController(activityItems: items, applicationActivities: nil) activityViewController.popoverPresentationController?.permittedArrowDirections = .any activityViewController.popoverPresentationController?.sourceView = mainTabBar activityViewController.popoverPresentationController?.sourceRect = mainTabBar.menuRect - + self.appDelegate.window?.rootViewController?.present(activityViewController, animated: true) - + } NCUtility.shared.stopActivityIndicator() } - + // MARK: - Save as scan - + func saveAsScan(metadata: tableMetadata) { let fileNamePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! let fileNameDestination = CCUtility.createFileName("scan.png", fileDate: Date(), fileType: PHAssetMediaType.image, keyFileName: NCGlobal.shared.keyFileNameMask, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: true)! let fileNamePathDestination = CCUtility.getDirectoryScan() + "/" + fileNameDestination - + NCUtilityFileSystem.shared.copyFile(atPath: fileNamePath, toPath: fileNamePathDestination) - + let storyboard = UIStoryboard(name: "Scan", bundle: nil) let navigationController = storyboard.instantiateInitialViewController()! - + navigationController.modalPresentationStyle = UIModalPresentationStyle.pageSheet - + appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil) } - + // MARK: - Print - + func printDocument(metadata: tableMetadata) { - + let fileNameURL = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!) - + if UIPrintInteractionController.canPrint(fileNameURL) { - + let printInfo = UIPrintInfo(dictionary: nil) printInfo.jobName = fileNameURL.lastPathComponent printInfo.outputType = .photo @@ -305,74 +305,74 @@ import IHProgressHUD printController.present(animated: true, completionHandler: nil) } } - + // MARK: - Save photo - + func saveAlbum(metadata: tableMetadata) { - + let fileNamePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! let status = PHPhotoLibrary.authorizationStatus() if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue && status == PHAuthorizationStatus.authorized { - - if let image = UIImage.init(contentsOfFile: fileNamePath) { - UIImageWriteToSavedPhotosAlbum(image, self, #selector(SaveAlbum(_:didFinishSavingWithError:contextInfo:)), nil) + + if let image = UIImage(contentsOfFile: fileNamePath) { + UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveAlbum(_:didFinishSavingWithError:contextInfo:)), nil) } else { NCContentPresenter.shared.messageNotification("_save_selected_files_", description: "_file_not_saved_cameraroll_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorFileNotSaved) } - + } else if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue && status == PHAuthorizationStatus.authorized { - + if UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(fileNamePath) { - UISaveVideoAtPathToSavedPhotosAlbum(fileNamePath, self, #selector(SaveAlbum(_:didFinishSavingWithError:contextInfo:)), nil) + UISaveVideoAtPathToSavedPhotosAlbum(fileNamePath, self, #selector(saveAlbum(_:didFinishSavingWithError:contextInfo:)), nil) } else { NCContentPresenter.shared.messageNotification("_save_selected_files_", description: "_file_not_saved_cameraroll_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorFileNotSaved) } - + } else if status != PHAuthorizationStatus.authorized { - + NCContentPresenter.shared.messageNotification("_access_photo_not_enabled_", description: "_access_photo_not_enabled_msg_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorFileNotSaved) } } - - @objc private func SaveAlbum(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) { - + + @objc private func saveAlbum(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) { + if error != nil { NCContentPresenter.shared.messageNotification("_save_selected_files_", description: "_file_not_saved_cameraroll_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorFileNotSaved) } } - + func saveLivePhoto(metadata: tableMetadata, metadataMOV: tableMetadata) { - + if !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { NCOperationQueue.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorSaveAlbumLivePhotoIMG) } - + if !CCUtility.fileProviderStorageExists(metadataMOV.ocId, fileNameView: metadataMOV.fileNameView) { NCOperationQueue.shared.download(metadata: metadataMOV, selector: NCGlobal.shared.selectorSaveAlbumLivePhotoMOV) } - + if CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) && CCUtility.fileProviderStorageExists(metadataMOV.ocId, fileNameView: metadataMOV.fileNameView) { saveLivePhotoToDisk(metadata: metadata, metadataMov: metadataMOV) } } - + func saveLivePhotoToDisk(metadata: tableMetadata, metadataMov: tableMetadata) { - + let fileNameImage = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!) let fileNameMov = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadataMov.ocId, fileNameView: metadataMov.fileNameView)!) - + IHProgressHUD.set(defaultMaskType: .clear) IHProgressHUD.set(minimumDismiss: 2) - + NCLivePhoto.generate(from: fileNameImage, videoURL: fileNameMov, progress: { progress in - + IHProgressHUD.show(progress: CGFloat(progress)) - - }, completion: { livePhoto, resources in - + + }, completion: { _, resources in + if resources != nil { - NCLivePhoto.saveToLibrary(resources!) { (result) in + NCLivePhoto.saveToLibrary(resources!) { result in if !result { IHProgressHUD.showError(withStatus: NSLocalizedString("_livephoto_save_error_", comment: "")) } else { @@ -384,14 +384,14 @@ import IHProgressHUD } }) } - + func saveBackground(metadata: tableMetadata) { - + let fileNamePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! let destination = CCUtility.getDirectoryGroup().appendingPathComponent(NCGlobal.shared.appBackground).path + "/" + metadata.fileNameView - + if NCUtilityFileSystem.shared.copyFile(atPath: fileNamePath, toPath: destination) { - + if appDelegate.activeViewController is NCCollectionViewCommon { let viewController: NCCollectionViewCommon = appDelegate.activeViewController as! NCCollectionViewCommon let layoutKey = viewController.layoutKey @@ -403,70 +403,70 @@ import IHProgressHUD } } } - + // MARK: - Copy & Paste - + func copyPasteboard() { - + var metadatas: [tableMetadata] = [] - var items = [[String : Any]]() - + var items = [[String: Any]]() + for ocId in appDelegate.pasteboardOcIds { if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { metadatas.append(metadata) } } - + for metadata in metadatas { - + if CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { do { // Get Data - let data = try Data.init(contentsOf: URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView))) + let data = try Data(contentsOf: URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView))) // Pasteboard item if let unmanagedFileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (metadata.fileNameView as NSString).pathExtension as CFString, nil) { let fileUTI = unmanagedFileUTI.takeRetainedValue() as String - items.append([fileUTI:data]) + items.append([fileUTI: data]) } } catch { print("error") } } else { - NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadCopy) { (_) in } + NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadCopy) { _ in } } } - + UIPasteboard.general.setItems(items, options: [:]) } func pastePasteboard(serverUrl: String) { - + var pasteboardTypes: [String] = [] - - func upload(pasteboardType : String?, data: Data?) -> Bool { - + + func upload(pasteboardType: String?, data: Data?) -> Bool { + guard let data = data else { return false} guard let pasteboardType = pasteboardType else { return false } - + let results = NCCommunicationCommon.shared.getFileProperties(inUTI: pasteboardType as CFString) if results.ext == "" { return false } - + do { let fileName = results.name + "_" + CCUtility.getIncrementalNumber() + "." + results.ext let serverUrlFileName = serverUrl + "/" + fileName let ocIdUpload = UUID().uuidString let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(ocIdUpload, fileNameView: fileName)! try data.write(to: URL(fileURLWithPath: fileNameLocalPath)) - + IHProgressHUD.set(defaultMaskType: .clear) IHProgressHUD.set(minimumDismiss: 2) - NCCommunication.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath) { task in + NCCommunication.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath) { _ in } progressHandler: { progress in - + IHProgressHUD.show(progress: CGFloat(progress.fractionCompleted), status: fileName) - - } completionHandler: { account, ocId, etag, date, size, allHeaderFields, errorCode, errorDescription in + + } completionHandler: { account, ocId, etag, _, _, _, errorCode, errorDescription in if errorCode == 0 && etag != nil && ocId != nil { let toPath = CCUtility.getDirectoryProviderStorageOcId(ocId!, fileNameView: fileName)! NCUtilityFileSystem.shared.moveFile(atPath: fileNameLocalPath, toPath: toPath) @@ -482,11 +482,11 @@ import IHProgressHUD } return true } - + for (index, items) in UIPasteboard.general.items.enumerated() { for item in items { pasteboardTypes.append(item.key) } - + for typeIdentifier in pasteboardTypes { let data = UIPasteboard.general.data(forPasteboardType: typeIdentifier, inItemSet: IndexSet([index]))?.first if upload(pasteboardType: typeIdentifier, data: data) { @@ -495,21 +495,21 @@ import IHProgressHUD } } } - + // MARK: - - + func openFileViewInFolder(serverUrl: String, fileName: String) { - + let viewController = UIStoryboard(name: "NCFileViewInFolder", bundle: nil).instantiateInitialViewController() as! NCFileViewInFolder - let navigationController = UINavigationController.init(rootViewController: viewController) + let navigationController = UINavigationController(rootViewController: viewController) let topViewController = viewController var listViewController = [NCFileViewInFolder]() var serverUrl = serverUrl let homeUrl = NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) - + while true { - + var viewController: NCFileViewInFolder? if serverUrl != homeUrl { viewController = UIStoryboard(name: "NCFileViewInFolder", bundle: nil).instantiateInitialViewController() as? NCFileViewInFolder @@ -521,30 +521,30 @@ import IHProgressHUD viewController = topViewController } guard let vc = viewController else { return } - + vc.serverUrl = serverUrl vc.fileName = fileName - + vc.navigationItem.backButtonTitle = vc.titleCurrentFolder listViewController.insert(vc, at: 0) - + if serverUrl != homeUrl { serverUrl = NCUtilityFileSystem.shared.deletingLastPathComponent(account: appDelegate.account, serverUrl: serverUrl) } else { break } } - + navigationController.setViewControllers(listViewController, animated: false) navigationController.modalPresentationStyle = .formSheet - + appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil) } - + // MARK: - NCSelect + Delegate - + func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) { - if (serverUrl != nil && items.count > 0) { + if serverUrl != nil && items.count > 0 { if copy { for metadata in items as! [tableMetadata] { NCOperationQueue.shared.copyMove(metadata: metadata, serverUrl: serverUrl!, overwrite: overwrite, move: false) @@ -558,19 +558,19 @@ import IHProgressHUD } func openSelectView(items: [Any], viewController: UIViewController) { - - let navigationController = UIStoryboard.init(name: "NCSelect", bundle: nil).instantiateInitialViewController() as! UINavigationController + + let navigationController = UIStoryboard(name: "NCSelect", bundle: nil).instantiateInitialViewController() as! UINavigationController let topViewController = navigationController.topViewController as! NCSelect var listViewController = [NCSelect]() - + var copyItems: [Any] = [] for item in items { copyItems.append(item) } - + let homeUrl = NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) var serverUrl = (copyItems[0] as! Nextcloud.tableMetadata).serverUrl - + // Setup view controllers such that the current view is of the same directory the items to be copied are in while true { // If not in the topmost directory, create a new view controller and set correct title. @@ -591,28 +591,28 @@ import IHProgressHUD vc.typeOfCommandView = .copyMove vc.items = copyItems vc.serverUrl = serverUrl - + vc.navigationItem.backButtonTitle = vc.titleCurrentFolder listViewController.insert(vc, at: 0) - + if serverUrl != homeUrl { serverUrl = NCUtilityFileSystem.shared.deletingLastPathComponent(account: appDelegate.account, serverUrl: serverUrl) } else { break } } - + navigationController.setViewControllers(listViewController, animated: false) navigationController.modalPresentationStyle = .formSheet - + viewController.present(navigationController, animated: true, completion: nil) } - + // MARK: - Context Menu Configuration - + @available(iOS 13.0, *) func contextMenuConfiguration(ocId: String, viewController: UIViewController, enableDeleteLocal: Bool, enableViewInFolder: Bool, image: UIImage?) -> UIMenu { - + guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return UIMenu() } @@ -625,7 +625,7 @@ import IHProgressHUD titleSave = NSLocalizedString("_livephoto_save_", comment: "") } let titleFavorite = metadata.favorite ? NSLocalizedString("_remove_favorites_", comment: "") : NSLocalizedString("_add_favorites_", comment: "") - + let serverUrl = metadata.serverUrl + "/" + metadata.fileName var isOffline = false if metadata.directory { @@ -638,23 +638,23 @@ import IHProgressHUD } } let titleOffline = isOffline ? NSLocalizedString("_remove_available_offline_", comment: "") : NSLocalizedString("_set_available_offline_", comment: "") - - let copy = UIAction(title: NSLocalizedString("_copy_file_", comment: ""), image: UIImage(systemName: "doc.on.doc")) { action in + + let copy = UIAction(title: NSLocalizedString("_copy_file_", comment: ""), image: UIImage(systemName: "doc.on.doc")) { _ in self.appDelegate.pasteboardOcIds = [metadata.ocId] self.copyPasteboard() } - - let copyPath = UIAction(title: NSLocalizedString("_copy_path_", comment: ""), image: UIImage(systemName: "doc.on.clipboard")) { action in + + let copyPath = UIAction(title: NSLocalizedString("_copy_path_", comment: ""), image: UIImage(systemName: "doc.on.clipboard")) { _ in let board = UIPasteboard.general board.string = NCUtilityFileSystem.shared.getPath(metadata: metadata) NCContentPresenter.shared.messageNotification("", description: "_copied_path_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorNoError) } - - let detail = UIAction(title: NSLocalizedString("_details_", comment: ""), image: UIImage(systemName: "info")) { action in - self.openShare(ViewController: viewController, metadata: metadata, indexPage: .activity) + + let detail = UIAction(title: NSLocalizedString("_details_", comment: ""), image: UIImage(systemName: "info")) { _ in + self.openShare(viewController: viewController, metadata: metadata, indexPage: .activity) } - - let offline = UIAction(title: titleOffline, image: UIImage(systemName: "tray.and.arrow.down")) { action in + + let offline = UIAction(title: titleOffline, image: UIImage(systemName: "tray.and.arrow.down")) { _ in if isOffline { if metadata.directory { NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, offline: false, account: self.appDelegate.account) @@ -666,19 +666,19 @@ import IHProgressHUD NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, offline: true, account: self.appDelegate.account) NCOperationQueue.shared.synchronizationMetadata(metadata, selector: NCGlobal.shared.selectorDownloadAllFile) } else { - NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadOffline) { (_) in } + 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 } + NCNetworking.shared.download(metadata: metadataLivePhoto, selector: NCGlobal.shared.selectorLoadOffline) { _ in } } } } - + if viewController is NCCollectionViewCommon { (viewController as! NCCollectionViewCommon).reloadDataSource() } } - - let save = UIAction(title: titleSave, image: UIImage(systemName: "square.and.arrow.down")) { action in + + let save = UIAction(title: titleSave, image: UIImage(systemName: "square.and.arrow.down")) { _ in if metadataMOV != nil { self.saveLivePhoto(metadata: metadata, metadataMOV: metadataMOV!) } else { @@ -689,120 +689,120 @@ import IHProgressHUD } } } - - let saveBackground = UIAction(title: NSLocalizedString("_use_as_background_", comment: ""), image: UIImage(systemName: "text.below.photo")) { action in + + let saveBackground = UIAction(title: NSLocalizedString("_use_as_background_", comment: ""), image: UIImage(systemName: "text.below.photo")) { _ in if CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { self.saveBackground(metadata: metadata) } else { NCOperationQueue.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorSaveBackground) } } - - let viewInFolder = UIAction(title: NSLocalizedString("_view_in_folder_", comment: ""), image: UIImage(systemName: "arrow.forward.square")) { action in + + let viewInFolder = UIAction(title: NSLocalizedString("_view_in_folder_", comment: ""), image: UIImage(systemName: "arrow.forward.square")) { _ in self.openFileViewInFolder(serverUrl: metadata.serverUrl, fileName: metadata.fileName) } - - let openIn = UIAction(title: NSLocalizedString("_open_in_", comment: ""), image: UIImage(systemName: "square.and.arrow.up") ) { action in + + let openIn = UIAction(title: NSLocalizedString("_open_in_", comment: ""), image: UIImage(systemName: "square.and.arrow.up") ) { _ in self.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorOpenIn) } - - let print = UIAction(title: NSLocalizedString("_print_", comment: ""), image: UIImage(systemName: "printer") ) { action in + + let print = UIAction(title: NSLocalizedString("_print_", comment: ""), image: UIImage(systemName: "printer") ) { _ in self.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorPrint) } - - let modify = UIAction(title: NSLocalizedString("_modify_", comment: ""), image: UIImage(systemName: "pencil.tip.crop.circle")) { action in + + let modify = UIAction(title: NSLocalizedString("_modify_", comment: ""), image: UIImage(systemName: "pencil.tip.crop.circle")) { _ in self.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorLoadFileQuickLook) } - - let saveAsScan = UIAction(title: NSLocalizedString("_save_as_scan_", comment: ""), image: UIImage(systemName: "viewfinder.circle")) { action in + + let saveAsScan = UIAction(title: NSLocalizedString("_save_as_scan_", comment: ""), image: UIImage(systemName: "viewfinder.circle")) { _ in self.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorSaveAsScan) } - - //let open = UIMenu(title: NSLocalizedString("_open_", comment: ""), image: UIImage(systemName: "square.and.arrow.up"), children: [openIn, openQuickLook]) - - let moveCopy = UIAction(title: NSLocalizedString("_move_or_copy_", comment: ""), image: UIImage(systemName: "arrow.up.right.square")) { action in + + // let open = UIMenu(title: NSLocalizedString("_open_", comment: ""), image: UIImage(systemName: "square.and.arrow.up"), children: [openIn, openQuickLook]) + + let moveCopy = UIAction(title: NSLocalizedString("_move_or_copy_", comment: ""), image: UIImage(systemName: "arrow.up.right.square")) { _ in self.openSelectView(items: [metadata], viewController: viewController) } - - let rename = UIAction(title: NSLocalizedString("_rename_", comment: ""), image: UIImage(systemName: "pencil")) { action in - + + let rename = UIAction(title: NSLocalizedString("_rename_", comment: ""), image: UIImage(systemName: "pencil")) { _ in + if let vcRename = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile { - + vcRename.metadata = metadata vcRename.imagePreview = image let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height) - + viewController.present(popup, animated: true) } } - - let favorite = UIAction(title: titleFavorite, image: NCUtility.shared.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite)) { action in - - NCNetworking.shared.favoriteMetadata(metadata) { (errorCode, errorDescription) in + + let favorite = UIAction(title: titleFavorite, image: NCUtility.shared.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite)) { _ in + + NCNetworking.shared.favoriteMetadata(metadata) { errorCode, errorDescription in if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } } } - - let deleteConfirmFile = UIAction(title: titleDeleteConfirmFile, image: UIImage(systemName: "trash"), attributes: .destructive) { action in - NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false) { (errorCode, errorDescription) in + + let deleteConfirmFile = UIAction(title: titleDeleteConfirmFile, image: UIImage(systemName: "trash"), attributes: .destructive) { _ in + NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false) { errorCode, errorDescription in if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } } } - - let deleteConfirmLocal = UIAction(title: NSLocalizedString("_remove_local_file_", comment: ""), image: UIImage(systemName: "trash"), attributes: .destructive) { action in - NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: true) { (errorCode, errorDescription) in + + let deleteConfirmLocal = UIAction(title: NSLocalizedString("_remove_local_file_", comment: ""), image: UIImage(systemName: "trash"), attributes: .destructive) { _ in + NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: true) { _, _ in } } - + var delete = UIMenu(title: NSLocalizedString("_delete_file_", comment: ""), image: UIImage(systemName: "trash"), options: .destructive, children: [deleteConfirmLocal, deleteConfirmFile]) - + if !enableDeleteLocal { delete = UIMenu(title: NSLocalizedString("_delete_file_", comment: ""), image: UIImage(systemName: "trash"), options: .destructive, children: [deleteConfirmFile]) } - + if metadata.directory { delete = UIMenu(title: NSLocalizedString("_delete_folder_", comment: ""), image: UIImage(systemName: "trash"), options: .destructive, children: [deleteConfirmFile]) } - + // ------ MENU ----- - + // DIR - + if metadata.directory { - + let submenu = UIMenu(title: "", options: .displayInline, children: [favorite, offline, rename, moveCopy, copyPath, delete]) return UIMenu(title: "", children: [detail, submenu]) } - + // FILE - + var children: [UIMenuElement] = [favorite, offline, openIn, rename, moveCopy, copy, copyPath, delete] if (metadata.contentType != "image/svg+xml") && (metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue) { children.insert(save, at: 2) } - + if (metadata.contentType != "image/svg+xml") && (metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue) { children.insert(saveAsScan, at: 2) } - + if (metadata.contentType != "image/svg+xml") && (metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue || metadata.contentType == "application/pdf" || metadata.contentType == "com.adobe.pdf") { children.insert(print, at: 2) } - + if enableViewInFolder { children.insert(viewInFolder, at: children.count-1) } - + if (!isFolderEncrypted && metadata.contentType != "image/gif" && metadata.contentType != "image/svg+xml") && (metadata.contentType == "com.adobe.pdf" || metadata.contentType == "application/pdf" || metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue) { children.insert(modify, at: children.count-1) } - + if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue && viewController is NCCollectionViewCommon && !NCBrandOptions.shared.disable_background_image { let viewController: NCCollectionViewCommon = viewController as! NCCollectionViewCommon let layoutKey = viewController.layoutKey @@ -810,9 +810,8 @@ import IHProgressHUD children.insert(saveBackground, at: children.count-1) } } - + let submenu = UIMenu(title: "", options: .displayInline, children: children) return UIMenu(title: "", children: [detail, submenu]) } } - diff --git a/iOSClient/Main/NCMainNavigationController.swift b/iOSClient/Main/NCMainNavigationController.swift index 206cf1471..91b426fbc 100644 --- a/iOSClient/Main/NCMainNavigationController.swift +++ b/iOSClient/Main/NCMainNavigationController.swift @@ -24,55 +24,53 @@ import UIKit class NCMainNavigationController: UINavigationController { - - private let appDelegate = UIApplication.shared.delegate as! AppDelegate // MARK: - View Life Cycle required init?(coder: NSCoder) { super.init(coder: coder) - + NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil) - + changeTheming() } - + override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - + changeTheming() } - + // MARK: - Theming - + @objc func changeTheming() { - + if #available(iOS 13.0, *) { - + let appearance = UINavigationBarAppearance() - + appearance.configureWithOpaqueBackground() - appearance.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor : NCBrandColor.shared.label] + appearance.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: NCBrandColor.shared.label] appearance.backgroundColor = NCBrandColor.shared.systemBackground appearance.configureWithOpaqueBackground() - appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor : NCBrandColor.shared.label] + appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: NCBrandColor.shared.label] appearance.backgroundColor = NCBrandColor.shared.systemBackground navigationBar.scrollEdgeAppearance = appearance navigationBar.standardAppearance = appearance - + } else { - + navigationBar.barStyle = .default navigationBar.barTintColor = NCBrandColor.shared.systemBackground - navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor:NCBrandColor.shared.label] - navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor:NCBrandColor.shared.label] + navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: NCBrandColor.shared.label] + navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: NCBrandColor.shared.label] } - + navigationBar.tintColor = .systemBlue navigationBar.setNeedsLayout() } diff --git a/iOSClient/Main/NCMainTabBar.swift b/iOSClient/Main/NCMainTabBar.swift index e1a5e1e2d..7a3dd50fa 100644 --- a/iOSClient/Main/NCMainTabBar.swift +++ b/iOSClient/Main/NCMainTabBar.swift @@ -29,40 +29,40 @@ class NCMainTabBar: UITabBar { private var shapeLayer: CALayer? private let appDelegate = UIApplication.shared.delegate as! AppDelegate private var timer: Timer? - + public var menuRect: CGRect { get { let tabBarItemWidth = Int(self.frame.size.width) / (self.items?.count ?? 0) let rect = CGRect(x: 0, y: -5, width: tabBarItemWidth, height: Int(self.frame.size.height)) - + return rect } } - + // MARK: - Life Cycle required init?(coder: NSCoder) { super.init(coder: coder) - + appDelegate.mainTabBar = self timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: (#selector(updateBadgeNumber)), userInfo: nil, repeats: true) - + 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 = NCBrandColor.shared.secondarySystemBackground backgroundColor = NCBrandColor.shared.secondarySystemBackground - + changeTheming() } - + @objc func changeTheming() { tintColor = NCBrandColor.shared.brandElement if let centerButton = self.viewWithTag(99) { centerButton.backgroundColor = NCBrandColor.shared.brandElement - } + } } - + override var backgroundColor: UIColor? { get { return self.fillColor @@ -72,7 +72,7 @@ class NCMainTabBar: UITabBar { self.setNeedsDisplay() } } - + override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { let button = self.viewWithTag(99) if self.bounds.contains(point) || (button != nil && button!.frame.contains(point)) { @@ -84,7 +84,7 @@ class NCMainTabBar: UITabBar { override func layoutSubviews() { super.layoutSubviews() - + layer.shadowPath = createPath() layer.shadowRadius = 5 layer.shadowOffset = .zero @@ -97,7 +97,7 @@ class NCMainTabBar: UITabBar { } private func addShape() { - + let shapeLayer = CAShapeLayer() shapeLayer.path = createPath() shapeLayer.fillColor = backgroundColor?.cgColor @@ -111,9 +111,9 @@ class NCMainTabBar: UITabBar { self.shapeLayer = shapeLayer } - + private func createPath() -> CGPath { - + let height: CGFloat = 28 let margin: CGFloat = 6 let path = UIBezierPath() @@ -131,54 +131,54 @@ class NCMainTabBar: UITabBar { return path.cgPath } - + private func createButtons() { - + // File if let item = items?[0] { item.title = NSLocalizedString("_home_", comment: "") item.image = UIImage(named: "tabBarFiles")?.image(color: NCBrandColor.shared.brandElement, size: 25) item.selectedImage = item.image } - + // Favorite if let item = items?[1] { item.title = NSLocalizedString("_favorites_", comment: "") item.image = UIImage(named: "tabBarFavorites")?.image(color: NCBrandColor.shared.brandElement, size: 25) item.selectedImage = item.image } - + // + if let item = items?[2] { item.title = "" item.image = nil item.isEnabled = false } - + // Media if let item = items?[3] { item.title = NSLocalizedString("_media_", comment: "") item.image = UIImage(named: "tabBarMedia")?.image(color: NCBrandColor.shared.brandElement, size: 25) item.selectedImage = item.image } - + // More if let item = items?[4] { item.title = NSLocalizedString("_more_", comment: "") item.image = UIImage(named: "tabBarMore")?.image(color: NCBrandColor.shared.brandElement, size: 25) item.selectedImage = item.image } - + // Center button - + if let centerButton = self.viewWithTag(99) { centerButton.removeFromSuperview() } let centerButtonHeight: CGFloat = 57 let centerButtonY: CGFloat = -28 - + let centerButton = UIButton(frame: CGRect(x: (self.bounds.width / 2)-(centerButtonHeight/2), y: centerButtonY, width: centerButtonHeight, height: centerButtonHeight)) - + centerButton.setTitle("", for: .normal) centerButton.setImage(UIImage(named: "tabBarPlus")?.image(color: .white, size: 100), for: .normal) centerButton.backgroundColor = NCBrandColor.shared.brandElement @@ -191,33 +191,33 @@ class NCMainTabBar: UITabBar { centerButton.layer.shadowRadius = 3.0 centerButton.layer.shadowOpacity = 0.5 centerButton.action(for: .touchUpInside) { _ in - + if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.appDelegate.activeServerUrl)) { - + if !directory.permissions.contains("CK") { NCContentPresenter.shared.messageNotification("_warning_", description: "_no_permission_add_file_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorInternalError) return } } - + if let viewController = self.window?.rootViewController { self.appDelegate.toggleMenu(viewController: viewController) } } - + self.addSubview(centerButton) } - + @objc func updateBadgeNumber() { - + if appDelegate.account == "" { return } - + let counterDownload = NCOperationQueue.shared.downloadCount() let counterUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "status == %d OR status == %d OR status == %d", NCGlobal.shared.metadataStatusWaitUpload, NCGlobal.shared.metadataStatusInUpload, NCGlobal.shared.metadataStatusUploading)).count let total = counterDownload + counterUpload - + UIApplication.shared.applicationIconBadgeNumber = total - + if let item = items?[0] { if total > 0 { item.badgeValue = String(total) @@ -226,7 +226,7 @@ class NCMainTabBar: UITabBar { } } } - + func getCenterButton() -> UIView? { if let centerButton = self.viewWithTag(99) { return centerButton @@ -235,4 +235,3 @@ class NCMainTabBar: UITabBar { } } } - diff --git a/iOSClient/Main/NCPickerViewController.swift b/iOSClient/Main/NCPickerViewController.swift index 5e1fad729..e005aa5ec 100644 --- a/iOSClient/Main/NCPickerViewController.swift +++ b/iOSClient/Main/NCPickerViewController.swift @@ -25,7 +25,7 @@ import UIKit import TLPhotoPicker import MobileCoreServices -//MARK: - Photo Picker +// MARK: - Photo Picker class NCPhotosPickerViewController: NSObject { @@ -38,65 +38,65 @@ class NCPhotosPickerViewController: NSObject { init(viewController: UIViewController, maxSelectedAssets: Int, singleSelectedMode: Bool) { sourceViewController = viewController super.init() - + self.maxSelectedAssets = maxSelectedAssets self.singleSelectedMode = singleSelectedMode - - self.openPhotosPickerViewController { (assets) in + + self.openPhotosPickerViewController { assets in guard let assets = assets else { return } if assets.count > 0 { - - let form = NCCreateFormUploadAssets.init(serverUrl: self.appDelegate.activeServerUrl, assets: assets, cryptated: false, session: NCNetworking.shared.sessionIdentifierBackground, delegate: nil) - let navigationController = UINavigationController.init(rootViewController: form) - + + let form = NCCreateFormUploadAssets(serverUrl: self.appDelegate.activeServerUrl, assets: assets, cryptated: false, session: NCNetworking.shared.sessionIdentifierBackground, delegate: nil) + let navigationController = UINavigationController(rootViewController: form) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) { viewController.present(navigationController, animated: true, completion: nil) } } } } - - private func openPhotosPickerViewController(completition: @escaping ([PHAsset]?) -> ()) { - + + private func openPhotosPickerViewController(completition: @escaping ([PHAsset]?) -> Void) { + var selectedAssets: [PHAsset] = [] var configure = TLPhotosPickerConfigure() - + configure.cancelTitle = NSLocalizedString("_cancel_", comment: "") configure.doneTitle = NSLocalizedString("_done_", comment: "") configure.emptyMessage = NSLocalizedString("_no_albums_", comment: "") configure.tapHereToChange = NSLocalizedString("_tap_here_to_change_", comment: "") - + if maxSelectedAssets > 0 { configure.maxSelectedAssets = maxSelectedAssets } configure.selectedColor = NCBrandColor.shared.brandElement configure.singleSelectedMode = singleSelectedMode configure.allowedAlbumCloudShared = true - - let viewController = customPhotoPickerViewController(withTLPHAssets: { (assets) in - + + let viewController = customPhotoPickerViewController(withTLPHAssets: { assets in + for asset: TLPHAsset in assets { if asset.phAsset != nil { selectedAssets.append(asset.phAsset!) } } - + completition(selectedAssets) - + }, didCancel: nil) - - viewController.didExceedMaximumNumberOfSelection = { (picker) in + + viewController.didExceedMaximumNumberOfSelection = { _ in NCContentPresenter.shared.messageNotification("_info_", description: "_limited_dimension_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError) } - - viewController.handleNoAlbumPermissions = { (picker) in + + viewController.handleNoAlbumPermissions = { _ in NCContentPresenter.shared.messageNotification("_info_", description: "_denied_album_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError) } - - viewController.handleNoCameraPermissions = { (picker) in + + viewController.handleNoCameraPermissions = { _ in NCContentPresenter.shared.messageNotification("_info_", description: "_denied_camera_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError) } - + viewController.configure = configure sourceViewController.present(viewController, animated: true, completion: nil) @@ -104,78 +104,76 @@ class NCPhotosPickerViewController: NSObject { } class customPhotoPickerViewController: TLPhotosPickerViewController { - + override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } - + override func makeUI() { super.makeUI() - + self.customNavItem.leftBarButtonItem?.tintColor = .systemBlue self.customNavItem.rightBarButtonItem?.tintColor = .systemBlue } } -//MARK: - Document Picker +// MARK: - Document Picker class NCDocumentPickerViewController: NSObject, UIDocumentPickerDelegate { let appDelegate = UIApplication.shared.delegate as! AppDelegate - + @discardableResult init (tabBarController: UITabBarController) { super.init() - + let documentProviderMenu = UIDocumentPickerViewController(documentTypes: ["public.data"], in: .import) - + documentProviderMenu.modalPresentationStyle = .formSheet documentProviderMenu.allowsMultipleSelection = true documentProviderMenu.popoverPresentationController?.sourceView = tabBarController.tabBar documentProviderMenu.popoverPresentationController?.sourceRect = tabBarController.tabBar.bounds documentProviderMenu.delegate = self - + appDelegate.window?.rootViewController?.present(documentProviderMenu, animated: true, completion: nil) } - + func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { - + for url in urls { - + let fileName = url.lastPathComponent let serverUrl = appDelegate.activeServerUrl let ocId = NSUUID().uuidString let atPath = url.path let toPath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)! - + if NCUtilityFileSystem.shared.copyFile(atPath: atPath, toPath: toPath) { - + 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: "", livePhoto: false) - + metadataForUpload.session = NCNetworking.shared.sessionIdentifierBackground metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile metadataForUpload.size = NCUtilityFileSystem.shared.getFileSize(filePath: toPath) metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload - + if NCManageDatabase.shared.getMetadataConflict(account: appDelegate.account, serverUrl: serverUrl, fileName: fileName) != nil { - - if let conflict = UIStoryboard.init(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict { - + + if let conflict = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict { + conflict.serverUrl = serverUrl conflict.metadatasUploadInConflict = [metadataForUpload] - + appDelegate.window?.rootViewController?.present(conflict, animated: true, completion: nil) } - + } else { appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: [metadataForUpload]) } - + } else { NCContentPresenter.shared.messageNotification("_error_", description: "_read_file_error_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError) } } } } - - diff --git a/iOSClient/Main/Section Header Footer/NCSectionHeaderFooter.swift b/iOSClient/Main/Section Header Footer/NCSectionHeaderFooter.swift index 5857c2fa1..53d37e134 100644 --- a/iOSClient/Main/Section Header Footer/NCSectionHeaderFooter.swift +++ b/iOSClient/Main/Section Header Footer/NCSectionHeaderFooter.swift @@ -25,7 +25,7 @@ import UIKit import MarkdownKit class NCSectionHeaderMenu: UICollectionReusableView, UIGestureRecognizerDelegate { - + @IBOutlet weak var buttonMore: UIButton! @IBOutlet weak var buttonSwitch: UIButton! @IBOutlet weak var buttonOrder: UIButton! @@ -35,35 +35,35 @@ class NCSectionHeaderMenu: UICollectionReusableView, UIGestureRecognizerDelegate @IBOutlet weak var textViewRichWorkspace: UITextView! @IBOutlet weak var separator: UIView! @IBOutlet weak var separatorHeightConstraint: NSLayoutConstraint! - - var delegate: NCSectionHeaderMenuDelegate? + + weak var delegate: NCSectionHeaderMenuDelegate? private var markdownParser = MarkdownParser() private var richWorkspaceText: String? private var textViewColor: UIColor? - private let gradient : CAGradientLayer = CAGradientLayer() - + private let gradient: CAGradientLayer = CAGradientLayer() + override func awakeFromNib() { super.awakeFromNib() - + backgroundColor = .clear - - buttonSwitch.setImage(UIImage.init(named: "switchList")!.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) - + + buttonSwitch.setImage(UIImage(named: "switchList")!.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) + buttonOrder.setTitle("", for: .normal) buttonOrder.setTitleColor(.systemBlue, for: .normal) - buttonMore.setImage(UIImage.init(named: "more")!.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) - + buttonMore.setImage(UIImage(named: "more")!.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) + // Gradient gradient.startPoint = CGPoint(x: 0, y: 0.50) gradient.endPoint = CGPoint(x: 0, y: 1) viewRichWorkspace.layer.addSublayer(gradient) setGradientColor() - + let tap = UITapGestureRecognizer(target: self, action: #selector(touchUpInsideViewRichWorkspace(_:))) tap.delegate = self viewRichWorkspace?.addGestureRecognizer(tap) - + separator.backgroundColor = NCBrandColor.shared.separator separatorHeightConstraint.constant = 0.5 @@ -74,36 +74,36 @@ class NCSectionHeaderMenu: UICollectionReusableView, UIGestureRecognizerDelegate } textViewColor = NCBrandColor.shared.label } - + override func layoutSublayers(of layer: CALayer) { super.layoutSublayers(of: layer) gradient.frame = viewRichWorkspace.bounds } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) setGradientColor() } - + func setGradientColor() { if traitCollection.userInterfaceStyle == .dark { - gradient.colors = [UIColor.init(white: 0, alpha: 0).cgColor, UIColor.black.cgColor] + gradient.colors = [UIColor(white: 0, alpha: 0).cgColor, UIColor.black.cgColor] } else { - gradient.colors = [UIColor.init(white: 1, alpha: 0).cgColor, UIColor.white.cgColor] + gradient.colors = [UIColor(white: 1, alpha: 0).cgColor, UIColor.white.cgColor] } } - + func setTitleSorted(datasourceTitleButton: String) { - + let title = NSLocalizedString(datasourceTitleButton, comment: "") - let size = title.size(withAttributes:[.font: buttonOrder.titleLabel?.font as Any]) - + let size = title.size(withAttributes: [.font: buttonOrder.titleLabel?.font as Any]) + buttonOrder.setTitle(title, for: .normal) buttonOrderWidthConstraint.constant = size.width + 5 } - + func setStatusButton(count: Int) { - + if count == 0 { buttonSwitch.isEnabled = false buttonOrder.isEnabled = false @@ -114,7 +114,7 @@ class NCSectionHeaderMenu: UICollectionReusableView, UIGestureRecognizerDelegate buttonMore.isEnabled = true } } - + func setRichWorkspaceText(richWorkspaceText: String?) { guard let richWorkspaceText = richWorkspaceText else { return } if richWorkspaceText != self.richWorkspaceText { @@ -122,25 +122,25 @@ class NCSectionHeaderMenu: UICollectionReusableView, UIGestureRecognizerDelegate self.richWorkspaceText = richWorkspaceText } } - + @IBAction func touchUpInsideMore(_ sender: Any) { delegate?.tapMoreHeader(sender: sender) } - + @IBAction func touchUpInsideSwitch(_ sender: Any) { delegate?.tapSwitchHeader(sender: sender) } - + @IBAction func touchUpInsideOrder(_ sender: Any) { delegate?.tapOrderHeader(sender: sender) } - + @objc func touchUpInsideViewRichWorkspace(_ sender: Any) { delegate?.tapRichWorkspace(sender: sender) } } -protocol NCSectionHeaderMenuDelegate { +protocol NCSectionHeaderMenuDelegate: AnyObject { func tapSwitchHeader(sender: Any) func tapMoreHeader(sender: Any) func tapOrderHeader(sender: Any) @@ -156,33 +156,33 @@ extension NCSectionHeaderMenuDelegate { } class NCSectionFooter: UICollectionReusableView { - + @IBOutlet weak var labelSection: UILabel! - + override func awakeFromNib() { super.awakeFromNib() - + self.backgroundColor = UIColor.clear labelSection.textColor = NCBrandColor.shared.gray } - + func setTitleLabel(directories: Int, files: Int, size: Int64) { - + var foldersText = "" var filesText = "" - + if directories > 1 { foldersText = "\(directories) " + NSLocalizedString("_folders_", comment: "") } else if directories == 1 { foldersText = "1 " + NSLocalizedString("_folder_", comment: "") } - + if files > 1 { filesText = "\(files) " + NSLocalizedString("_files_", comment: "") + " " + CCUtility.transformedSize(size) } else if files == 1 { filesText = "1 " + NSLocalizedString("_file_", comment: "") + " " + CCUtility.transformedSize(size) } - + if foldersText == "" { labelSection.text = filesText } else if filesText == "" { diff --git a/iOSClient/Media/Cell/NCGridMediaCell.swift b/iOSClient/Media/Cell/NCGridMediaCell.swift index 92da88272..eb2c9a4a8 100644 --- a/iOSClient/Media/Cell/NCGridMediaCell.swift +++ b/iOSClient/Media/Cell/NCGridMediaCell.swift @@ -29,10 +29,10 @@ class NCGridMediaCell: UICollectionViewCell, NCCellProtocol { @IBOutlet weak var imageVisualEffect: UIVisualEffectView! @IBOutlet weak var imageSelect: UIImageView! @IBOutlet weak var imageStatus: UIImageView! - + private var objectId: String = "" private var user: String = "" - + var date: Date? var filePreviewImageView: UIImageView? { @@ -61,7 +61,7 @@ class NCGridMediaCell: UICollectionViewCell, NCCellProtocol { user = newValue ?? "" } } - + override func awakeFromNib() { super.awakeFromNib() initCell() @@ -71,7 +71,7 @@ class NCGridMediaCell: UICollectionViewCell, NCCellProtocol { super.prepareForReuse() initCell() } - + func initCell() { imageItem.backgroundColor = UIColor.lightGray imageStatus.image = nil @@ -81,7 +81,7 @@ class NCGridMediaCell: UICollectionViewCell, NCCellProtocol { imageVisualEffect.layer.cornerRadius = 6 imageVisualEffect.clipsToBounds = true } - + func selectMode(_ status: Bool) { if status { imageSelect.isHidden = false @@ -90,7 +90,7 @@ class NCGridMediaCell: UICollectionViewCell, NCCellProtocol { imageVisualEffect.isHidden = true } } - + func selected(_ status: Bool) { if status { imageSelect.image = NCBrandColor.cacheImages.checkedYes @@ -102,4 +102,3 @@ class NCGridMediaCell: UICollectionViewCell, NCCellProtocol { } } } - diff --git a/iOSClient/Media/NCMedia.swift b/iOSClient/Media/NCMedia.swift index 29cdda77a..1c92ea5cf 100644 --- a/iOSClient/Media/NCMedia.swift +++ b/iOSClient/Media/NCMedia.swift @@ -25,15 +25,15 @@ import UIKit import NCCommunication class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate { - - @IBOutlet weak var collectionView : UICollectionView! - + + @IBOutlet weak var collectionView: UICollectionView! + private var emptyDataSet: NCEmptyDataSet? private var mediaCommandView: NCMediaCommandView? private var gridLayout: NCGridMediaLayout! internal let appDelegate = UIApplication.shared.delegate as! AppDelegate - + public var metadatas: [tableMetadata] = [] private var account: String = "" @@ -42,57 +42,57 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate { internal var isEditMode = false internal var selectOcId: [String] = [] - + internal var filterClassTypeImage = false internal var filterClassTypeVideo = false - + private let maxImageGrid: CGFloat = 7 private var cellHeigth: CGFloat = 0 private var oldInProgress = false private var newInProgress = false - + private var lastContentOffsetY: CGFloat = 0 private var mediaPath = "" private var livePhoto: Bool = false - + private var timeIntervalSearchNewMedia: TimeInterval = 3.0 private var timerSearchNewMedia: Timer? - + private let insetsTop: CGFloat = 75 - + struct cacheImages { static var cellLivePhotoImage = UIImage() static var cellPlayImage = UIImage() } - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + appDelegate.activeMedia = self - + view.backgroundColor = NCBrandColor.shared.systemBackground - collectionView.register(UINib.init(nibName: "NCGridMediaCell", bundle: nil), forCellWithReuseIdentifier: "gridCell") - + collectionView.register(UINib(nibName: "NCGridMediaCell", bundle: nil), forCellWithReuseIdentifier: "gridCell") + collectionView.alwaysBounceVertical = true - collectionView.contentInset = UIEdgeInsets(top: insetsTop, left: 0, bottom: 50, right: 0); + collectionView.contentInset = UIEdgeInsets(top: insetsTop, left: 0, bottom: 50, right: 0) collectionView.backgroundColor = NCBrandColor.shared.systemBackground - + gridLayout = NCGridMediaLayout() gridLayout.itemForLine = CGFloat(min(CCUtility.getMediaWidthImage(), 5)) gridLayout.sectionHeadersPinToVisibleBounds = true collectionView.collectionViewLayout = gridLayout - + // Empty - emptyDataSet = NCEmptyDataSet.init(view: collectionView, offset: 0, delegate: self) - + emptyDataSet = NCEmptyDataSet(view: collectionView, offset: 0, delegate: self) + // Notification NotificationCenter.default.addObserver(self, selector: #selector(initialize), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil) - + mediaCommandView = Bundle.main.loadNibNamed("NCMediaCommandView", owner: self, options: nil)?.first as? NCMediaCommandView self.view.addSubview(mediaCommandView!) mediaCommandView?.mediaView = self @@ -105,60 +105,60 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate { mediaCommandView?.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true mediaCommandView?.heightAnchor.constraint(equalToConstant: 150).isActive = true self.updateMediaControlVisibility() - + collectionView.prefetchDataSource = self - + cacheImages.cellLivePhotoImage = NCUtility.shared.loadImage(named: "livephoto", color: .white) cacheImages.cellPlayImage = NCUtility.shared.loadImage(named: "play.fill", color: .white) } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + appDelegate.activeViewController = self - + // 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) NotificationCenter.default.addObserver(self, selector: #selector(renameFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterRenameFile), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(uploadedFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile), object: nil) - + // hide nagigation controller navigationController?.navigationBar.prefersLargeTitles = true navigationController?.setNavigationBarHidden(true, animated: false) - - self.reloadDataSourceWithCompletion { (_) in + + self.reloadDataSourceWithCompletion { _ in self.timerSearchNewMedia?.invalidate() self.timerSearchNewMedia = Timer.scheduledTimer(timeInterval: self.timeIntervalSearchNewMedia, target: self, selector: #selector(self.searchNewMediaTimer), userInfo: nil, repeats: false) } } - + 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.notificationCenterMoveFile), 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.notificationCenterUploadedFile), object: nil) } - + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) - + coordinator.animate(alongsideTransition: nil) { _ in self.reloadDataThenPerform { } } } - + override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } - - //MARK: - NotificationCenter + + // MARK: - NotificationCenter @objc func initialize() { - - self.reloadDataSourceWithCompletion { (_) in + + self.reloadDataSourceWithCompletion { _ in self.timerSearchNewMedia?.invalidate() self.timerSearchNewMedia = Timer.scheduledTimer(timeInterval: self.timeIntervalSearchNewMedia, target: self, selector: #selector(self.searchNewMediaTimer), userInfo: nil, repeats: false) DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { @@ -166,82 +166,82 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate { } } } - + @objc func deleteFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String { - + let indexes = self.metadatas.indices.filter { self.metadatas[$0].ocId == ocId } let metadatas = self.metadatas.filter { $0.ocId != ocId } self.metadatas = metadatas - + if self.metadatas.count == 0 { collectionView?.reloadData() } else if let row = indexes.first { let indexPath = IndexPath(row: row, section: 0) collectionView?.deleteItems(at: [indexPath]) } - + self.updateMediaControlVisibility() } } } - + @objc func moveFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - + if metadata.account == appDelegate.account { - + let indexes = self.metadatas.indices.filter { self.metadatas[$0].ocId == metadata.ocId } let metadatas = self.metadatas.filter { $0.ocId != metadata.ocId } self.metadatas = metadatas - + if self.metadatas.count == 0 { collectionView?.reloadData() } else if let row = indexes.first { let indexPath = IndexPath(row: row, section: 0) collectionView?.deleteItems(at: [indexPath]) } - + self.updateMediaControlVisibility() } } } } - + @objc func renameFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - + if metadata.account == appDelegate.account { - self.reloadDataSourceWithCompletion { (_) in } + self.reloadDataSourceWithCompletion { _ in } } } } } - + @objc func uploadedFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId), let errorCode = userInfo["errorCode"] as? Int { if errorCode == 0 && metadata.account == appDelegate.account { - self.reloadDataSourceWithCompletion { (_) in } + self.reloadDataSourceWithCompletion { _ in } } } } } - - //MARK: - Command - + + // 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 { if cell.date != nil { mediaCommandView?.title.text = CCUtility.getTitleSectionDate(cell.date) @@ -249,14 +249,14 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate { } } } - + @objc func zoomOutGrid() { UIView.animate(withDuration: 0.0, animations: { - if(self.gridLayout.itemForLine + 1 < self.maxImageGrid) { + if self.gridLayout.itemForLine + 1 < self.maxImageGrid { self.gridLayout.itemForLine += 1 self.mediaCommandView?.zoomInButton.isEnabled = true } - if(self.gridLayout.itemForLine == self.maxImageGrid - 1) { + if self.gridLayout.itemForLine == self.maxImageGrid - 1 { self.mediaCommandView?.zoomOutButton.isEnabled = false } @@ -267,11 +267,11 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate { @objc func zoomInGrid() { UIView.animate(withDuration: 0.0, animations: { - if(self.gridLayout.itemForLine - 1 > 0) { + if self.gridLayout.itemForLine - 1 > 0 { self.gridLayout.itemForLine -= 1 self.mediaCommandView?.zoomOutButton.isEnabled = true } - if(self.gridLayout.itemForLine == 1) { + if self.gridLayout.itemForLine == 1 { self.mediaCommandView?.zoomInButton.isEnabled = false } @@ -279,28 +279,28 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate { CCUtility.setMediaWidthImage(Int(self.gridLayout.itemForLine)) }) } - + @objc func openMenuButtonMore(_ sender: Any) { toggleMenu() } - + // MARK: Select Path - + func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) { if serverUrl != nil { let path = CCUtility.returnPathfromServerUrl(serverUrl, urlBase: appDelegate.urlBase, account: appDelegate.account) ?? "" NCManageDatabase.shared.setAccountMediaPath(path, account: appDelegate.account) - reloadDataSourceWithCompletion { (_) in + reloadDataSourceWithCompletion { _ in self.searchNewMedia() } } } - + // MARK: - Empty - + func emptyDataSetView(_ view: NCEmptyView) { - - view.emptyImage.image = UIImage.init(named: "media")?.image(color: .gray, size: UIScreen.main.bounds.width) + + view.emptyImage.image = UIImage(named: "media")?.image(color: .gray, size: UIScreen.main.bounds.width) if oldInProgress || newInProgress { view.emptyTitle.text = NSLocalizedString("_search_in_progress_", comment: "") } else { @@ -313,11 +313,11 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate { // MARK: - Collection View extension NCMedia: UICollectionViewDelegate { - + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - + let metadata = metadatas[indexPath.row] - + if isEditMode { if let index = selectOcId.firstIndex(of: metadata.ocId) { selectOcId.remove(at: index) @@ -327,38 +327,38 @@ extension NCMedia: UICollectionViewDelegate { if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) { collectionView.reloadItems(at: [indexPath]) } - + } else { - + // ACTIVE SERVERURL appDelegate.activeServerUrl = metadata.serverUrl let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as? NCGridMediaCell NCViewer.shared.view(viewController: self, metadata: metadata, metadatas: metadatas, imageIcon: cell?.imageItem.image) } } - + @available(iOS 13.0, *) func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { - + let metadata = metadatas[indexPath.row] let identifier = indexPath as NSCopying if let cell = collectionView.cellForItem(at: indexPath) as? NCGridMediaCell { - + let image = cell.imageItem.image return UIContextMenuConfiguration(identifier: identifier, previewProvider: { - + return NCViewerProviderContextMenu(metadata: metadata, image: image) - - }, actionProvider: { suggestedActions in - + + }, actionProvider: { _ in + return NCFunctionCenter.shared.contextMenuConfiguration(ocId: metadata.ocId, viewController: self, enableDeleteLocal: false, enableViewInFolder: true, image: image) }) } else { return nil } } - + @available(iOS 13.0, *) func collectionView(_ collectionView: UICollectionView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) { animator.addCompletion { @@ -372,19 +372,19 @@ extension NCMedia: UICollectionViewDelegate { extension NCMedia: UICollectionViewDataSourcePrefetching { func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) { - //print("[LOG] n. " + String(indexPaths.count)) + // print("[LOG] n. " + String(indexPaths.count)) } } extension NCMedia: UICollectionViewDataSource { - + func reloadDataThenPerform(_ closure: @escaping (() -> Void)) { CATransaction.begin() CATransaction.setCompletionBlock(closure) collectionView?.reloadData() CATransaction.commit() } - + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { emptyDataSet?.numberOfItemsInSection(metadatas.count, section: section) return metadatas.count @@ -393,16 +393,16 @@ extension NCMedia: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { if indexPath.row < self.metadatas.count { let metadata = self.metadatas[indexPath.row] - + if FileManager().fileExists(atPath: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) { (cell as! NCGridMediaCell).imageItem.backgroundColor = nil - (cell as! NCGridMediaCell).imageItem.image = UIImage.init(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) + (cell as! NCGridMediaCell).imageItem.image = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) } else { NCOperationQueue.shared.downloadThumbnail(metadata: metadata, placeholder: false, cell: cell, view: collectionView) } } } - + func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { if !collectionView.indexPathsForVisibleItems.contains(indexPath) && indexPath.row < metadatas.count { let metadata = metadatas[indexPath.row] @@ -411,12 +411,12 @@ extension NCMedia: UICollectionViewDataSource { } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - + if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) && indexPath.row < metadatas.count { - + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as! NCGridMediaCell let metadata = metadatas[indexPath.row] - + self.cellHeigth = cell.frame.size.height cell.date = metadata.date as Date @@ -428,7 +428,7 @@ extension NCMedia: UICollectionViewDataSource { } else if metadata.livePhoto && livePhoto { cell.imageStatus.image = cacheImages.cellLivePhotoImage } - + if isEditMode { cell.selectMode(true) if selectOcId.contains(metadata.ocId) { @@ -439,22 +439,22 @@ extension NCMedia: UICollectionViewDataSource { } else { cell.selectMode(false) } - + return cell - + } else { - + return collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as! NCGridMediaCell } } } 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) } @@ -465,24 +465,24 @@ extension NCMedia { // MARK: - Datasource @objc func reloadDataSourceWithCompletion(_ completion: @escaping (_ metadatas: [tableMetadata]) -> Void) { - + if appDelegate.account == "" { return } - + if account != appDelegate.account { self.metadatas = [] account = appDelegate.account collectionView?.reloadData() } - + livePhoto = CCUtility.getLivePhoto() - + if let activeAccount = NCManageDatabase.shared.getActiveAccount() { self.mediaPath = activeAccount.mediaPath } let startServerUrl = NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) + mediaPath - + predicateDefault = NSPredicate(format: "account == %@ AND serverUrl BEGINSWITH %@ AND (classFile == %@ OR classFile == %@) AND NOT (session CONTAINS[c] 'upload')", appDelegate.account, startServerUrl, NCCommunicationCommon.typeClassFile.image.rawValue, NCCommunicationCommon.typeClassFile.video.rawValue) - + if filterClassTypeImage { predicate = NSPredicate(format: "account == %@ AND serverUrl BEGINSWITH %@ AND classFile == %@ AND NOT (session CONTAINS[c] 'upload')", appDelegate.account, startServerUrl, NCCommunicationCommon.typeClassFile.video.rawValue) } else if filterClassTypeVideo { @@ -490,14 +490,14 @@ extension NCMedia { } else { predicate = predicateDefault } - + guard var predicateForGetMetadatasMedia = predicate else { return } - + if livePhoto { let predicateLivePhoto = NSPredicate(format: "!(ext == 'mov' AND livePhoto == true)") - predicateForGetMetadatasMedia = NSCompoundPredicate.init(andPredicateWithSubpredicates:[predicateForGetMetadatasMedia, predicateLivePhoto]) + predicateForGetMetadatasMedia = NSCompoundPredicate(andPredicateWithSubpredicates: [predicateForGetMetadatasMedia, predicateLivePhoto]) } - + DispatchQueue.global().async { self.metadatas = NCManageDatabase.shared.getMetadatasMedia(predicate: predicateForGetMetadatasMedia, sort: CCUtility.getMediaSortDate()) DispatchQueue.main.sync { @@ -509,7 +509,7 @@ extension NCMedia { } } } - + func updateMediaControlVisibility() { if self.metadatas.count == 0 { if !self.filterClassTypeImage && !self.filterClassTypeVideo { @@ -524,13 +524,12 @@ extension NCMedia { self.mediaCommandView?.isHidden = false } } - + // MARK: - Search media private func searchOldMedia(value: Int = -30, limit: Int = 300) { - - if oldInProgress { return } - else { oldInProgress = true } + + if oldInProgress { return } else { oldInProgress = true } collectionView.reloadData() var lessDate = Date() @@ -539,34 +538,34 @@ extension NCMedia { 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)! + greaterDate = Calendar.current.date(byAdding: .day, value: value, to: lessDate)! } - + let height = self.tabBarController?.tabBar.frame.size.height ?? 0 NCUtility.shared.startActivityIndicator(backgroundView: self.view, blurEffect: false, bottom: height + 50, style: .gray) - NCCommunication.shared.searchMedia(path: mediaPath, lessDate: lessDate, greaterDate: greaterDate, elementDate: "d:getlastmodified/", limit: limit, showHiddenFiles: CCUtility.getShowHiddenFiles(), timeout: 120) { (account, files, errorCode, errorDescription) in - + NCCommunication.shared.searchMedia(path: mediaPath, lessDate: lessDate, greaterDate: greaterDate, elementDate: "d:getlastmodified/", limit: limit, showHiddenFiles: CCUtility.getShowHiddenFiles(), timeout: 120) { account, files, errorCode, errorDescription in + self.oldInProgress = false NCUtility.shared.stopActivityIndicator() self.collectionView.reloadData() if errorCode == 0 && account == self.appDelegate.account { if files.count > 0 { - NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: false, account: self.appDelegate.account) { (_, _, metadatas) in + NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: false, account: self.appDelegate.account) { _, _, metadatas in let predicateDate = NSPredicate(format: "date > %@ AND date < %@", greaterDate as NSDate, lessDate as NSDate) - let predicateResult = NSCompoundPredicate.init(andPredicateWithSubpredicates:[predicateDate, self.predicateDefault!]) + let predicateResult = NSCompoundPredicate(andPredicateWithSubpredicates: [predicateDate, self.predicateDefault!]) let metadatasResult = NCManageDatabase.shared.getMetadatas(predicate: predicateResult) let metadatasChanged = NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult, addCompareLivePhoto: false) if metadatasChanged.metadatasUpdate.count == 0 { self.researchOldMedia(value: value, limit: limit, withElseReloadDataSource: true) } else { - self.reloadDataSourceWithCompletion { (_) in } + self.reloadDataSourceWithCompletion { _ in } } } } else { @@ -577,9 +576,9 @@ extension NCMedia { } } } - - private func researchOldMedia(value: Int , limit: Int, withElseReloadDataSource: Bool) { - + + private func researchOldMedia(value: Int, limit: Int, withElseReloadDataSource: Bool) { + if value == -30 { searchOldMedia(value: -90) } else if value == -90 { @@ -590,23 +589,22 @@ extension NCMedia { searchOldMedia(value: -999, limit: 0) } else { if withElseReloadDataSource { - self.reloadDataSourceWithCompletion { (_) in } + self.reloadDataSourceWithCompletion { _ in } } } } - + @objc func searchNewMediaTimer() { self.searchNewMedia() } - + @objc func searchNewMedia() { - - if newInProgress { return } - else { + + 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 } @@ -626,22 +624,22 @@ extension NCMedia { } } } - + reloadDataThenPerform { - NCCommunication.shared.searchMedia(path: self.mediaPath, lessDate: lessDate, greaterDate: greaterDate, elementDate: "d:getlastmodified/", limit: limit, showHiddenFiles: CCUtility.getShowHiddenFiles(), timeout: 120) { (account, files, errorCode, errorDescription) in - + NCCommunication.shared.searchMedia(path: self.mediaPath, lessDate: lessDate, greaterDate: greaterDate, elementDate: "d:getlastmodified/", limit: limit, showHiddenFiles: CCUtility.getShowHiddenFiles(), timeout: 120) { account, files, errorCode, errorDescription in + self.newInProgress = false self.mediaCommandView?.activityIndicator.stopAnimating() - + if errorCode == 0 && account == self.appDelegate.account && files.count > 0 { - NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: false, account: account) { (_, _, metadatas) in + NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: false, account: account) { _, _, metadatas in let predicate = NSPredicate(format: "date > %@ AND date < %@", greaterDate as NSDate, lessDate as NSDate) - let predicateResult = NSCompoundPredicate.init(andPredicateWithSubpredicates:[predicate, self.predicate!]) + let predicateResult = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, self.predicate!]) let metadatasResult = NCManageDatabase.shared.getMetadatas(predicate: predicateResult) let updateMetadatas = NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult, addCompareLivePhoto: false) if updateMetadatas.metadatasUpdate.count > 0 || updateMetadatas.metadatasDelete.count > 0 { - self.reloadDataSourceWithCompletion { (_) in } + self.reloadDataSourceWithCompletion { _ in } } } } else if errorCode == 0 && files.count == 0 && self.metadatas.count == 0 { @@ -657,41 +655,41 @@ extension NCMedia { // MARK: - ScrollView extension NCMedia: UIScrollViewDelegate { - + func scrollViewDidScroll(_ scrollView: UIScrollView) { - + if lastContentOffsetY == 0 || lastContentOffsetY + cellHeigth/2 <= scrollView.contentOffset.y || lastContentOffsetY - cellHeigth/2 >= scrollView.contentOffset.y { mediaCommandTitle() 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)) { + + if scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height) { searchOldMedia() } } } - + 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)) { + + if scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height) { searchOldMedia() } } - + func scrollViewDidScrollToTop(_ scrollView: UIScrollView) { let y = view.safeAreaInsets.top scrollView.contentOffset.y = -(insetsTop + y) @@ -701,7 +699,7 @@ extension NCMedia: UIScrollViewDelegate { // MARK: - Media Command View class NCMediaCommandView: UIView { - + @IBOutlet weak var moreView: UIVisualEffectView! @IBOutlet weak var gridSwitchButton: UIButton! @IBOutlet weak var separatorView: UIView! @@ -710,12 +708,12 @@ class NCMediaCommandView: UIView { @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! + @IBOutlet weak var title: UILabel! + @IBOutlet weak var activityIndicator: UIActivityIndicatorView! - var mediaView:NCMedia? + var mediaView: NCMedia? private let gradient: CAGradientLayer = CAGradientLayer() - + override func awakeFromNib() { moreView.layer.cornerRadius = 20 moreView.layer.masksToBounds = true @@ -724,12 +722,12 @@ class NCMediaCommandView: UIView { gradient.frame = bounds gradient.startPoint = CGPoint(x: 0, y: 0.50) gradient.endPoint = CGPoint(x: 0, y: 0.9) - gradient.colors = [UIColor.black.withAlphaComponent(0.4).cgColor , UIColor.clear.cgColor] + gradient.colors = [UIColor.black.withAlphaComponent(0.4).cgColor, UIColor.clear.cgColor] layer.insertSublayer(gradient, at: 0) - moreButton.setImage(UIImage.init(named: "more")!.image(color: .white, size: 25), for: .normal) + 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) { @@ -745,25 +743,25 @@ class NCMediaCommandView: UIView { } } } - + @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) { + if collapse { self.buttonControlWidthConstraint.constant = 40 UIView.animate(withDuration: 0.25) { self.zoomOutButton.isHidden = true @@ -783,11 +781,11 @@ class NCMediaCommandView: UIView { } } } - + 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 @@ -797,36 +795,36 @@ class NCMediaCommandView: UIView { // MARK: - Media Grid Layout class NCGridMediaLayout: UICollectionViewFlowLayout { - + var marginLeftRight: CGFloat = 6 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) + 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) } @@ -834,9 +832,8 @@ class NCGridMediaLayout: UICollectionViewFlowLayout { super.itemSize = newValue } } - + override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint { return proposedContentOffset } } - diff --git a/iOSClient/Menu/AppDelegate+Menu.swift b/iOSClient/Menu/AppDelegate+Menu.swift index 6779297ad..6c693c466 100644 --- a/iOSClient/Menu/AppDelegate+Menu.swift +++ b/iOSClient/Menu/AppDelegate+Menu.swift @@ -28,25 +28,23 @@ import FloatingPanel import NCCommunication extension AppDelegate { - + func toggleMenu(viewController: UIViewController) { - + var actions: [NCMenuAction] = [] - + let appDelegate = UIApplication.shared.delegate as! AppDelegate let directEditingCreators = NCManageDatabase.shared.getDirectEditingCreators(account: appDelegate.account) let isEncrypted = CCUtility.isFolderEncrypted(appDelegate.activeServerUrl, e2eEncrypted: false, account: appDelegate.account, urlBase: appDelegate.urlBase) let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, appDelegate.activeServerUrl)) let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor) - + actions.append( NCMenuAction( - title: NSLocalizedString("_upload_photos_videos_", comment: ""), icon: UIImage(named: "file_photo")!.image(color: NCBrandColor.shared.gray, size: 50), action: { menuAction in - NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { (hasPermission) in + title: NSLocalizedString("_upload_photos_videos_", comment: ""), icon: UIImage(named: "file_photo")!.image(color: NCBrandColor.shared.gray, size: 50), action: { _ in + NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { hasPermission in if hasPermission { - if let viewController = appDelegate.window?.rootViewController { - NCPhotosPickerViewController.init(viewController: viewController, maxSelectedAssets: 0, singleSelectedMode: false) - } + NCPhotosPickerViewController.init(viewController: viewController, maxSelectedAssets: 0, singleSelectedMode: false) } } } @@ -55,9 +53,9 @@ extension AppDelegate { actions.append( NCMenuAction( - title: NSLocalizedString("_upload_file_", comment: ""), icon: UIImage(named: "file")!.image(color: NCBrandColor.shared.gray, size: 50), action: { menuAction in + title: NSLocalizedString("_upload_file_", comment: ""), icon: UIImage(named: "file")!.image(color: NCBrandColor.shared.gray, size: 50), action: { _ in if let tabBarController = self.window?.rootViewController as? UITabBarController { - self.documentPickerViewController = NCDocumentPickerViewController.init(tabBarController: tabBarController) + self.documentPickerViewController = NCDocumentPickerViewController(tabBarController: tabBarController) } } ) @@ -66,12 +64,12 @@ extension AppDelegate { if NCCommunication.shared.isNetworkReachable() && directEditingCreators != nil && directEditingCreators!.contains(where: { $0.editor == NCGlobal.shared.editorText}) && !isEncrypted { let directEditingCreator = directEditingCreators!.first(where: { $0.editor == NCGlobal.shared.editorText})! actions.append( - NCMenuAction(title: NSLocalizedString("_create_nextcloudtext_document_", comment: ""), icon: UIImage(named: "file_txt")!.image(color: NCBrandColor.shared.gray, size: 50), action: { menuAction in + NCMenuAction(title: NSLocalizedString("_create_nextcloudtext_document_", comment: ""), icon: UIImage(named: "file_txt")!.image(color: NCBrandColor.shared.gray, size: 50), action: { _ in guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController() else { return } navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet - + let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments viewController.editorId = NCGlobal.shared.editorText viewController.creatorId = directEditingCreator.identifier @@ -82,12 +80,12 @@ extension AppDelegate { appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil) }) ) - } - + } + if #available(iOS 13.0, *) { actions.append( NCMenuAction( - title: NSLocalizedString("_scans_document_", comment: ""), icon: NCUtility.shared.loadImage(named: "doc.text.viewfinder"), action: { menuAction in + title: NSLocalizedString("_scans_document_", comment: ""), icon: NCUtility.shared.loadImage(named: "doc.text.viewfinder"), action: { _ in if let viewController = appDelegate.window?.rootViewController { NCCreateScanDocument.shared.openScannerDocument(viewController: viewController) } @@ -95,21 +93,21 @@ extension AppDelegate { ) ) } - + actions.append( NCMenuAction( - title: NSLocalizedString("_create_voice_memo_", comment: ""), icon: UIImage(named: "microphone")!.image(color: NCBrandColor.shared.gray, size: 50), action: { menuAction in - - NCAskAuthorization.shared.askAuthorizationAudioRecord(viewController: viewController) { (hasPermission) in + title: NSLocalizedString("_create_voice_memo_", comment: ""), icon: UIImage(named: "microphone")!.image(color: NCBrandColor.shared.gray, size: 50), action: { _ in + + NCAskAuthorization.shared.askAuthorizationAudioRecord(viewController: viewController) { hasPermission in if hasPermission { let fileName = CCUtility.createFileNameDate(NSLocalizedString("_voice_memo_filename_", comment: ""), extension: "m4a")! let viewController = UIStoryboard(name: "NCAudioRecorderViewController", bundle: nil).instantiateInitialViewController() as! NCAudioRecorderViewController - + viewController.delegate = self viewController.createRecorder(fileName: fileName) viewController.modalTransitionStyle = .crossDissolve viewController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext - + appDelegate.window?.rootViewController?.present(viewController, animated: true, completion: nil) } } @@ -119,27 +117,27 @@ extension AppDelegate { actions.append( NCMenuAction(title: NSLocalizedString("_create_folder_", comment: ""), - icon: UIImage(named: "folder")!.image(color: NCBrandColor.shared.brandElement, size: 50), action: { menuAction in - + icon: UIImage(named: "folder")!.image(color: NCBrandColor.shared.brandElement, size: 50), action: { _ in + if appDelegate.activeServerUrl == "" { return } - + let alertController = UIAlertController(title: NSLocalizedString("_create_folder_on_", comment: ""), message: nil, preferredStyle: .alert) - - alertController.addTextField { (textField) in + + alertController.addTextField { textField in textField.autocapitalizationType = UITextAutocapitalizationType.sentences } - + let cancelAction = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil) - let okAction = UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { action in + let okAction = UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in if let fileNameFolder = alertController.textFields?.first?.text { - NCNetworking.shared.createFolder(fileName: fileNameFolder, serverUrl: appDelegate.activeServerUrl, account: appDelegate.account, urlBase: appDelegate.urlBase, overwrite: false) { (errorCode, errorDescription) in + NCNetworking.shared.createFolder(fileName: fileNameFolder, serverUrl: appDelegate.activeServerUrl, account: appDelegate.account, urlBase: appDelegate.urlBase, overwrite: false) { errorCode, errorDescription in if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } } } }) - + alertController.addAction(cancelAction) alertController.addAction(okAction) @@ -151,7 +149,7 @@ extension AppDelegate { if serverVersionMajor >= NCGlobal.shared.nextcloudVersion18 && directory?.richWorkspace == nil && !isEncrypted && NCCommunication.shared.isNetworkReachable() { actions.append( NCMenuAction( - title: NSLocalizedString("_add_folder_info_", comment: ""), icon: UIImage(named: "addFolderInfo")!.image(color: NCBrandColor.shared.gray, size: 50), action: { menuAction in + title: NSLocalizedString("_add_folder_info_", comment: ""), icon: UIImage(named: "addFolderInfo")!.image(color: NCBrandColor.shared.gray, size: 50), action: { _ in let richWorkspaceCommon = NCRichWorkspaceCommon() if let viewController = self.activeViewController { if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView LIKE[c] %@", appDelegate.account, appDelegate.activeServerUrl, NCGlobal.shared.fileNameRichWorkspace.lowercased())) == nil { @@ -164,12 +162,12 @@ extension AppDelegate { ) ) } - + if NCCommunication.shared.isNetworkReachable() && directEditingCreators != nil && directEditingCreators!.contains(where: { $0.editor == NCGlobal.shared.editorOnlyoffice && $0.identifier == NCGlobal.shared.onlyofficeDocx}) && !isEncrypted { let directEditingCreator = directEditingCreators!.first(where: { $0.editor == NCGlobal.shared.editorOnlyoffice && $0.identifier == NCGlobal.shared.onlyofficeDocx})! actions.append( NCMenuAction( - title: NSLocalizedString("_create_new_document_", comment: ""), icon: UIImage(named: "create_file_document")!, action: { menuAction in + title: NSLocalizedString("_create_new_document_", comment: ""), icon: UIImage(named: "create_file_document")!, action: { _ in guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController() else { return } @@ -187,12 +185,12 @@ extension AppDelegate { ) ) } - + if NCCommunication.shared.isNetworkReachable() && directEditingCreators != nil && directEditingCreators!.contains(where: { $0.editor == NCGlobal.shared.editorOnlyoffice && $0.identifier == NCGlobal.shared.onlyofficeXlsx}) && !isEncrypted { let directEditingCreator = directEditingCreators!.first(where: { $0.editor == NCGlobal.shared.editorOnlyoffice && $0.identifier == NCGlobal.shared.onlyofficeXlsx})! actions.append( NCMenuAction( - title: NSLocalizedString("_create_new_spreadsheet_", comment: ""), icon: UIImage(named: "create_file_xls")!, action: { menuAction in + title: NSLocalizedString("_create_new_spreadsheet_", comment: ""), icon: UIImage(named: "create_file_xls")!, action: { _ in guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController() else { return } @@ -210,12 +208,12 @@ extension AppDelegate { ) ) } - + if NCCommunication.shared.isNetworkReachable() && directEditingCreators != nil && directEditingCreators!.contains(where: { $0.editor == NCGlobal.shared.editorOnlyoffice && $0.identifier == NCGlobal.shared.onlyofficePptx}) && !isEncrypted { let directEditingCreator = directEditingCreators!.first(where: { $0.editor == NCGlobal.shared.editorOnlyoffice && $0.identifier == NCGlobal.shared.onlyofficePptx})! actions.append( NCMenuAction( - title: NSLocalizedString("_create_new_presentation_", comment: ""), icon: UIImage(named: "create_file_ppt")!, action: { menuAction in + title: NSLocalizedString("_create_new_presentation_", comment: ""), icon: UIImage(named: "create_file_ppt")!, action: { _ in guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController() else { return } @@ -233,12 +231,12 @@ extension AppDelegate { ) ) } - + if let richdocumentsMimetypes = NCManageDatabase.shared.getCapabilitiesServerArray(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesRichdocumentsMimetypes) { if richdocumentsMimetypes.count > 0 && NCCommunication.shared.isNetworkReachable() && !isEncrypted { actions.append( NCMenuAction( - title: NSLocalizedString("_create_new_document_", comment: ""), icon: UIImage(named: "create_file_document")!, action: { menuAction in + title: NSLocalizedString("_create_new_document_", comment: ""), icon: UIImage(named: "create_file_document")!, action: { _ in guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController() else { return } @@ -257,7 +255,7 @@ extension AppDelegate { actions.append( NCMenuAction( - title: NSLocalizedString("_create_new_spreadsheet_", comment: ""), icon: UIImage(named: "create_file_xls")!, action: { menuAction in + title: NSLocalizedString("_create_new_spreadsheet_", comment: ""), icon: UIImage(named: "create_file_xls")!, action: { _ in guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController() else { return } @@ -273,10 +271,10 @@ extension AppDelegate { } ) ) - + actions.append( NCMenuAction( - title: NSLocalizedString("_create_new_presentation_", comment: ""), icon: UIImage(named: "create_file_ppt")!, action: { menuAction in + title: NSLocalizedString("_create_new_presentation_", comment: ""), icon: UIImage(named: "create_file_ppt")!, action: { _ in guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController() else { return } @@ -294,7 +292,7 @@ extension AppDelegate { ) } } - + viewController.presentMenu(with: actions) } } diff --git a/iOSClient/Menu/NCCollectionViewCommon+Menu.swift b/iOSClient/Menu/NCCollectionViewCommon+Menu.swift index 5cce76d05..e4cfb8b0b 100644 --- a/iOSClient/Menu/NCCollectionViewCommon+Menu.swift +++ b/iOSClient/Menu/NCCollectionViewCommon+Menu.swift @@ -39,7 +39,7 @@ extension NCCollectionViewCommon { let isFolderEncrypted = CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase) let serverUrlHome = NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) var isOffline = false - + var titleDelete = NSLocalizedString("_delete_", comment: "") if NCManageDatabase.shared.isMetadataShareOrMounted(metadata: metadata, metadataFolder: metadataFolder) { titleDelete = NSLocalizedString("_leave_share_", comment: "") @@ -48,7 +48,7 @@ extension NCCollectionViewCommon { } else { titleDelete = NSLocalizedString("_delete_file_", comment: "") } - + if let metadataFolder = metadataFolder { let isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !metadataFolder.permissions.contains(NCGlobal.shared.permissionShared) let isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !metadataFolder.permissions.contains(NCGlobal.shared.permissionMounted) @@ -56,7 +56,7 @@ extension NCCollectionViewCommon { titleDelete = NSLocalizedString("_leave_share_", comment: "") } } - + if metadata.directory { if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, serverUrl)) { isOffline = directory.offline @@ -66,12 +66,12 @@ extension NCCollectionViewCommon { isOffline = localFile.offline } } - + let editors = NCUtility.shared.isDirectEditing(account: metadata.account, contentType: metadata.contentType) let isRichDocument = NCUtility.shared.isRichDocument(metadata) var iconHeader: UIImage! - + if imageIcon != nil { iconHeader = imageIcon! } else { @@ -81,7 +81,7 @@ extension NCCollectionViewCommon { iconHeader = NCBrandColor.cacheImages.file } } - + actions.append( NCMenuAction( title: metadata.fileNameView, @@ -97,8 +97,8 @@ extension NCCollectionViewCommon { NCMenuAction( title: metadata.favorite ? NSLocalizedString("_remove_favorites_", comment: "") : NSLocalizedString("_add_favorites_", comment: ""), icon: NCUtility.shared.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite), - action: { menuAction in - NCNetworking.shared.favoriteMetadata(metadata) { (errorCode, errorDescription) in + action: { _ in + NCNetworking.shared.favoriteMetadata(metadata) { errorCode, errorDescription in if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } @@ -106,7 +106,7 @@ extension NCCollectionViewCommon { } ) ) - + // // DETAIL // @@ -115,13 +115,13 @@ extension NCCollectionViewCommon { NCMenuAction( title: NSLocalizedString("_details_", comment: ""), icon: NCUtility.shared.loadImage(named: "info"), - action: { menuAction in - NCFunctionCenter.shared.openShare(ViewController: self, metadata: metadata, indexPage: .activity) + action: { _ in + NCFunctionCenter.shared.openShare(viewController: self, metadata: metadata, indexPage: .activity) } ) ) } - + // // OFFLINE // @@ -130,7 +130,7 @@ extension NCCollectionViewCommon { NCMenuAction( title: isOffline ? NSLocalizedString("_remove_available_offline_", comment: "") : NSLocalizedString("_set_available_offline_", comment: ""), icon: NCUtility.shared.loadImage(named: "tray.and.arrow.down"), - action: { menuAction in + action: { _ in if isOffline { if metadata.directory { NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, offline: false, account: self.appDelegate.account) @@ -142,9 +142,9 @@ extension NCCollectionViewCommon { NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, offline: true, account: self.appDelegate.account) NCOperationQueue.shared.synchronizationMetadata(metadata, selector: NCGlobal.shared.selectorDownloadAllFile) } else { - NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadOffline) { (_) in } + 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 } + NCNetworking.shared.download(metadata: metadataLivePhoto, selector: NCGlobal.shared.selectorLoadOffline) { _ in } } } } @@ -153,16 +153,16 @@ extension NCCollectionViewCommon { ) ) } - + // // OPEN with external editor // - if metadata.classFile == NCCommunicationCommon.typeClassFile.document.rawValue && editors.contains(NCGlobal.shared.editorText) && ((editors.contains(NCGlobal.shared.editorOnlyoffice) || isRichDocument)) { - + if metadata.classFile == NCCommunicationCommon.typeClassFile.document.rawValue && editors.contains(NCGlobal.shared.editorText) && ((editors.contains(NCGlobal.shared.editorOnlyoffice) || isRichDocument)) { + var editor = "" var title = "" var icon: UIImage? - + if editors.contains(NCGlobal.shared.editorOnlyoffice) { editor = NCGlobal.shared.editorOnlyoffice title = NSLocalizedString("_open_in_onlyoffice_", comment: "") @@ -172,20 +172,20 @@ extension NCCollectionViewCommon { title = NSLocalizedString("_open_in_collabora_", comment: "") icon = NCUtility.shared.loadImage(named: "collabora") } - + if editor != "" { actions.append( NCMenuAction( title: title, icon: icon!, - action: { menuAction in + action: { _ in NCViewer.shared.view(viewController: self, metadata: metadata, metadatas: [metadata], imageIcon: imageIcon, editor: editor, isRichDocument: isRichDocument) } ) ) } } - + // // OPEN IN // @@ -195,12 +195,18 @@ extension NCCollectionViewCommon { title: NSLocalizedString("_open_in_", comment: ""), icon: NCUtility.shared.loadImage(named: "square.and.arrow.up"), action: { menuAction in - NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorOpenIn) + if self is NCFileViewInFolder { + self.dismiss(animated: true) { + NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorOpenIn) + } + } else { + NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorOpenIn) + } } ) ) } - + // // PRINT // @@ -209,13 +215,13 @@ extension NCCollectionViewCommon { NCMenuAction( title: NSLocalizedString("_print_", comment: ""), icon: NCUtility.shared.loadImage(named: "printer"), - action: { menuAction in + action: { _ in NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorPrint) } ) ) } - + // // SAVE // @@ -227,12 +233,12 @@ extension NCCollectionViewCommon { title = NSLocalizedString("_livephoto_save_", comment: "") icon = NCUtility.shared.loadImage(named: "livephoto") } - + actions.append( NCMenuAction( title: title, icon: icon, - action: { menuAction in + action: { _ in if metadataMOV != nil { NCFunctionCenter.shared.saveLivePhoto(metadata: metadata, metadataMOV: metadataMOV!) } else { @@ -246,24 +252,24 @@ extension NCCollectionViewCommon { ) ) } - + // // SAVE AS SCAN // if #available(iOS 13.0, *) { - if (metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue && metadata.contentType != "image/svg+xml") { + if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue && metadata.contentType != "image/svg+xml" { actions.append( NCMenuAction( title: NSLocalizedString("_save_as_scan_", comment: ""), icon: NCUtility.shared.loadImage(named: "viewfinder.circle"), - action: { menuAction in + action: { _ in NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorSaveAsScan) } ) ) } } - + // // RENAME // @@ -272,22 +278,22 @@ extension NCCollectionViewCommon { NCMenuAction( title: NSLocalizedString("_rename_", comment: ""), icon: NCUtility.shared.loadImage(named: "pencil"), - action: { menuAction in - + action: { _ in + if let vcRename = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile { - + vcRename.metadata = metadata vcRename.imagePreview = imageIcon let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height) - + self.present(popup, animated: true) } } ) ) } - + // // COPY - MOVE // @@ -296,13 +302,13 @@ extension NCCollectionViewCommon { NCMenuAction( title: NSLocalizedString("_move_or_copy_", comment: ""), icon: NCUtility.shared.loadImage(named: "arrow.up.right.square"), - action: { menuAction in + action: { _ in NCFunctionCenter.shared.openSelectView(items: [metadata], viewController: self) } ) ) } - + // // COPY // @@ -311,29 +317,14 @@ extension NCCollectionViewCommon { NCMenuAction( title: NSLocalizedString("_copy_file_", comment: ""), icon: NCUtility.shared.loadImage(named: "doc.on.doc"), - action: { menuAction in - self.appDelegate.pasteboardOcIds = [metadata.ocId]; + action: { _ in + self.appDelegate.pasteboardOcIds = [metadata.ocId] NCFunctionCenter.shared.copyPasteboard() } ) ) } - // - // VIEW IN FOLDER - // - if layoutKey == NCGlobal.shared.layoutViewRecent && appDelegate.activeFileViewInFolder == nil { - actions.append( - NCMenuAction( - title: NSLocalizedString("_view_in_folder_", comment: ""), - icon: NCUtility.shared.loadImage(named: "arrow.forward.square"), - action: { menuAction in - NCFunctionCenter.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, fileName: metadata.fileName) - } - ) - ) - } - /* // // USE AS BACKGROUND @@ -356,7 +347,7 @@ extension NCCollectionViewCommon { } } */ - + // // MODIFY // @@ -367,13 +358,19 @@ extension NCCollectionViewCommon { title: NSLocalizedString("_modify_", comment: ""), icon: NCUtility.shared.loadImage(named: "pencil.tip.crop.circle"), action: { menuAction in - NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorLoadFileQuickLook) + if self is NCFileViewInFolder { + self.dismiss(animated: true) { + NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorLoadFileQuickLook) + } + } else { + NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorLoadFileQuickLook) + } } ) ) } } - + // // DELETE // @@ -381,22 +378,20 @@ extension NCCollectionViewCommon { NCMenuAction( title: titleDelete, icon: NCUtility.shared.loadImage(named: "trash"), - action: { menuAction in + action: { _ in let alertController = UIAlertController(title: "", message: metadata.fileNameView + "\n\n" + NSLocalizedString("_want_delete_", comment: ""), preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (action:UIAlertAction) in + alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (_: UIAlertAction) in NCOperationQueue.shared.delete(metadata: metadata, onlyLocalCache: false) }) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_remove_local_file_", comment: ""), style: .default) { (action:UIAlertAction) in + alertController.addAction(UIAlertAction(title: NSLocalizedString("_remove_local_file_", comment: ""), style: .default) { (_: UIAlertAction) in NCOperationQueue.shared.delete(metadata: metadata, onlyLocalCache: true) }) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (action:UIAlertAction) in }) - self.present(alertController, animated: true, completion:nil) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (_: UIAlertAction) in }) + self.present(alertController, animated: true, completion: nil) } ) ) - - - + // // SET FOLDER E2EE // @@ -404,15 +399,15 @@ extension NCCollectionViewCommon { actions.append( NCMenuAction( title: NSLocalizedString("_e2e_set_folder_encrypted_", comment: ""), - icon:NCUtility.shared.loadImage(named: "lock"), - action: { menuAction in - NCCommunication.shared.markE2EEFolder(fileId: metadata.fileId, delete: false) { (account, errorCode, errorDescription) in + icon: NCUtility.shared.loadImage(named: "lock"), + action: { _ in + NCCommunication.shared.markE2EEFolder(fileId: metadata.fileId, delete: false) { account, errorCode, errorDescription in if errorCode == 0 { NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, serverUrl)) NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, serverUrlTo: nil, etag: nil, ocId: nil, fileId: nil, encrypted: true, richWorkspace: nil, account: metadata.account) NCManageDatabase.shared.setMetadataEncrypted(ocId: metadata.ocId, encrypted: true) - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE, userInfo: ["serverUrl":metadata.serverUrl]) + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE, userInfo: ["serverUrl": metadata.serverUrl]) } else { NCContentPresenter.shared.messageNotification(NSLocalizedString("_e2e_error_mark_folder_", comment: ""), description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: .error, errorCode: errorCode) } @@ -421,7 +416,7 @@ extension NCCollectionViewCommon { ) ) } - + // // UNSET FOLDER E2EE // @@ -430,14 +425,14 @@ extension NCCollectionViewCommon { NCMenuAction( title: NSLocalizedString("_e2e_remove_folder_encrypted_", comment: ""), icon: NCUtility.shared.loadImage(named: "lock"), - action: { menuAction in - NCCommunication.shared.markE2EEFolder(fileId: metadata.fileId, delete: true) { (account, errorCode, errorDescription) in + action: { _ in + NCCommunication.shared.markE2EEFolder(fileId: metadata.fileId, delete: true) { account, errorCode, errorDescription in if errorCode == 0 { NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, serverUrl)) NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, serverUrlTo: nil, etag: nil, ocId: nil, fileId: nil, encrypted: false, richWorkspace: nil, account: metadata.account) NCManageDatabase.shared.setMetadataEncrypted(ocId: metadata.ocId, encrypted: false) - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE, userInfo: ["serverUrl":metadata.serverUrl]) + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE, userInfo: ["serverUrl": metadata.serverUrl]) } else { NCContentPresenter.shared.messageNotification(NSLocalizedString("_e2e_error_delete_mark_folder_", comment: ""), description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: .error, errorCode: errorCode) } @@ -446,10 +441,10 @@ extension NCCollectionViewCommon { ) ) } - + presentMenu(with: actions) } - + func toggleMenuSelect() { var actions = [NCMenuAction]() @@ -461,12 +456,12 @@ extension NCCollectionViewCommon { NCMenuAction( title: NSLocalizedString("_select_all_", comment: ""), icon: NCUtility.shared.loadImage(named: "checkmark.circle.fill"), - action: { menuAction in + action: { _ in self.collectionViewSelectAll() } ) ) - + // // OPEN IN // @@ -474,7 +469,7 @@ extension NCCollectionViewCommon { NCMenuAction( title: NSLocalizedString("_open_in_", comment: ""), icon: NCUtility.shared.loadImage(named: "square.and.arrow.up"), - action: { menuAction in + action: { _ in NCFunctionCenter.shared.openActivityViewController(selectOcId: self.selectOcId) self.tapSelect(sender: self) } @@ -488,7 +483,7 @@ extension NCCollectionViewCommon { NCMenuAction( title: NSLocalizedString("_save_selected_files_", comment: ""), icon: NCUtility.shared.loadImage(named: "square.and.arrow.down"), - action: { menuAction in + action: { _ in for ocId in self.selectOcId { if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue { @@ -508,7 +503,7 @@ extension NCCollectionViewCommon { } ) ) - + // // COPY - MOVE // @@ -516,7 +511,7 @@ extension NCCollectionViewCommon { NCMenuAction( title: NSLocalizedString("_move_or_copy_selected_files_", comment: ""), icon: NCUtility.shared.loadImage(named: "arrow.up.right.square"), - action: { menuAction in + action: { _ in var meradatasSelect = [tableMetadata]() for ocId in self.selectOcId { if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { @@ -530,7 +525,7 @@ extension NCCollectionViewCommon { } ) ) - + // // COPY // @@ -538,7 +533,7 @@ extension NCCollectionViewCommon { NCMenuAction( title: NSLocalizedString("_copy_file_", comment: ""), icon: NCUtility.shared.loadImage(named: "doc.on.doc"), - action: { menuAction in + action: { _ in self.appDelegate.pasteboardOcIds.removeAll() for ocId in self.selectOcId { self.appDelegate.pasteboardOcIds.append(ocId) @@ -548,7 +543,7 @@ extension NCCollectionViewCommon { } ) ) - + // // DELETE // @@ -556,9 +551,9 @@ extension NCCollectionViewCommon { NCMenuAction( title: NSLocalizedString("_delete_selected_files_", comment: ""), icon: NCUtility.shared.loadImage(named: "trash"), - action: { menuAction in + action: { _ in let alertController = UIAlertController(title: "", message: NSLocalizedString("_want_delete_", comment: ""), preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (action:UIAlertAction) in + alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (_: UIAlertAction) in for ocId in self.selectOcId { if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { NCOperationQueue.shared.delete(metadata: metadata, onlyLocalCache: false) @@ -566,7 +561,7 @@ extension NCCollectionViewCommon { } self.tapSelect(sender: self) }) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_remove_local_file_", comment: ""), style: .default) { (action:UIAlertAction) in + alertController.addAction(UIAlertAction(title: NSLocalizedString("_remove_local_file_", comment: ""), style: .default) { (_: UIAlertAction) in for ocId in self.selectOcId { if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { NCOperationQueue.shared.delete(metadata: metadata, onlyLocalCache: true) @@ -574,8 +569,8 @@ extension NCCollectionViewCommon { } self.tapSelect(sender: self) }) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (action:UIAlertAction) in }) - self.present(alertController, animated: true, completion:nil) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (_: UIAlertAction) in }) + self.present(alertController, animated: true, completion: nil) } ) ) diff --git a/iOSClient/Menu/NCLoginWeb+Menu.swift b/iOSClient/Menu/NCLoginWeb+Menu.swift index c62f7d69d..c01d18b38 100644 --- a/iOSClient/Menu/NCLoginWeb+Menu.swift +++ b/iOSClient/Menu/NCLoginWeb+Menu.swift @@ -27,14 +27,14 @@ import FloatingPanel extension NCLoginWeb { func toggleMenu() { - + var actions = [NCMenuAction]() - + let accounts = NCManageDatabase.shared.getAllAccount() var avatar = NCUtility.shared.loadImage(named: "person.crop.circle") - + for account in accounts { - + let title = account.user + " " + (URL(string: account.urlBase)?.host ?? "") avatar = NCUtility.shared.loadUserImage( @@ -50,7 +50,7 @@ extension NCLoginWeb { onIcon: avatar, selected: account.active == true, on: account.active == true, - action: { menuAction in + action: { _ in if self.appDelegate.account != account.account { NCManageDatabase.shared.setAccountActive(account.account) self.dismiss(animated: true) { @@ -71,7 +71,7 @@ extension NCLoginWeb { onIcon: avatar, selected: false, on: false, - action: { menuAction in + action: { _ in self.appDelegate.deleteAccount(self.appDelegate.account, wipe: false) self.dismiss(animated: true) { let accounts = NCManageDatabase.shared.getAllAccount() @@ -88,4 +88,3 @@ extension NCLoginWeb { presentMenu(with: actions) } } - diff --git a/iOSClient/Menu/NCMedia+Menu.swift b/iOSClient/Menu/NCMedia+Menu.swift index ffd196121..5b2efe67c 100644 --- a/iOSClient/Menu/NCMedia+Menu.swift +++ b/iOSClient/Menu/NCMedia+Menu.swift @@ -37,7 +37,7 @@ extension NCMedia { NCMenuAction( title: NSLocalizedString("_select_", comment: ""), icon: NCUtility.shared.loadImage(named: "checkmark.circle.fill"), - action: { menuAction in + action: { _ in self.isEditMode = true } ) @@ -50,10 +50,10 @@ extension NCMedia { icon: NCUtility.shared.loadImage(named: "photo"), selected: filterClassTypeImage, on: true, - action: { menuAction in + action: { _ in self.filterClassTypeImage = !self.filterClassTypeImage self.filterClassTypeVideo = false - self.reloadDataSourceWithCompletion { (_) in } + self.reloadDataSourceWithCompletion { _ in } } ) ) @@ -64,72 +64,72 @@ extension NCMedia { icon: NCUtility.shared.loadImage(named: "video"), selected: filterClassTypeVideo, on: true, - action: { menuAction in + action: { _ in self.filterClassTypeVideo = !self.filterClassTypeVideo self.filterClassTypeImage = false - self.reloadDataSourceWithCompletion { (_) in } + self.reloadDataSourceWithCompletion { _ in } } ) ) - + actions.append( NCMenuAction( title: NSLocalizedString("_select_media_folder_", comment: ""), icon: NCUtility.shared.loadImage(named: "folder"), - action: { menuAction in + action: { _ in 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" - + self.present(navigationController, animated: true, completion: nil) } ) ) - + actions.append( NCMenuAction( title: NSLocalizedString("_media_by_modified_date_", comment: ""), icon: NCUtility.shared.loadImage(named: "circle.grid.cross.up.fill"), selected: CCUtility.getMediaSortDate() == "date", on: true, - action: { menuAction in + action: { _ in CCUtility.setMediaSortDate("date") - self.reloadDataSourceWithCompletion { (_) in } + self.reloadDataSourceWithCompletion { _ in } } ) ) - + actions.append( NCMenuAction( title: NSLocalizedString("_media_by_created_date_", comment: ""), icon: NCUtility.shared.loadImage(named: "circle.grid.cross.down.fill"), selected: CCUtility.getMediaSortDate() == "creationDate", on: true, - action: { menuAction in + action: { _ in CCUtility.setMediaSortDate("creationDate") - self.reloadDataSourceWithCompletion { (_) in } + self.reloadDataSourceWithCompletion { _ in } } ) ) - + actions.append( NCMenuAction( title: NSLocalizedString("_media_by_upload_date_", comment: ""), icon: NCUtility.shared.loadImage(named: "circle.grid.cross.right.fill"), selected: CCUtility.getMediaSortDate() == "uploadDate", on: true, - action: { menuAction in + action: { _ in CCUtility.setMediaSortDate("uploadDate") - self.reloadDataSourceWithCompletion { (_) in } + self.reloadDataSourceWithCompletion { _ in } } ) ) - + } else { - + // // CANCEL // @@ -137,14 +137,14 @@ extension NCMedia { NCMenuAction( title: NSLocalizedString("_cancel_", comment: ""), icon: NCUtility.shared.loadImage(named: "xmark"), - action: { menuAction in + action: { _ in self.isEditMode = false self.selectOcId.removeAll() self.reloadDataThenPerform { } } ) ) - + // // OPEN IN // @@ -152,7 +152,7 @@ extension NCMedia { NCMenuAction( title: NSLocalizedString("_open_in_", comment: ""), icon: NCUtility.shared.loadImage(named: "square.and.arrow.up"), - action: { menuAction in + action: { _ in self.isEditMode = false NCFunctionCenter.shared.openActivityViewController(selectOcId: self.selectOcId) self.selectOcId.removeAll() @@ -160,7 +160,7 @@ extension NCMedia { } ) ) - + // // SAVE TO PHOTO GALLERY // @@ -168,7 +168,7 @@ extension NCMedia { NCMenuAction( title: NSLocalizedString("_save_selected_files_", comment: ""), icon: NCUtility.shared.loadImage(named: "square.and.arrow.down"), - action: { menuAction in + action: { _ in self.isEditMode = false for ocId in self.selectOcId { if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { @@ -190,7 +190,7 @@ extension NCMedia { } ) ) - + // // COPY - MOVE // @@ -198,7 +198,7 @@ extension NCMedia { NCMenuAction( title: NSLocalizedString("_move_or_copy_selected_files_", comment: ""), icon: NCUtility.shared.loadImage(named: "arrow.up.right.square"), - action: { menuAction in + action: { _ in self.isEditMode = false var meradatasSelect = [tableMetadata]() for ocId in self.selectOcId { @@ -214,7 +214,7 @@ extension NCMedia { } ) ) - + // // COPY // @@ -222,7 +222,7 @@ extension NCMedia { NCMenuAction( title: NSLocalizedString("_copy_file_", comment: ""), icon: NCUtility.shared.loadImage(named: "doc.on.doc"), - action: { menuAction in + action: { _ in self.isEditMode = false self.appDelegate.pasteboardOcIds.removeAll() for ocId in self.selectOcId { @@ -234,7 +234,7 @@ extension NCMedia { } ) ) - + // // DELETE // @@ -242,11 +242,11 @@ extension NCMedia { NCMenuAction( title: NSLocalizedString("_delete_selected_files_", comment: ""), icon: NCUtility.shared.loadImage(named: "trash"), - action: { menuAction in + action: { _ in self.isEditMode = false for ocId in self.selectOcId { if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false) { (errorCode, errorDescription) in + NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false) { errorCode, errorDescription in if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } @@ -263,4 +263,3 @@ extension NCMedia { presentMenu(with: actions) } } - diff --git a/iOSClient/Menu/NCMenu+FloatingPanel.swift b/iOSClient/Menu/NCMenu+FloatingPanel.swift new file mode 100644 index 000000000..053697c80 --- /dev/null +++ b/iOSClient/Menu/NCMenu+FloatingPanel.swift @@ -0,0 +1,79 @@ +// +// NCMenu+FloatingPanel.swift +// Nextcloud +// +// Created by Philippe Weidmann on 16.12.21. +// Copyright © 2021 Henrik Storch All rights reserved. +// +// Author Henrik Storch <henrik.storch@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 FloatingPanel + +class NCMenuFloatingPanelLayout: FloatingPanelLayout { + var position: FloatingPanelPosition = .bottom + + var initialState: FloatingPanelState = .full + + var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] { + [ + .full: FloatingPanelLayoutAnchor(absoluteInset: topInset, edge: .top, referenceGuide: .superview) + ] + } + + let topInset: CGFloat + + init(numberOfActions: Int) { + // sometimes UIScreen.main.bounds.size.height is not updated correctly + // this ensures we use the correct height value + // can't use `layoutFor size` since menu is dieplayed on top of the whole screen not just the VC + let screenHeight = UIApplication.shared.isLandscape + ? min(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height) + : max(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height) + let bottomInset = UIApplication.shared.keyWindow?.rootViewController?.view.safeAreaInsets.bottom ?? 0 + let panelHeight = CGFloat(numberOfActions * 60) + bottomInset + + topInset = max(48, screenHeight - panelHeight) + } + + func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] { + return [ + surfaceView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0), + surfaceView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0) + ] + } + + func backdropAlpha(for state: FloatingPanelState) -> CGFloat { + return 0.2 + } +} + +class NCMenuPanelController: FloatingPanelController { + + var parentPresenter: UIViewController? + + // MARK: - View Life Cycle + + override func viewDidLoad() { + super.viewDidLoad() + + self.surfaceView.backgroundColor = NCBrandColor.shared.systemBackground + self.isRemovalInteractionEnabled = true + self.backdropView.dismissalTapGestureRecognizer.isEnabled = true + self.surfaceView.layer.cornerRadius = 16 + } +} diff --git a/iOSClient/Menu/NCMenu.swift b/iOSClient/Menu/NCMenu.swift index c57b457a9..a174b62d7 100644 --- a/iOSClient/Menu/NCMenu.swift +++ b/iOSClient/Menu/NCMenu.swift @@ -5,9 +5,11 @@ // Created by Philippe Weidmann on 16.01.20. // Copyright © 2020 Philippe Weidmann. All rights reserved. // Copyright © 2020 Marino Faggiana All rights reserved. +// Copyright © 2021 Henrik Storch All rights reserved. // // Author Philippe Weidmann <philippe.weidmann@infomaniak.com> // Author Marino Faggiana <marino.faggiana@nextcloud.com> +// Author Henrik Storch <henrik.storch@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 @@ -30,12 +32,12 @@ class NCMenu: UITableViewController { var actions = [NCMenuAction]() - static func makeNCMenu(with actions: [NCMenuAction]) -> NCMenu { - let menuViewController = UIStoryboard(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu - menuViewController.actions = actions + static func makeNCMenu(with actions: [NCMenuAction]) -> NCMenu? { + let menuViewController = UIStoryboard(name: "NCMenu", bundle: nil).instantiateInitialViewController() as? NCMenu + menuViewController?.actions = actions return menuViewController } - + // MARK: - View Life Cycle override func viewDidLoad() { @@ -64,19 +66,19 @@ class NCMenu: UITableViewController { let cell = tableView.dequeueReusableCell(withIdentifier: "menuActionCell", for: indexPath) cell.tintColor = NCBrandColor.shared.customer let action = actions[indexPath.row] - let actionIconView = cell.viewWithTag(1) as! UIImageView - let actionNameLabel = cell.viewWithTag(2) as! UILabel + let actionIconView = cell.viewWithTag(1) as? UIImageView + let actionNameLabel = cell.viewWithTag(2) as? UILabel if action.action == nil { cell.selectionStyle = .none } - if (action.isOn) { - actionIconView.image = action.onIcon - actionNameLabel.text = action.onTitle + if action.isOn { + actionIconView?.image = action.onIcon + actionNameLabel?.text = action.onTitle } else { - actionIconView.image = action.icon - actionNameLabel.text = action.title + actionIconView?.image = action.icon + actionNameLabel?.text = action.title } cell.accessoryType = action.selectable && action.selected ? .checkmark : .none @@ -84,100 +86,33 @@ class NCMenu: UITableViewController { return cell } - // MARK: - Accessibility - - open override func accessibilityPerformEscape() -> Bool { - dismiss(animated: true) - return true - } - -} -extension NCMenu: FloatingPanelControllerDelegate { - - func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout? { - let safeAreaInsetsBottom = Int(UIApplication.shared.keyWindow?.rootViewController?.view.safeAreaInsets.bottom ?? 0) - return NCMenuFloatingPanelLayout(height: self.actions.count * 60 + safeAreaInsetsBottom) - } - - func floatingPanel(_ vc: FloatingPanelController, behaviorFor newCollection: UITraitCollection) -> FloatingPanelBehavior? { - return NCMenuFloatingPanelBehavior() - } + // MARK: - Tabel View Layout - func floatingPanelDidEndDecelerating(_ vc: FloatingPanelController) { - if vc.position == .hidden { - vc.dismiss(animated: false, completion: nil) - } + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 60 } } +extension NCMenu: FloatingPanelControllerDelegate { -class NCMenuFloatingPanelLayout: FloatingPanelLayout { - - let height: CGFloat - - init(height: Int) { - self.height = CGFloat(height) - } - - var initialPosition: FloatingPanelPosition { - return .full - } - - var supportedPositions: Set<FloatingPanelPosition> { - return [.full, .hidden] - } - - func insetFor(position: FloatingPanelPosition) -> CGFloat? { - if (position == .full) { - return max(48, UIScreen.main.bounds.size.height - height) - } else { - return nil - } - } - - var positionReference: FloatingPanelLayoutReference { - return .fromSuperview - } - - public func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] { - return [ - surfaceView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0), - surfaceView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0), - ] - } - - func backdropAlphaFor(position: FloatingPanelPosition) -> CGFloat { - return 0.2 + func floatingPanel(_ fpc: FloatingPanelController, layoutFor size: CGSize) -> FloatingPanelLayout { + return NCMenuFloatingPanelLayout(numberOfActions: self.actions.count) } -} - -public class NCMenuFloatingPanelBehavior: FloatingPanelBehavior { - public func addAnimator(_ fpc: FloatingPanelController, to: FloatingPanelPosition) -> UIViewPropertyAnimator { - return UIViewPropertyAnimator(duration: 0.3, curve: .easeInOut) + func floatingPanel(_ fpc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout { + return NCMenuFloatingPanelLayout(numberOfActions: self.actions.count) } - public func removeAnimator(_ fpc: FloatingPanelController, from: FloatingPanelPosition) -> UIViewPropertyAnimator { + func floatingPanel(_ fpc: FloatingPanelController, animatorForDismissingWith velocity: CGVector) -> UIViewPropertyAnimator { return UIViewPropertyAnimator(duration: 0.1, curve: .easeInOut) } - public func moveAnimator(_ fpc: FloatingPanelController, from: FloatingPanelPosition, to: FloatingPanelPosition) -> UIViewPropertyAnimator { - return UIViewPropertyAnimator(duration: 0.1, curve: .easeInOut) + func floatingPanel(_ fpc: FloatingPanelController, animatorForPresentingTo state: FloatingPanelState) -> UIViewPropertyAnimator { + return UIViewPropertyAnimator(duration: 0.3, curve: .easeInOut) } -} - -class NCMenuPanelController: FloatingPanelController { - - var parentPresenter: UIViewController? - - // MARK: - View Life Cycle - - override func viewDidLoad() { - super.viewDidLoad() - - self.surfaceView.backgroundColor = NCBrandColor.shared.systemBackground - self.isRemovalInteractionEnabled = true - self.surfaceView.cornerRadius = 16 + func floatingPanelWillEndDragging(_ fpc: FloatingPanelController, withVelocity velocity: CGPoint, targetState: UnsafeMutablePointer<FloatingPanelState>) { + guard velocity.y > 750 else { return } + fpc.dismiss(animated: true, completion: nil) } } diff --git a/iOSClient/Menu/NCSortMenu.swift b/iOSClient/Menu/NCSortMenu.swift index 358747896..754714c50 100644 --- a/iOSClient/Menu/NCSortMenu.swift +++ b/iOSClient/Menu/NCSortMenu.swift @@ -26,25 +26,25 @@ import FloatingPanel import NCCommunication class NCSortMenu: NSObject { - + private var sortButton: UIButton? private var serverUrl: String = "" private var hideDirectoryOnTop: Bool? - + private var key = "" func toggleMenu(viewController: UIViewController, key: String, sortButton: UIButton?, serverUrl: String, hideDirectoryOnTop: Bool = false) { - + self.key = key self.sortButton = sortButton self.serverUrl = serverUrl self.hideDirectoryOnTop = hideDirectoryOnTop - + var layoutForView = NCUtility.shared.getLayoutForView(key: key, serverUrl: serverUrl) var actions = [NCMenuAction]() var title = "" var icon = UIImage() - + if layoutForView.ascending { title = NSLocalizedString("_order_by_name_z_a_", comment: "") icon = UIImage(named: "sortFileNameZA")!.image(color: NCBrandColor.shared.gray, size: 50) @@ -52,14 +52,14 @@ class NCSortMenu: NSObject { title = NSLocalizedString("_order_by_name_a_z_", comment: "") icon = UIImage(named: "sortFileNameAZ")!.image(color: NCBrandColor.shared.gray, size: 50) } - + actions.append( NCMenuAction( title: title, icon: icon, selected: layoutForView.sort == "fileName", on: layoutForView.sort == "fileName", - action: { menuAction in + action: { _ in layoutForView.sort = "fileName" layoutForView.ascending = !layoutForView.ascending self.actionMenu(layoutForView: layoutForView) @@ -74,14 +74,14 @@ class NCSortMenu: NSObject { title = NSLocalizedString("_order_by_date_less_recent_", comment: "") icon = UIImage(named: "sortDateLessRecent")!.image(color: NCBrandColor.shared.gray, size: 50) } - + actions.append( NCMenuAction( title: title, icon: icon, selected: layoutForView.sort == "date", on: layoutForView.sort == "date", - action: { menuAction in + action: { _ in layoutForView.sort = "date" layoutForView.ascending = !layoutForView.ascending self.actionMenu(layoutForView: layoutForView) @@ -96,14 +96,14 @@ class NCSortMenu: NSObject { title = NSLocalizedString("_order_by_size_smallest_", comment: "") icon = UIImage(named: "sortSmallest")!.image(color: NCBrandColor.shared.gray, size: 50) } - + actions.append( NCMenuAction( title: title, icon: icon, selected: layoutForView.sort == "size", on: layoutForView.sort == "size", - action: { menuAction in + action: { _ in layoutForView.sort = "size" layoutForView.ascending = !layoutForView.ascending self.actionMenu(layoutForView: layoutForView) @@ -118,21 +118,21 @@ class NCSortMenu: NSObject { icon: UIImage(named: "foldersOnTop")!.image(color: NCBrandColor.shared.gray, size: 50), selected: layoutForView.directoryOnTop, on: layoutForView.directoryOnTop, - action: { menuAction in + action: { _ in layoutForView.directoryOnTop = !layoutForView.directoryOnTop self.actionMenu(layoutForView: layoutForView) } ) ) } - + viewController.presentMenu(with: actions) } - + func actionMenu(layoutForView: NCGlobal.layoutForViewType) { - + var layoutForView = layoutForView - + switch layoutForView.sort { case "fileName": layoutForView.titleButtonHeader = layoutForView.ascending ? "_sorted_by_name_a_z_" : "_sorted_by_name_z_a_" @@ -143,11 +143,11 @@ class NCSortMenu: NSObject { default: break } - + self.sortButton?.setTitle(NSLocalizedString(layoutForView.titleButtonHeader, comment: ""), for: .normal) - + NCUtility.shared.setLayoutForView(key: key, serverUrl: serverUrl, layoutForView: layoutForView) - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl":self.serverUrl]) + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl": self.serverUrl]) } } diff --git a/iOSClient/Menu/NCTrash+Menu.swift b/iOSClient/Menu/NCTrash+Menu.swift index 8ce4fef58..05831d9e0 100644 --- a/iOSClient/Menu/NCTrash+Menu.swift +++ b/iOSClient/Menu/NCTrash+Menu.swift @@ -36,7 +36,7 @@ extension NCTrash { NCMenuAction( title: NSLocalizedString("_trash_delete_selected_", comment: ""), icon: NCUtility.shared.loadImage(named: "trash"), - action: { menuAction in + action: { _ in let alert = UIAlertController(title: NSLocalizedString("_trash_delete_selected_", comment: ""), message: "", preferredStyle: .alert) alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .destructive, handler: { _ in for ocId in self.selectOcId { @@ -57,7 +57,7 @@ extension NCTrash { NCMenuAction( title: NSLocalizedString("_trash_delete_all_", comment: ""), icon: NCUtility.shared.loadImage(named: "trash"), - action: { menuAction in + action: { _ in let alert = UIAlertController(title: NSLocalizedString("_trash_delete_all_", comment: ""), message: "", preferredStyle: .alert) alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .destructive, handler: { _ in self.emptyTrash() @@ -85,7 +85,7 @@ extension NCTrash { if let icon = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(tableTrash.fileId, etag: tableTrash.fileName)) { iconHeader = icon } else { - if(tableTrash.directory) { + if tableTrash.directory { iconHeader = UIImage(named: "folder")!.image(color: NCBrandColor.shared.gray, size: 50) } else { iconHeader = UIImage(named: tableTrash.iconName) @@ -104,7 +104,7 @@ extension NCTrash { NCMenuAction( title: NSLocalizedString("_delete_", comment: ""), icon: NCUtility.shared.loadImage(named: "trash"), - action: { menuAction in + action: { _ in self.deleteItem(with: objectId) } ) @@ -112,7 +112,7 @@ extension NCTrash { self.presentMenu(with: actions) } - + func toggleMenuMoreGrid(with objectId: String, namedButtonMore: String, image: UIImage?) { var actions: [NCMenuAction] = [] @@ -125,7 +125,7 @@ extension NCTrash { if let icon = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(tableTrash.fileId, etag: tableTrash.fileName)) { iconHeader = icon } else { - if(tableTrash.directory) { + if tableTrash.directory { iconHeader = UIImage(named: "folder")!.image(color: NCBrandColor.shared.gray, size: 50) } else { iconHeader = UIImage(named: tableTrash.iconName) @@ -144,7 +144,7 @@ extension NCTrash { NCMenuAction( title: NSLocalizedString("_restore_", comment: ""), icon: UIImage(named: "restore")!.image(color: NCBrandColor.shared.gray, size: 50), - action: { menuAction in + action: { _ in self.restoreItem(with: objectId) } ) @@ -154,7 +154,7 @@ extension NCTrash { NCMenuAction( title: NSLocalizedString("_delete_", comment: ""), icon: NCUtility.shared.loadImage(named: "trash"), - action: { menuAction in + action: { _ in self.deleteItem(with: objectId) } ) @@ -163,4 +163,3 @@ extension NCTrash { presentMenu(with: actions) } } - diff --git a/iOSClient/Menu/NCViewer+Menu.swift b/iOSClient/Menu/NCViewer+Menu.swift index 4a873e12b..8f87ec463 100644 --- a/iOSClient/Menu/NCViewer+Menu.swift +++ b/iOSClient/Menu/NCViewer+Menu.swift @@ -28,20 +28,20 @@ import NCCommunication extension NCViewer { func toggleMenu(viewController: UIViewController, metadata: tableMetadata, webView: Bool, imageIcon: UIImage?) { - + var actions = [NCMenuAction]() - + var titleFavorite = NSLocalizedString("_add_favorites_", comment: "") if metadata.favorite { titleFavorite = NSLocalizedString("_remove_favorites_", comment: "") } let localFile = NCManageDatabase.shared.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) - + var titleOffline = "" - if (localFile == nil || localFile!.offline == false) { + if localFile == nil || localFile!.offline == false { titleOffline = NSLocalizedString("_set_available_offline_", comment: "") } else { titleOffline = NSLocalizedString("_remove_available_offline_", comment: "") } - + var titleDelete = NSLocalizedString("_delete_", comment: "") if NCManageDatabase.shared.isMetadataShareOrMounted(metadata: metadata, metadataFolder: nil) { titleDelete = NSLocalizedString("_leave_share_", comment: "") @@ -50,9 +50,9 @@ extension NCViewer { } else { titleDelete = NSLocalizedString("_delete_file_", comment: "") } - + let isFolderEncrypted = CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase) - + // // FAVORITE // @@ -60,8 +60,8 @@ extension NCViewer { NCMenuAction( title: titleFavorite, icon: NCUtility.shared.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite), - action: { menuAction in - NCNetworking.shared.favoriteMetadata(metadata) { (errorCode, errorDescription) in + action: { _ in + NCNetworking.shared.favoriteMetadata(metadata) { errorCode, errorDescription in if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } @@ -69,7 +69,7 @@ extension NCViewer { } ) ) - + // // DETAIL // @@ -78,13 +78,13 @@ extension NCViewer { NCMenuAction( title: NSLocalizedString("_details_", comment: ""), icon: NCUtility.shared.loadImage(named: "info"), - action: { menuAction in - NCFunctionCenter.shared.openShare(ViewController: viewController, metadata: metadata, indexPage: .activity) + action: { _ in + NCFunctionCenter.shared.openShare(viewController: viewController, metadata: metadata, indexPage: .activity) } ) ) } - + // // OFFLINE // @@ -93,9 +93,9 @@ extension NCViewer { NCMenuAction( title: titleOffline, icon: NCUtility.shared.loadImage(named: "tray.and.arrow.down"), - action: { menuAction in - if ((localFile == nil || !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView)) && metadata.session == "") { - NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadOffline) { (_) in } + action: { _ in + if (localFile == nil || !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView)) && metadata.session == "" { + NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadOffline) { _ in } } else { NCManageDatabase.shared.setLocalFile(ocId: metadata.ocId, offline: !localFile!.offline) } @@ -103,7 +103,7 @@ extension NCViewer { ) ) } - + // // OPEN IN // @@ -112,13 +112,13 @@ extension NCViewer { NCMenuAction( title: NSLocalizedString("_open_in_", comment: ""), icon: NCUtility.shared.loadImage(named: "square.and.arrow.up"), - action: { menuAction in + action: { _ in NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorOpenIn) } ) ) } - + // // PRINT // @@ -127,18 +127,18 @@ extension NCViewer { NCMenuAction( title: NSLocalizedString("_print_", comment: ""), icon: NCUtility.shared.loadImage(named: "printer"), - action: { menuAction in + action: { _ in NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorPrint) } ) ) } - + // // SAVE IMAGE / VIDEO // if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue { - + var title: String = NSLocalizedString("_save_selected_files_", comment: "") var icon = NCUtility.shared.loadImage(named: "square.and.arrow.down") let metadataMOV = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) @@ -146,12 +146,12 @@ extension NCViewer { title = NSLocalizedString("_livephoto_save_", comment: "") icon = NCUtility.shared.loadImage(named: "livephoto") } - + actions.append( NCMenuAction( title: title, icon: icon, - action: { menuAction in + action: { _ in if metadataMOV != nil { NCFunctionCenter.shared.saveLivePhoto(metadata: metadata, metadataMOV: metadataMOV!) } else { @@ -161,24 +161,24 @@ extension NCViewer { ) ) } - + // // SAVE AS SCAN // if #available(iOS 13.0, *) { - if (metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue && metadata.contentType != "image/svg+xml") { + if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue && metadata.contentType != "image/svg+xml" { actions.append( NCMenuAction( title: NSLocalizedString("_save_as_scan_", comment: ""), icon: NCUtility.shared.loadImage(named: "viewfinder.circle"), - action: { menuAction in + action: { _ in NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorSaveAsScan) } ) ) } } - + // // RENAME // @@ -187,23 +187,23 @@ extension NCViewer { NCMenuAction( title: NSLocalizedString("_rename_", comment: ""), icon: NCUtility.shared.loadImage(named: "pencil"), - action: { menuAction in - + action: { _ in + if let vcRename = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile { - + vcRename.metadata = metadata vcRename.disableChangeExt = true vcRename.imagePreview = imageIcon - + let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height) - + viewController.present(popup, animated: true) } } ) ) } - + // // COPY - MOVE // @@ -212,22 +212,22 @@ extension NCViewer { NCMenuAction( title: NSLocalizedString("_move_or_copy_", comment: ""), icon: NCUtility.shared.loadImage(named: "arrow.up.right.square"), - action: { menuAction in - + action: { _ in + let storyboard = UIStoryboard(name: "NCSelect", bundle: nil) let navigationController = storyboard.instantiateInitialViewController() as! UINavigationController let viewController = navigationController.topViewController as! NCSelect - + viewController.delegate = NCViewer.shared viewController.typeOfCommandView = .copyMove viewController.items = [metadata] - + self.appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil) } ) ) } - + // // COPY // @@ -235,30 +235,28 @@ extension NCViewer { NCMenuAction( title: NSLocalizedString("_copy_file_", comment: ""), icon: NCUtility.shared.loadImage(named: "doc.on.doc"), - action: { menuAction in - self.appDelegate.pasteboardOcIds = [metadata.ocId]; + action: { _ in + self.appDelegate.pasteboardOcIds = [metadata.ocId] NCFunctionCenter.shared.copyPasteboard() } ) ) - + // // VIEW IN FOLDER // if !webView { - if appDelegate.activeFileViewInFolder == nil { - actions.append( - NCMenuAction( - title: NSLocalizedString("_view_in_folder_", comment: ""), - icon: NCUtility.shared.loadImage(named: "arrow.forward.square"), - action: { menuAction in - NCFunctionCenter.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, fileName: metadata.fileName) - } - ) + actions.append( + NCMenuAction( + title: NSLocalizedString("_view_in_folder_", comment: ""), + icon: NCUtility.shared.loadImage(named: "arrow.forward.square"), + action: { menuAction in + NCFunctionCenter.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, fileName: metadata.fileName) + } ) - } + ) } - + // // DOWNLOAD IMAGE MAX RESOLUTION // @@ -268,14 +266,14 @@ extension NCViewer { NCMenuAction( title: NSLocalizedString("_download_image_max_", comment: ""), icon: NCUtility.shared.loadImage(named: "square.and.arrow.down"), - action: { menuAction in - NCNetworking.shared.download(metadata: metadata, selector: "") { (_) in } + action: { _ in + NCNetworking.shared.download(metadata: metadata, selector: "") { _ in } } ) ) } } - + // // PDF // @@ -284,15 +282,15 @@ extension NCViewer { NCMenuAction( title: NSLocalizedString("_search_", comment: ""), icon: UIImage(named: "search")!.image(color: NCBrandColor.shared.gray, size: 50), - action: { menuAction in + action: { _ in NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterMenuSearchTextPDF) } ) ) - + var title = "" var icon = UIImage() - + if CCUtility.getPDFDisplayDirection() == .horizontal { title = NSLocalizedString("_pdf_vertical_", comment: "") icon = UIImage(named: "pdf-vertical")!.image(color: NCBrandColor.shared.gray, size: 50) @@ -300,12 +298,12 @@ extension NCViewer { title = NSLocalizedString("_pdf_horizontal_", comment: "") icon = UIImage(named: "pdf-horizontal")!.image(color: NCBrandColor.shared.gray, size: 50) } - + actions.append( NCMenuAction( title: title, icon: icon, - action: { menuAction in + action: { _ in if CCUtility.getPDFDisplayDirection() == .horizontal { NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterMenuPDFDisplayDirection, userInfo: ["direction": PDFDisplayDirection.vertical]) } else { @@ -314,18 +312,18 @@ extension NCViewer { } ) ) - + actions.append( NCMenuAction( title: NSLocalizedString("_go_to_page_", comment: ""), icon: NCUtility.shared.loadImage(named: "repeat"), - action: { menuAction in + action: { _ in NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterMenuGotToPageInPDF) } ) ) } - + // // MODIFY // @@ -335,14 +333,14 @@ extension NCViewer { NCMenuAction( title: NSLocalizedString("_modify_", comment: ""), icon: NCUtility.shared.loadImage(named: "pencil.tip.crop.circle"), - action: { menuAction in + action: { _ in NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorLoadFileQuickLook) } ) ) } } - + // // DELETE // @@ -351,22 +349,22 @@ extension NCViewer { NCMenuAction( title: titleDelete, icon: NCUtility.shared.loadImage(named: "trash"), - action: { menuAction in - + action: { _ in + let alertController = UIAlertController(title: "", message: NSLocalizedString("_want_delete_", comment: ""), preferredStyle: .alert) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (action:UIAlertAction) in - - NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false) { (errorCode, errorDescription) in + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (_: UIAlertAction) in + + NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false) { errorCode, errorDescription in if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } } }) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (action:UIAlertAction) in }) - - viewController.present(alertController, animated: true, completion:nil) + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (_: UIAlertAction) in }) + + viewController.present(alertController, animated: true, completion: nil) } ) ) diff --git a/iOSClient/Menu/UIViewController+Menu.swift b/iOSClient/Menu/UIViewController+Menu.swift index 94e86afb4..821827d24 100644 --- a/iOSClient/Menu/UIViewController+Menu.swift +++ b/iOSClient/Menu/UIViewController+Menu.swift @@ -63,7 +63,7 @@ extension UIViewController { let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor) guard serverVersionMajor >= NCGlobal.shared.nextcloudVersion23 else { return } - NCCommunication.shared.getHovercard(for: userId) { (card, errCode, err) in + NCCommunication.shared.getHovercard(for: userId) { card, _, _ in guard let card = card else { return } let personHeader = NCMenuAction( @@ -104,9 +104,12 @@ extension UIViewController { present(mail, animated: true) } - + func presentMenu(with actions: [NCMenuAction]) { - let menuViewController = NCMenu.makeNCMenu(with: actions) + guard let menuViewController = NCMenu.makeNCMenu(with: actions) else { + NCContentPresenter.shared.showGenericError(description: "_internal_generic_error_") + return + } let menuPanelController = NCMenuPanelController() menuPanelController.parentPresenter = self diff --git a/iOSClient/More/NCMore.swift b/iOSClient/More/NCMore.swift index 06fd83791..02e21a1bb 100644 --- a/iOSClient/More/NCMore.swift +++ b/iOSClient/More/NCMore.swift @@ -55,8 +55,8 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { tableView.backgroundColor = NCBrandColor.shared.systemGroupedBackground tableView.separatorColor = NCBrandColor.shared.separator - tableView.register(UINib.init(nibName: "NCMoreUserCell", bundle: nil), forCellReuseIdentifier: "userCell") - + tableView.register(UINib(nibName: "NCMoreUserCell", bundle: nil), forCellReuseIdentifier: "userCell") + // create tap gesture recognizer let tapQuota = UITapGestureRecognizer(target: self, action: #selector(tapLabelQuotaExternalSite)) labelQuotaExternalSite.isUserInteractionEnabled = true @@ -68,22 +68,22 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + appDelegate.activeViewController = self - + loadItems() } - + // MARK: - NotificationCenter @objc func initialize() { loadItems() } - + // MARK: - - + func loadItems() { - + var item = NCCommunicationExternalSite() var quota: String = "" @@ -94,7 +94,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { quotaMenu.removeAll() labelQuotaExternalSite.text = "" progressQuota.progressTintColor = NCBrandColor.shared.brandElement - + // ITEM : Transfer item = NCCommunicationExternalSite() item.name = "_transfers_" @@ -108,7 +108,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { item.icon = "recent" item.url = "segueRecent" functionMenu.append(item) - + // ITEM : Notification item = NCCommunicationExternalSite() item.name = "_notification_" @@ -132,7 +132,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { item.url = "segueShares" functionMenu.append(item) } - + // ITEM : Offline item = NCCommunicationExternalSite() item.name = "_manage_file_offline_" @@ -148,7 +148,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { item.url = "openStoryboardScan" functionMenu.append(item) } - + // ITEM : Trash let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor) if serverVersionMajor >= NCGlobal.shared.nextcloudVersion15 { @@ -166,7 +166,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { item.icon = "gear" item.url = "segueSettings" settingsMenu.append(item) - + // ITEM: Test API if NCUtility.shared.isSimulator() { item = NCCommunicationExternalSite() @@ -176,18 +176,18 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { settingsMenu.append(item) } - if (quotaMenu.count > 0) { + if quotaMenu.count > 0 { let item = quotaMenu[0] labelQuotaExternalSite.text = item.name } - + // Display Name user & Quota if let activeAccount = NCManageDatabase.shared.getActiveAccount() { - + self.tabAccount = activeAccount - if (activeAccount.quotaRelative > 0) { + if activeAccount.quotaRelative > 0 { progressQuota.progress = Float(activeAccount.quotaRelative) / 100 } else { progressQuota.progress = 0 @@ -208,7 +208,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { labelQuota.text = String.localizedStringWithFormat(NSLocalizedString("_quota_using_", comment: ""), quotaUsed, quota) } - + // ITEM : External if NCBrandOptions.shared.disable_more_external_site == false { if let externalSites = NCManageDatabase.shared.getAllExternalSites(account: appDelegate.account) { @@ -218,7 +218,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { item.name = externalSite.name item.url = urlEncoded item.icon = "network" - if (externalSite.type == "settings") { + if externalSite.type == "settings" { item.icon = "gear" } externalSiteMenu.append(item) @@ -237,7 +237,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { @objc func tapLabelQuotaExternalSite() { - if (quotaMenu.count > 0) { + if quotaMenu.count > 0 { let item = quotaMenu[0] let browserWebVC = UIStoryboard(name: "NCBrowserWeb", bundle: nil).instantiateInitialViewController() as! NCBrowserWeb @@ -251,13 +251,13 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { @objc func tapImageLogoManageAccount() { - let controller = CCManageAccount.init() + let controller = CCManageAccount() self.navigationController?.pushViewController(controller, animated: true) } - + // MARK: - - + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { if indexPath.section == 0 { return 100 @@ -265,10 +265,10 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { return NCGlobal.shared.heightCellSettings } } - + func numberOfSections(in tableView: UITableView) -> Int { - if (externalSiteMenu.count == 0) { + if externalSiteMenu.count == 0 { return 3 } else { return 4 @@ -278,26 +278,26 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { var cont = 0 - - if (section == 0) { + + if section == 0 { cont = tabAccount == nil ? 0 : 1 - } else if (section == 1) { + } else if section == 1 { // Menu Normal cont = functionMenu.count } else { - switch (numberOfSections(in: tableView)) { + switch numberOfSections(in: tableView) { case 3: // Menu Settings - if (section == 2) { + if section == 2 { cont = settingsMenu.count } case 4: // Menu External Site - if (section == 2) { + if section == 2 { cont = externalSiteMenu.count } // Menu Settings - if (section == 3) { + if section == 3 { cont = settingsMenu.count } default: @@ -314,10 +314,10 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { // change color selection and disclosure indicator let selectionColor: UIView = UIView() - if (indexPath.section == 0) { - + if indexPath.section == 0 { + let cell = tableView.dequeueReusableCell(withIdentifier: "userCell", for: indexPath) as! NCMoreUserCell - + cell.avatar.image = nil cell.icon.image = nil cell.status.text = "" @@ -339,7 +339,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { cell.selectedBackgroundView = selectionColor cell.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator - + if NCManageDatabase.shared.getCapabilitiesServerBool(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesUserStatusEnabled, exists: false) { if let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", appDelegate.account)) { let status = NCUtility.shared.getUserStatus(userIcon: account.userStatusIcon, userStatus: account.userStatusStatus, userMessage: account.userStatusMessage) @@ -354,35 +354,35 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { } } } - + return cell - + } else { - + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CCCellMore - + // Menu Normal - if (indexPath.section == 1) { + if indexPath.section == 1 { item = functionMenu[indexPath.row] } // Menu External Site - if (numberOfSections(in: tableView) == 4 && indexPath.section == 2) { + if numberOfSections(in: tableView) == 4 && indexPath.section == 2 { item = externalSiteMenu[indexPath.row] } // Menu Settings - if ((numberOfSections(in: tableView) == 3 && indexPath.section == 2) || (numberOfSections(in: tableView) == 4 && indexPath.section == 3)) { + if (numberOfSections(in: tableView) == 3 && indexPath.section == 2) || (numberOfSections(in: tableView) == 4 && indexPath.section == 3) { item = settingsMenu[indexPath.row] } cell.imageIcon?.image = NCUtility.shared.loadImage(named: item.icon) cell.labelText?.text = NSLocalizedString(item.name, comment: "") cell.labelText.textColor = NCBrandColor.shared.label - + cell.selectedBackgroundView = selectionColor cell.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator - + return cell } } @@ -403,12 +403,12 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { } // Menu External Site - if (numberOfSections(in: tableView) == 4 && indexPath.section == 2) { + if numberOfSections(in: tableView) == 4 && indexPath.section == 2 { item = externalSiteMenu[indexPath.row] } // Menu Settings - if ((numberOfSections(in: tableView) == 3 && indexPath.section == 2) || (numberOfSections(in: tableView) == 4 && indexPath.section == 3)) { + if (numberOfSections(in: tableView) == 3 && indexPath.section == 2) || (numberOfSections(in: tableView) == 4 && indexPath.section == 3) { item = settingsMenu[indexPath.row] } @@ -427,7 +427,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { } } else if item.url.contains("//") { - + let browserWebVC = UIStoryboard(name: "NCBrowserWeb", bundle: nil).instantiateInitialViewController() as! NCBrowserWeb browserWebVC.urlBase = item.url browserWebVC.isHiddenButtonExit = true @@ -440,24 +440,24 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { let alertController = UIAlertController(title: "", message: NSLocalizedString("_want_delete_", comment: ""), preferredStyle: .alert) - let actionYes = UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (action: UIAlertAction) in + let actionYes = UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (_: UIAlertAction) in let manageAccount = CCManageAccount() manageAccount.delete(self.appDelegate.account) - self.appDelegate.openLogin(viewController:self, selector: NCGlobal.shared.introLogin, openLoginWeb: false) + self.appDelegate.openLogin(viewController: self, selector: NCGlobal.shared.introLogin, openLoginWeb: false) } - let actionNo = UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (action: UIAlertAction) in + let actionNo = UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (_: UIAlertAction) in print("You've pressed No button") } alertController.addAction(actionYes) alertController.addAction(actionNo) self.present(alertController, animated: true, completion: nil) - + } else if item.url == "test" { - + } } } diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index e14824728..3c3a1b274 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -39,7 +39,7 @@ class NCGlobal: NSObject { in: username, range: NSRange(username.startIndex..., in: username)) - if (!matches.isEmpty) { + if !matches.isEmpty { // Already a md5 hash? // done, use as is. hash = lowerUsername @@ -68,7 +68,7 @@ class NCGlobal: NSObject { var totalBytes: Int64 var totalBytesExpected: Int64 } - + // Struct for LayoutForView // struct layoutForViewType { @@ -82,7 +82,7 @@ class NCGlobal: NSObject { var imageBackgroud: String var imageBackgroudContentMode: String } - + // Directory on Group // @objc let appDatabaseNextcloud = "Library/Application Support/Nextcloud" @@ -99,7 +99,7 @@ class NCGlobal: NSObject { let metadataKeyedUnarchiver = "it.twsweb.nextcloud.metadata" let refreshTask = "com.nextcloud.refreshTask" let processingTask = "com.nextcloud.processingTask" - + // Nextcloud version // let nextcloudVersion12: Int = 12 @@ -113,33 +113,34 @@ class NCGlobal: NSObject { // let databaseDefault = "nextcloud.realm" let databaseSchemaVersion: UInt64 = 213 - + // Intro selector // @objc let introLogin: Int = 0 let introSignup: Int = 1 - + // Varie size GUI // @objc let heightCellSettings: CGFloat = 50 - + // Avatar & Preview size // let avatarSize: Int = 128 * Int(UIScreen.main.scale) let avatarSizeRounded: Int = 128 let sizePreview: Int = 1024 let sizeIcon: Int = 512 - + // E2EE // let e2eeMaxFileSize: UInt64 = 500000000 // 500 MB let e2eePassphraseTest = "more over television factory tendency independence international intellectual impress interest sentence pony" @objc let e2eeVersion = "1.1" - // Max Cache Proxy Video + // Video // let maxHTTPCache: Int64 = 10000000000 // 10 GB - + let fileNameVideoEncoded: String = "video_encoded.mp4" + // NCSharePaging // enum NCSharePagingIndex: Int, CaseIterable { @@ -154,12 +155,12 @@ class NCGlobal: NSObject { // Nextcloud unsupported // let nextcloud_unsupported_version: Int = 16 - + // Layout // let layoutList = "typeLayoutList" let layoutGrid = "typeLayoutGrid" - + let layoutViewMove = "LayoutMove" let layoutViewTrash = "LayoutTrash" let layoutViewOffline = "LayoutOffline" @@ -175,7 +176,7 @@ class NCGlobal: NSObject { // let buttonMoreMore = "more" let buttonMoreStop = "stop" - + // Text - OnlyOffice - Collabora - QuickLook // let editorText = "text" @@ -192,19 +193,19 @@ class NCGlobal: NSObject { let templateDocument = "document" let templateSpreadsheet = "spreadsheet" let templatePresentation = "presentation" - + // Rich Workspace // let fileNameRichWorkspace = "Readme.md" - + // Extension @objc let extensionPreview = "ico" - + // ContentPresenter // @objc let dismissAfterSecond: TimeInterval = 4 @objc let dismissAfterSecondLong: TimeInterval = 10 - + // Error // @objc let errorNoError: Int = 0 @@ -237,23 +238,23 @@ class NCGlobal: NSObject { @objc let permissionCanDelete = "D" @objc let permissionCanRename = "N" @objc let permissionCanMove = "V" - - //Share permission - //permissions - (int) 1 = read; 2 = update; 4 = create; 8 = delete; 16 = share; 31 = all + + // Share permission + // permissions - (int) 1 = read; 2 = update; 4 = create; 8 = delete; 16 = share; 31 = all // @objc let permissionReadShare: Int = 1 @objc let permissionUpdateShare: Int = 2 @objc let permissionCreateShare: Int = 4 @objc let permissionDeleteShare: Int = 8 @objc let permissionShareShare: Int = 16 - + @objc let permissionMinFileShare: Int = 1 @objc let permissionMaxFileShare: Int = 19 @objc let permissionMinFolderShare: Int = 1 @objc let permissionMaxFolderShare: Int = 31 @objc let permissionDefaultFileRemoteShareNoSupportShareOption: Int = 3 @objc let permissionDefaultFolderRemoteShareNoSupportShareOption: Int = 15 - + // Filename Mask and Type // let keyFileNameMask = "fileNameMask" @@ -303,7 +304,7 @@ class NCGlobal: NSObject { let metadataStatusInUpload: Int = 2 let metadataStatusUploading: Int = 3 let metadataStatusUploadError: Int = 4 - + // Notification Center // @objc let notificationCenterApplicationDidEnterBackground = "applicationDidEnterBackground" @@ -334,7 +335,7 @@ class NCGlobal: NSObject { let notificationCenterUploadCancelFile = "uploadCancelFile" // userInfo: ocId, serverUrl, account let notificationCenterProgressTask = "progressTask" // userInfo: account, ocId, serverUrl, status, progress, totalBytes, totalBytesExpected - + let notificationCenterCreateFolder = "createFolder" // userInfo: ocId let notificationCenterDeleteFile = "deleteFile" // userInfo: ocId, fileNameView, classFile, onlyLocalCache let notificationCenterRenameFile = "renameFile" // userInfo: ocId, errorCode, errorDescription @@ -346,44 +347,19 @@ class NCGlobal: NSObject { let notificationCenterMenuPDFDisplayDirection = "menuPDFDisplayDirection" // userInfo: direction let notificationCenterMenuGotToPageInPDF = "menuGotToPageInPDF" let notificationCenterMenuDetailClose = "menuDetailClose" - + let notificationCenterChangedLocation = "changedLocation" let notificationStatusAuthorizationChangedLocation = "statusAuthorizationChangedLocation" - + let notificationCenterShareChangePermissions = "shareChangePermissions" // userInfo: idShare, permissions, hideDownload - + let notificationCenterDownloadedThumbnail = "DownloadedThumbnail" // userInfo: ocId - + let notificationCenterHidePlayerToolBar = "hidePlayerToolBar" // userInfo: ocId let notificationCenterShowPlayerToolBar = "showPlayerToolBar" // userInfo: ocId, enableTimerAutoHide - let notificationCenterOpenMediaDetail = "openMediaDetail" // userInfo: ocId + let notificationCenterReloadMediaPage = "reloadMediaPage" + let notificationCenterPlayMedia = "playMedia" + let notificationCenterPauseMedia = "pauseMedia" } - -//let rootView = UIApplication.shared.keyWindow?.rootViewController?.view - -/* -DispatchQueue.main.async { -DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) -DispatchQueue.global().async -DispatchQueue.global(qos: .background).async - -#if targetEnvironment(simulator) -#endif - -dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ -dispatch_async(dispatch_get_main_queue(), ^{ -dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) { - -#if TARGET_OS_SIMULATOR -#endif - -if let popoverController = alertController.popoverPresentationController { - popoverController.sourceView = self.view - popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0) - popoverController.permittedArrowDirections = [] -} - -@discardableResult -*/ diff --git a/iOSClient/Networking/NCAutoUpload.swift b/iOSClient/Networking/NCAutoUpload.swift index 3dc563c90..ce5017567 100644 --- a/iOSClient/Networking/NCAutoUpload.swift +++ b/iOSClient/Networking/NCAutoUpload.swift @@ -30,44 +30,44 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { let instance = NCAutoUpload() return instance }() - + private let appDelegate = UIApplication.shared.delegate as! AppDelegate public var locationManager: CLLocationManager? private var endForAssetToUpload: Bool = false // MARK: - - + @objc func startSignificantChangeUpdates() { - + if locationManager == nil { - - locationManager = CLLocationManager.init() + + locationManager = CLLocationManager() locationManager?.delegate = self locationManager?.distanceFilter = 10 } - + locationManager?.requestAlwaysAuthorization() locationManager?.startMonitoringSignificantLocationChanges() } - + @objc func stopSignificantChangeUpdates() { - + locationManager?.stopMonitoringSignificantLocationChanges() } - + func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { - + let location = locations.last guard let latitude = location?.coordinate.latitude else { return } guard let longitude = location?.coordinate.longitude else { return } - + NCCommunicationCommon.shared.writeLog("Location manager: latitude \(latitude) longitude \(longitude)") - + if let activeAccount = NCManageDatabase.shared.getActiveAccount() { if activeAccount.autoUpload && activeAccount.autoUploadBackground && UIApplication.shared.applicationState == UIApplication.State.background { - NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: nil) { (hasPermission) in + NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: nil) { hasPermission in if hasPermission { - self.uploadAssetsNewAndFull(viewController: nil, selector: NCGlobal.shared.selectorUploadAutoUpload, log: "Change location") { (items) in + self.uploadAssetsNewAndFull(viewController: nil, selector: NCGlobal.shared.selectorUploadAutoUpload, log: "Change location") { items in NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUpdateBadgeNumber) if items > 0 { self.appDelegate.networkingProcessUpload?.startProcess() @@ -78,38 +78,38 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { } } } - + func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { if CLLocationManager.authorizationStatus() != CLAuthorizationStatus.authorizedAlways { NCManageDatabase.shared.setAccountAutoUploadProperty("autoUploadBackground", state: false) self.stopSignificantChangeUpdates() } } - + func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { - NCAskAuthorization.shared.askAuthorizationLocationManager() { (hasFullPermissions) in + NCAskAuthorization.shared.askAuthorizationLocationManager { hasFullPermissions in if !hasFullPermissions { NCManageDatabase.shared.setAccountAutoUploadProperty("autoUploadBackground", state: false) self.stopSignificantChangeUpdates() } } } - + // MARK: - - - @objc func initAutoUpload(viewController: UIViewController?, completion: @escaping (_ items: Int)->()) { + + @objc func initAutoUpload(viewController: UIViewController?, completion: @escaping (_ items: Int) -> Void) { if let activeAccount = NCManageDatabase.shared.getActiveAccount() { if activeAccount.autoUpload { - NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { (hasPermission) in + NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { hasPermission in if hasPermission { - self.uploadAssetsNewAndFull(viewController:viewController, selector: NCGlobal.shared.selectorUploadAutoUpload, log: "Init Auto Upload") { (items) in + self.uploadAssetsNewAndFull(viewController: viewController, selector: NCGlobal.shared.selectorUploadAutoUpload, log: "Init Auto Upload") { items in if items > 0 { self.appDelegate.networkingProcessUpload?.startProcess() } completion(items) } if activeAccount.autoUploadBackground { - NCAskAuthorization.shared.askAuthorizationLocationManager() { (hasFullPermissions) in + NCAskAuthorization.shared.askAuthorizationLocationManager { hasFullPermissions in if hasFullPermissions { self.startSignificantChangeUpdates() } else { @@ -132,32 +132,32 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { completion(0) } } - + @objc func autoUploadFullPhotos(viewController: UIViewController?, log: String) { - NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: appDelegate.window?.rootViewController) { (hasPermission) in + NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: appDelegate.window?.rootViewController) { hasPermission in if hasPermission { NCContentPresenter.shared.messageNotification("_attention_", description: "_create_full_upload_", delay: NCGlobal.shared.dismissAfterSecondLong, type: .info, errorCode: NCGlobal.shared.errorNoError, priority: .max) NCUtility.shared.startActivityIndicator(backgroundView: nil, blurEffect: true) - self.uploadAssetsNewAndFull(viewController: viewController, selector: NCGlobal.shared.selectorUploadAutoUploadAll, log: log) { (items) in + self.uploadAssetsNewAndFull(viewController: viewController, selector: NCGlobal.shared.selectorUploadAutoUploadAll, log: log) { _ in NCUtility.shared.stopActivityIndicator() } } } } - - private func uploadAssetsNewAndFull(viewController: UIViewController?, selector: String, log: String, completion: @escaping (_ items: Int)->()) { - + + private func uploadAssetsNewAndFull(viewController: UIViewController?, selector: String, log: String, completion: @escaping (_ items: Int) -> Void) { + if appDelegate.account == "" { return } - + guard let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", appDelegate.account)) else { return } let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: account.urlBase, account: account.account) var counterLivePhoto: Int = 0 var metadataFull: [tableMetadata] = [] var counterItemsUpload: Int = 0 DispatchQueue.global(qos: .background).async { - - self.getCameraRollAssets(viewController: viewController, account: account, selector: selector, alignPhotoLibrary: false) { (assets) in - + + self.getCameraRollAssets(viewController: viewController, account: account, selector: selector, alignPhotoLibrary: false) { assets in + if assets == nil || assets?.count == 0 { NCCommunicationCommon.shared.writeLog("Automatic upload, no new assets found [" + log + "]") DispatchQueue.main.async { @@ -168,7 +168,7 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { NCCommunicationCommon.shared.writeLog("Automatic upload, new \(assets?.count ?? 0) assets found [" + log + "]") } guard let assets = assets else { return } - + // Create the folder for auto upload & if request the subfolders if !NCNetworking.shared.createFolder(assets: assets, selector: selector, useSubFolder: account.autoUploadCreateSubfolder, account: account.account, urlBase: account.urlBase) { DispatchQueue.main.async { @@ -178,39 +178,43 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { return completion(counterItemsUpload) } } - + self.endForAssetToUpload = false - + for asset in assets { - + var livePhoto = false var session: String = "" guard let assetDate = asset.creationDate else { continue } let assetMediaType = asset.mediaType let formatter = DateFormatter() var serverUrl: String = "" - + let fileName = CCUtility.createFileName(asset.value(forKey: "filename") as? String, fileDate: assetDate, fileType: assetMediaType, keyFileName: NCGlobal.shared.keyFileNameAutoUploadMask, keyFileNameType: NCGlobal.shared.keyFileNameAutoUploadType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginalAutoUpload, forcedNewFileName: false)! - + if asset.mediaSubtypes.contains(.photoLive) && CCUtility.getLivePhoto() { livePhoto = true } - + if selector == NCGlobal.shared.selectorUploadAutoUploadAll { session = NCCommunicationCommon.shared.sessionIdentifierUpload } else { - if assetMediaType == PHAssetMediaType.image && account.autoUploadWWAnPhoto == false { session = NCNetworking.shared.sessionIdentifierBackground } - else if assetMediaType == PHAssetMediaType.video && account.autoUploadWWAnVideo == false { session = NCNetworking.shared.sessionIdentifierBackground } - else if assetMediaType == PHAssetMediaType.image && account.autoUploadWWAnPhoto { session = NCNetworking.shared.sessionIdentifierBackgroundWWan } - else if assetMediaType == PHAssetMediaType.video && account.autoUploadWWAnVideo { session = NCNetworking.shared.sessionIdentifierBackgroundWWan } - else { session = NCNetworking.shared.sessionIdentifierBackground } + if assetMediaType == PHAssetMediaType.image && account.autoUploadWWAnPhoto == false { + session = NCNetworking.shared.sessionIdentifierBackground + } else if assetMediaType == PHAssetMediaType.video && account.autoUploadWWAnVideo == false { + session = NCNetworking.shared.sessionIdentifierBackground + } else if assetMediaType == PHAssetMediaType.image && account.autoUploadWWAnPhoto { + session = NCNetworking.shared.sessionIdentifierBackgroundWWan + } else if assetMediaType == PHAssetMediaType.video && account.autoUploadWWAnVideo { + session = NCNetworking.shared.sessionIdentifierBackgroundWWan + } else { session = NCNetworking.shared.sessionIdentifierBackground } } - + formatter.dateFormat = "yyyy" let yearString = formatter.string(from: assetDate) formatter.dateFormat = "MM" let monthString = formatter.string(from: assetDate) - + if account.autoUploadCreateSubfolder { serverUrl = autoUploadPath + "/" + yearString + "/" + monthString } else { @@ -223,15 +227,15 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { if ext == "HEIC" && CCUtility.getFormatCompatibility() { fileNameSearchMetadata = (fileNameSearchMetadata as NSString).deletingPathExtension + ".jpg" } - + if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView == %@", account.account, serverUrl, fileNameSearchMetadata)) != nil { - + if selector == NCGlobal.shared.selectorUploadAutoUpload { NCManageDatabase.shared.addPhotoLibrary([asset], account: account.account) } - + } else { - + /* INSERT METADATA FOR UPLOAD */ let metadataForUpload = NCManageDatabase.shared.createMetadata(account: account.account, user: account.user, userId: account.userId, fileName: fileName, fileNameView: fileName, ocId: NSUUID().uuidString, serverUrl: serverUrl, urlBase: account.urlBase, url: "", contentType: "", livePhoto: livePhoto) metadataForUpload.assetLocalIdentifier = asset.localIdentifier @@ -241,10 +245,10 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload if assetMediaType == PHAssetMediaType.video { metadataForUpload.classFile = NCCommunicationCommon.typeClassFile.video.rawValue - } else if (assetMediaType == PHAssetMediaType.image) { + } else if assetMediaType == PHAssetMediaType.image { metadataForUpload.classFile = NCCommunicationCommon.typeClassFile.image.rawValue } - + if selector == NCGlobal.shared.selectorUploadAutoUpload { NCCommunicationCommon.shared.writeLog("Automatic upload added \(metadataForUpload.fileNameView) (\(metadataForUpload.size) bytes) with Identifier \(metadataForUpload.assetLocalIdentifier)") self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: [metadataForUpload], verifyAlreadyExists: true) @@ -253,16 +257,16 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { metadataFull.append(metadataForUpload) } counterItemsUpload += 1 - + /* INSERT METADATA MOV LIVE PHOTO FOR UPLOAD */ if livePhoto { - + counterLivePhoto += 1 let fileName = (fileName as NSString).deletingPathExtension + ".mov" let ocId = NSUUID().uuidString let filePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)! - - CCUtility.extractLivePhotoAsset(asset, filePath: filePath) { (url) in + + CCUtility.extractLivePhotoAsset(asset, filePath: filePath) { url in if url != nil { let metadataForUpload = NCManageDatabase.shared.createMetadata(account: account.account, user: account.user, userId: account.userId, fileName: fileName, fileNameView: fileName, ocId: ocId, serverUrl: serverUrl, urlBase: account.urlBase, url: "", contentType: "", livePhoto: livePhoto) metadataForUpload.session = session @@ -270,11 +274,11 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { metadataForUpload.size = NCUtilityFileSystem.shared.getFileSize(filePath: filePath) metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload metadataForUpload.classFile = NCCommunicationCommon.typeClassFile.video.rawValue - + if selector == NCGlobal.shared.selectorUploadAutoUpload { NCCommunicationCommon.shared.writeLog("Automatic upload added Live Photo \(metadataForUpload.fileNameView) (\(metadataForUpload.size) bytes) with Identifier \(metadataForUpload.assetLocalIdentifier)") self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: [metadataForUpload], verifyAlreadyExists: true) - + } else if selector == NCGlobal.shared.selectorUploadAutoUploadAll { metadataFull.append(metadataForUpload) } @@ -293,9 +297,9 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { } } } - + self.endForAssetToUpload = true - + if counterLivePhoto == 0 { DispatchQueue.main.async { if selector == NCGlobal.shared.selectorUploadAutoUploadAll { @@ -307,12 +311,12 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { } } } - + // MARK: - @objc func alignPhotoLibrary(viewController: UIViewController?) { if let activeAccount = NCManageDatabase.shared.getActiveAccount() { - getCameraRollAssets(viewController: viewController, account: activeAccount, selector: NCGlobal.shared.selectorUploadAutoUploadAll, alignPhotoLibrary: true) { (assets) in + getCameraRollAssets(viewController: viewController, account: activeAccount, selector: NCGlobal.shared.selectorUploadAutoUploadAll, alignPhotoLibrary: true) { assets in NCManageDatabase.shared.clearTable(tablePhotoLibrary.self, account: activeAccount.account) if let assets = assets { NCManageDatabase.shared.addPhotoLibrary(assets, account: activeAccount.account) @@ -321,14 +325,14 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { } } } - - private func getCameraRollAssets(viewController: UIViewController?, account: tableAccount, selector: String, alignPhotoLibrary: Bool, completion: @escaping (_ assets: [PHAsset]?)->()) { - - NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { (hasPermission) in + + private func getCameraRollAssets(viewController: UIViewController?, account: tableAccount, selector: String, alignPhotoLibrary: Bool, completion: @escaping (_ assets: [PHAsset]?) -> Void) { + + NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { hasPermission in if hasPermission { let assetCollection = PHAssetCollection.fetchAssetCollections(with: PHAssetCollectionType.smartAlbum, subtype: PHAssetCollectionSubtype.smartAlbumUserLibrary, options: nil) if assetCollection.count > 0 { - + let predicateImage = NSPredicate(format: "mediaType == %i", PHAssetMediaType.image.rawValue) let predicateVideo = NSPredicate(format: "mediaType == %i", PHAssetMediaType.video.rawValue) var predicate: NSPredicate? @@ -344,15 +348,15 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { } else { return completion(nil) } - + fetchOptions.predicate = predicate let assets: PHFetchResult<PHAsset> = PHAsset.fetchAssets(in: assetCollection.firstObject!, options: fetchOptions) - + if selector == NCGlobal.shared.selectorUploadAutoUpload { var creationDate = "" var idAsset = "" let idsAsset = NCManageDatabase.shared.getPhotoLibraryIdAsset(image: account.autoUploadImage, video: account.autoUploadVideo, account: account.account) - assets.enumerateObjects { (asset, _, _) in + assets.enumerateObjects { asset, _, _ in if asset.creationDate != nil { creationDate = String(describing: asset.creationDate!) } idAsset = account.account + asset.localIdentifier + creationDate if !(idsAsset?.contains(idAsset) ?? false) { @@ -360,7 +364,7 @@ class NCAutoUpload: NSObject, CLLocationManagerDelegate { } } } else { - assets.enumerateObjects { (asset, _, _) in + assets.enumerateObjects { asset, _, _ in newAssets.append(asset) } } diff --git a/iOSClient/Networking/NCNetworking.swift b/iOSClient/Networking/NCNetworking.swift index c21d98c33..35a8356be 100644 --- a/iOSClient/Networking/NCNetworking.swift +++ b/iOSClient/Networking/NCNetworking.swift @@ -39,17 +39,15 @@ import Queuer let instance = NCNetworking() return instance }() - - var delegate: NCNetworkingDelegate? - + + weak var delegate: NCNetworkingDelegate? + var lastReachability: Bool = true var networkReachability: NCCommunicationCommon.typeReachability? var downloadRequest: [String: DownloadRequest] = [:] var uploadRequest: [String: UploadRequest] = [:] var uploadMetadataInBackground: [String: tableMetadata] = [:] - var certificatesError: String? - @objc public let sessionMaximumConnectionsPerHost = 5 @objc public let sessionIdentifierBackground: String = "com.nextcloud.session.upload.background" @objc public let sessionIdentifierBackgroundWWan: String = "com.nextcloud.session.upload.backgroundWWan" @@ -65,7 +63,7 @@ import Queuer let session = URLSession(configuration: configuration, delegate: NCCommunicationBackground.shared, delegateQueue: OperationQueue.main) return session }() - + @objc public lazy var sessionManagerBackgroundWWan: URLSession = { let configuration = URLSessionConfiguration.background(withIdentifier: sessionIdentifierBackgroundWWan) configuration.allowsCellularAccess = false @@ -76,7 +74,7 @@ import Queuer let session = URLSession(configuration: configuration, delegate: NCCommunicationBackground.shared, delegateQueue: OperationQueue.main) return session }() - + #if EXTENSION @objc public lazy var sessionManagerBackgroundExtension: URLSession = { let configuration = URLSessionConfiguration.background(withIdentifier: sessionIdentifierBackgroundExtension) @@ -90,12 +88,12 @@ import Queuer return session }() #endif - - //MARK: - init - + + // MARK: - init + override init() { super.init() - + #if EXTENSION _ = sessionIdentifierBackgroundExtension #else @@ -103,50 +101,50 @@ import Queuer _ = sessionManagerBackgroundWWan #endif } - - //MARK: - Communication Delegate - + + // MARK: - Communication Delegate + func networkReachabilityObserver(_ typeReachability: NCCommunicationCommon.typeReachability) { - + #if !EXTENSION if typeReachability == NCCommunicationCommon.typeReachability.reachableCellular || typeReachability == NCCommunicationCommon.typeReachability.reachableEthernetOrWiFi { - + if !lastReachability { NCService.shared.startRequestServicesServer() } lastReachability = true - + } else { - + if lastReachability { NCContentPresenter.shared.messageNotification("_network_not_available_", description: nil, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: -1009) } lastReachability = false } - + networkReachability = typeReachability #endif } - + func authenticationChallenge(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { - + if checkTrustedChallenge(session, didReceive: challenge) { - completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential.init(trust: challenge.protectionSpace.serverTrust!)) + completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!)) } else { completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil) } } - + func downloadProgress(_ progress: Float, totalBytes: Int64, totalBytesExpected: Int64, fileName: String, serverUrl: String, session: URLSession, task: URLSessionTask) { delegate?.downloadProgress?(progress, totalBytes: totalBytes, totalBytesExpected: totalBytesExpected, fileName: fileName, serverUrl: serverUrl, session: session, task: task) } - + func downloadComplete(fileName: String, serverUrl: String, etag: String?, date: NSDate?, dateLastModified: NSDate?, length: Int64, description: String?, task: URLSessionTask, errorCode: Int, errorDescription: String) { delegate?.downloadComplete?(fileName: fileName, serverUrl: serverUrl, etag: etag, date: date, dateLastModified: dateLastModified, length: length, description: description, task: task, errorCode: errorCode, errorDescription: errorDescription) } - + func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { - + #if !EXTENSION if let appDelegate = UIApplication.shared.delegate as? AppDelegate, let completionHandler = appDelegate.backgroundSessionCompletionHandler { NCCommunicationCommon.shared.writeLog("Called urlSessionDidFinishEvents for Background URLSession") @@ -155,202 +153,197 @@ import Queuer } #endif } - - //MARK: - Pinning check - + + // MARK: - Pinning check + private func checkTrustedChallenge(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge) -> Bool { - + let protectionSpace: URLProtectionSpace = challenge.protectionSpace let directoryCertificate = CCUtility.getDirectoryCerificates()! let host = challenge.protectionSpace.host - let pushNotificationServerProxyHost = URL(string: NCBrandOptions.shared.pushNotificationServerProxy)?.host - + let certificateSavedPath = directoryCertificate + "/" + host + ".der" + var isTrusted: Bool + + #if !EXTENSION + defer { + DispatchQueue.main.async { + if !isTrusted { + (UIApplication.shared.delegate as? AppDelegate)?.trustCertificateError(host: host) + } + } + } + #endif + print("SSL host: \(host)") - if let serverTrust: SecTrust = protectionSpace.serverTrust { - - saveX509Certificate(serverTrust, host: host, directoryCertificate: directoryCertificate) + if let serverTrust: SecTrust = protectionSpace.serverTrust, let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0) { + // extarct certificate txt + saveX509Certificate(certificate, host: host, directoryCertificate: directoryCertificate) + var secresult = SecTrustResultType.invalid let status = SecTrustEvaluate(serverTrust, &secresult) - if errSecSuccess == status, let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) { - - let serverCertificateData = SecCertificateCopyData(serverCertificate) - let data = CFDataGetBytePtr(serverCertificateData); - let size = CFDataGetLength(serverCertificateData); - let certificate = NSData(bytes: data, length: size) - - // write certificate tmp to disk - certificate.write(toFile: directoryCertificate + "/" + host + ".tmp", atomically: true) + let isServerTrusted = SecTrustEvaluateWithError(serverTrust, nil) + + let certificateCopyData = SecCertificateCopyData(certificate) + let data = CFDataGetBytePtr(certificateCopyData); + let size = CFDataGetLength(certificateCopyData); + let certificateData = NSData(bytes: data, length: size) - // verify - let certificateSavedPath = directoryCertificate + "/" + host + ".der" - if let certificateSaved = NSData(contentsOfFile: certificateSavedPath), certificate.isEqual(to: certificateSaved as Data) { - return true - } + certificateData.write(toFile: directoryCertificate + "/" + host + ".tmp", atomically: true) + + if isServerTrusted { + isTrusted = true + } else if status == errSecSuccess, let certificateDataSaved = NSData(contentsOfFile: certificateSavedPath), certificateData.isEqual(to: certificateDataSaved as Data) { + isTrusted = true + } else { + isTrusted = false } + } else { + isTrusted = false } - if host != pushNotificationServerProxyHost { - NCNetworking.shared.certificatesError = host - } - - return false + return isTrusted } - + func writeCertificate(host: String) { - + let directoryCertificate = CCUtility.getDirectoryCerificates()! let certificateAtPath = directoryCertificate + "/" + host + ".tmp" let certificateToPath = directoryCertificate + "/" + host + ".der" - + if !NCUtilityFileSystem.shared.moveFile(atPath: certificateAtPath, toPath: certificateToPath) { NCContentPresenter.shared.messageNotification("_error_", description: "_error_creation_file_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorCreationFile, priority: .max) } } - private func saveX509Certificate(_ serverTrust: SecTrust, host: String, directoryCertificate: String) { + private func saveX509Certificate(_ certificate: SecCertificate, host: String, directoryCertificate: String) { - if let currentServerCert = SecTrustGetCertificateAtIndex(serverTrust, 0) { - - let certNamePathTXT = directoryCertificate + "/" + host + ".txt" - let data: CFData = SecCertificateCopyData(currentServerCert) - let mem = BIO_new_mem_buf(CFDataGetBytePtr(data), Int32(CFDataGetLength(data))) - let x509cert = d2i_X509_bio(mem, nil) + let certNamePathTXT = directoryCertificate + "/" + host + ".txt" + let data: CFData = SecCertificateCopyData(certificate) + let mem = BIO_new_mem_buf(CFDataGetBytePtr(data), Int32(CFDataGetLength(data))) + let x509cert = d2i_X509_bio(mem, nil) - if x509cert == nil { - print("[LOG] OpenSSL couldn't parse X509 Certificate") - } else { - - // save certificate -// if FileManager.default.fileExists(atPath: certNamePath) { -// do { -// try FileManager.default.removeItem(atPath: certNamePath) -// } catch { } -// } -// let fileCert = fopen(certNamePath, "w") -// if fileCert != nil { -// PEM_write_X509(fileCert, x509cert) -// } -// fclose(fileCert) - - // save details - if FileManager.default.fileExists(atPath: certNamePathTXT) { - do { - try FileManager.default.removeItem(atPath: certNamePathTXT) - } catch { } - } - let fileCertInfo = fopen(certNamePathTXT, "w") - if fileCertInfo != nil { - let output = BIO_new_fp(fileCertInfo, BIO_NOCLOSE) - X509_print_ex(output, x509cert, UInt(XN_FLAG_COMPAT), UInt(X509_FLAG_COMPAT)) - BIO_free(output) - } - fclose(fileCertInfo) + if x509cert == nil { + print("[LOG] OpenSSL couldn't parse X509 Certificate") + } else { - X509_free(x509cert) + // save details + if FileManager.default.fileExists(atPath: certNamePathTXT) { + do { + try FileManager.default.removeItem(atPath: certNamePathTXT) + } catch { } } - - BIO_free(mem) + let fileCertInfo = fopen(certNamePathTXT, "w") + if fileCertInfo != nil { + let output = BIO_new_fp(fileCertInfo, BIO_NOCLOSE) + X509_print_ex(output, x509cert, UInt(XN_FLAG_COMPAT), UInt(X509_FLAG_COMPAT)) + BIO_free(output) + } + fclose(fileCertInfo) + + X509_free(x509cert) } + + BIO_free(mem) } - - func checkPushNotificationServerProxyCertificateUntrusted(viewController: UIViewController?, completion: @escaping (_ errorCode: Int)->()) { - + + func checkPushNotificationServerProxyCertificateUntrusted(viewController: UIViewController?, completion: @escaping (_ errorCode: Int) -> Void) { + guard let host = URL(string: NCBrandOptions.shared.pushNotificationServerProxy)?.host else { return } - - NCCommunication.shared.checkServer(serverUrl: NCBrandOptions.shared.pushNotificationServerProxy) { (errorCode, errorDescription) in - + + NCCommunication.shared.checkServer(serverUrl: NCBrandOptions.shared.pushNotificationServerProxy) { errorCode, _ in + if errorCode == 0 { - + NCNetworking.shared.writeCertificate(host: host) completion(errorCode) - + } else if errorCode == NSURLErrorServerCertificateUntrusted { - + let alertController = UIAlertController(title: NSLocalizedString("_ssl_certificate_untrusted_", comment: ""), message: NSLocalizedString("_connect_server_anyway_", comment: ""), preferredStyle: .alert) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { action in + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { _ in NCNetworking.shared.writeCertificate(host: host) completion(0) })) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { _ in completion(errorCode) })) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { action in + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { _ in if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() as? UINavigationController { let vcCertificateDetails = navigationController.topViewController as! NCViewCertificateDetails vcCertificateDetails.host = host viewController?.present(navigationController, animated: true) } })) - + viewController?.present(alertController, animated: true) - + } else { - + completion(0) } } } - - //MARK: - Utility - + + // MARK: - Utility + func cancelTaskWithUrl(_ url: URL) { - NCCommunication.shared.getSessionManager().getAllTasks { tasks in + NCCommunication.shared.getSessionManager().getAllTasks { tasks in tasks.filter { $0.state == .running }.filter { $0.originalRequest?.url == url }.first?.cancel() } } - + @objc func cancelAllTask() { - NCCommunication.shared.getSessionManager().getAllTasks { tasks in + NCCommunication.shared.getSessionManager().getAllTasks { tasks in for task in tasks { task.cancel() } } } - - //MARK: - Download - - @objc func cancelDownload(ocId: String, serverUrl:String, fileNameView: String) { - + + // MARK: - Download + + @objc func cancelDownload(ocId: String, serverUrl: String, fileNameView: String) { + #if !EXTENSION // removed progress ocid DispatchQueue.main.async { (UIApplication.shared.delegate as! AppDelegate).listProgress[ocId] = nil } #endif - + guard let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameView) else { return } - + if let request = downloadRequest[fileNameLocalPath] { request.cancel() } else { if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - + NCManageDatabase.shared.setMetadataSession(ocId: ocId, session: "", sessionError: "", sessionSelector: "", sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusNormal) - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadCancelFile, userInfo: ["ocId":metadata.ocId]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadCancelFile, userInfo: ["ocId": metadata.ocId]) } } } - @objc func download(metadata: tableMetadata, selector: String, completion: @escaping (_ errorCode: Int)->()) { + @objc func download(metadata: tableMetadata, selector: String, notificationCenterProgressTask: Bool = true, progressHandler: @escaping (_ progress: Progress) -> () = { _ in }, completion: @escaping (_ errorCode: Int)->()) { let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileName)! - + if NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) == nil { NCManageDatabase.shared.addMetadata(tableMetadata.init(value: metadata)) } - + if metadata.status == NCGlobal.shared.metadataStatusInDownload || metadata.status == NCGlobal.shared.metadataStatusDownloading { return } - + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: NCCommunicationCommon.shared.sessionIdentifierDownload, sessionError: "", sessionSelector: selector, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusInDownload) - - NCCommunication.shared.download(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, queue: NCCommunicationCommon.shared.backgroundQueue, requestHandler: { (request) in - + + NCCommunication.shared.download(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, queue: NCCommunicationCommon.shared.backgroundQueue, requestHandler: { request in + self.downloadRequest[fileNameLocalPath] = request - + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusDownloading) NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadStartFile, userInfo: ["ocId":metadata.ocId]) @@ -358,68 +351,72 @@ import Queuer }, progressHandler: { (progress) in - #if !EXTENSION - // add progress ocid - let progressType = NCGlobal.progressType(progress: Float(progress.fractionCompleted), totalBytes: progress.totalUnitCount, totalBytesExpected: progress.completedUnitCount) - DispatchQueue.main.async { (UIApplication.shared.delegate as! AppDelegate).listProgress[metadata.ocId] = progressType } - #endif - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterProgressTask, object: nil, userInfo: ["account":metadata.account, "ocId":metadata.ocId, "fileName":metadata.fileName, "serverUrl":metadata.serverUrl, "status":NSNumber(value: NCGlobal.shared.metadataStatusInDownload), "progress":NSNumber(value: progress.fractionCompleted), "totalBytes":NSNumber(value: progress.totalUnitCount), "totalBytesExpected":NSNumber(value: progress.completedUnitCount)]) + if notificationCenterProgressTask { + #if !EXTENSION + // add progress ocid + let progressType = NCGlobal.progressType(progress: Float(progress.fractionCompleted), totalBytes: progress.totalUnitCount, totalBytesExpected: progress.completedUnitCount) + DispatchQueue.main.async { (UIApplication.shared.delegate as! AppDelegate).listProgress[metadata.ocId] = progressType } + #endif + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterProgressTask, object: nil, userInfo: ["account":metadata.account, "ocId":metadata.ocId, "fileName":metadata.fileName, "serverUrl":metadata.serverUrl, "status":NSNumber(value: NCGlobal.shared.metadataStatusInDownload), "progress":NSNumber(value: progress.fractionCompleted), "totalBytes":NSNumber(value: progress.totalUnitCount), "totalBytesExpected":NSNumber(value: progress.completedUnitCount)]) + } + progressHandler(progress) + }) { (account, etag, date, length, allHeaderFields, error, errorCode, errorDescription) in if error?.isExplicitlyCancelledError ?? false { - + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: "", sessionError: "", sessionSelector: selector, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusNormal) - + } else if errorCode == 0 { - + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: "", sessionError: "", sessionSelector: selector, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusNormal, etag: etag) NCManageDatabase.shared.addLocalFile(metadata: metadata) - + #if !EXTENSION if let result = NCManageDatabase.shared.getE2eEncryption(predicate: NSPredicate(format: "fileNameIdentifier == %@ AND serverUrl == %@", metadata.fileName, metadata.serverUrl)) { - + NCEndToEndEncryption.sharedManager()?.decryptFileName(metadata.fileName, fileNameView: metadata.fileNameView, ocId: metadata.ocId, key: result.key, initializationVector: result.initializationVector, authenticationTag: result.authenticationTag) } - CCUtility.setExif(metadata) { (latitude, longitude, location, date, lensMode) in }; + CCUtility.setExif(metadata) { _, _, _, _, _ in } #endif - + } else { - + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: "", sessionError: errorDescription, sessionSelector: selector, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusDownloadError) - + #if !EXTENSION if errorCode == 401 || errorCode == 403 { NCNetworkingCheckRemoteUser.shared.checkRemoteUser(account: metadata.account, errorCode: errorCode, errorDescription: errorDescription) - } + } #endif } - + self.downloadRequest[fileNameLocalPath] = nil #if !EXTENSION DispatchQueue.main.async { (UIApplication.shared.delegate as! AppDelegate).listProgress[metadata.ocId] = nil } #endif - + if error?.isExplicitlyCancelledError ?? false { - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadCancelFile, userInfo: ["ocId":metadata.ocId]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadCancelFile, userInfo: ["ocId": metadata.ocId]) } else { - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId":metadata.ocId, "selector":selector, "errorCode":errorCode, "errorDescription":errorDescription]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": selector, "errorCode": errorCode, "errorDescription": errorDescription]) } - + completion(errorCode) } } - - //MARK: - Upload - @objc func upload(metadata: tableMetadata, start: @escaping () -> Void, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - + // MARK: - Upload + + @objc func upload(metadata: tableMetadata, start: @escaping () -> Void, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + var metadata = tableMetadata.init(value: metadata) var fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! - + if CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { - + let results = NCCommunicationCommon.shared.getInternalType(fileName: metadata.fileNameView, mimeType: metadata.contentType, directory: false) metadata.contentType = results.mimeType metadata.iconName = results.iconName @@ -431,10 +428,10 @@ import Queuer metadata.date = date } metadata.size = NCUtilityFileSystem.shared.getFileSize(filePath: fileNameLocalPath) - + NCManageDatabase.shared.addMetadata(metadata) metadata = tableMetadata.init(value: metadata) - + if metadata.e2eEncrypted { #if !EXTENSION_FILE_PROVIDER_EXTENSION NCNetworkingE2EE.shared.upload(metadata: tableMetadata.init(value: metadata), start: { start() }, completion: completion) @@ -446,22 +443,22 @@ import Queuer } else { uploadFileInBackground(metadata: metadata, start: { start() }, completion: completion) } - + } else { - - CCUtility.extractImageVideoFromAssetLocalIdentifier(forUpload: metadata, notification: true) { (extractMetadata, fileNamePath) in - + + CCUtility.extractImageVideoFromAssetLocalIdentifier(forUpload: metadata, notification: true) { extractMetadata, fileNamePath in + guard let extractMetadata = extractMetadata else { NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) return completion(NCGlobal.shared.errorInternalError, "Internal error") } - + let metadata = tableMetadata.init(value: extractMetadata) fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(extractMetadata.ocId, fileNameView: extractMetadata.fileNameView) NCUtilityFileSystem.shared.moveFileInBackground(atPath: fileNamePath!, toPath: fileNameLocalPath) NCManageDatabase.shared.addMetadata(extractMetadata) - + if metadata.e2eEncrypted { #if !EXTENSION_FILE_PROVIDER_EXTENSION NCNetworkingE2EE.shared.upload(metadata: extractMetadata, start: { start() }, completion: completion) @@ -476,118 +473,128 @@ import Queuer } } } - - private func uploadFile(metadata: tableMetadata, start: @escaping () -> Void, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - + + private func uploadFile(metadata: tableMetadata, start: @escaping () -> Void, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! var uploadTask: URLSessionTask? let description = metadata.ocId - - NCCommunication.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: metadata.creationDate as Date, dateModificationFile: metadata.date as Date, customUserAgent: nil, addCustomHeaders: nil, requestHandler: { (request) in - + + NCCommunication.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: metadata.creationDate as Date, dateModificationFile: metadata.date as Date, customUserAgent: nil, addCustomHeaders: nil, requestHandler: { request in + self.uploadRequest[fileNameLocalPath] = request - - }, taskHandler: { (task) in - + + }, taskHandler: { task in + uploadTask = task NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, sessionError: "", sessionTaskIdentifier: task.taskIdentifier, status: NCGlobal.shared.metadataStatusUploading) - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId":metadata.ocId]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId": metadata.ocId]) start() - - }, progressHandler: { (progress) in - + + }, progressHandler: { progress in + #if !EXTENSION // add progress ocid let progressType = NCGlobal.progressType(progress: Float(progress.fractionCompleted), totalBytes: progress.totalUnitCount, totalBytesExpected: progress.completedUnitCount) DispatchQueue.main.async { (UIApplication.shared.delegate as! AppDelegate).listProgress[metadata.ocId] = progressType } #endif - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterProgressTask, userInfo: ["account":metadata.account, "ocId":metadata.ocId, "fileName":metadata.fileName, "serverUrl":metadata.serverUrl, "status":NSNumber(value: NCGlobal.shared.metadataStatusInUpload), "progress":NSNumber(value: progress.fractionCompleted), "totalBytes":NSNumber(value: progress.totalUnitCount), "totalBytesExpected":NSNumber(value: progress.completedUnitCount)]) - - }) { (account, ocId, etag, date, size, allHeaderFields, error, errorCode, errorDescription) in - + + NotificationCenter.default.postOnMainThread( + name: NCGlobal.shared.notificationCenterProgressTask, + userInfo: [ + "account": metadata.account, + "ocId": metadata.ocId, + "fileName": metadata.fileName, + "serverUrl": metadata.serverUrl, + "status": NSNumber(value: NCGlobal.shared.metadataStatusInUpload), + "progress": NSNumber(value: progress.fractionCompleted), + "totalBytes": NSNumber(value: progress.totalUnitCount), + "totalBytesExpected": NSNumber(value: progress.completedUnitCount)]) + + }) { _, ocId, etag, date, size, _, _, errorCode, errorDescription in + self.uploadRequest[fileNameLocalPath] = nil self.uploadComplete(fileName: metadata.fileName, serverUrl: metadata.serverUrl, ocId: ocId, etag: etag, date: date, size: size, description: description, task: uploadTask!, errorCode: errorCode, errorDescription: errorDescription) - + completion(errorCode, errorDescription) } } - - private func uploadFileInBackground(metadata: tableMetadata, start: @escaping () -> Void, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - + + private func uploadFileInBackground(metadata: tableMetadata, start: @escaping () -> Void, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + var session: URLSession? let metadata = tableMetadata.init(value: metadata) let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! - + if metadata.session == sessionIdentifierBackground || metadata.session == sessionIdentifierBackgroundExtension { session = sessionManagerBackground } else if metadata.session == sessionIdentifierBackgroundWWan { session = sessionManagerBackgroundWWan } - + start() - + // Check file dim > 0 if NCUtilityFileSystem.shared.getFileSize(filePath: fileNameLocalPath) == 0 { - + NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) - + completion(NCGlobal.shared.errorResourceNotFound, NSLocalizedString("_error_not_found_", value: "The requested resource could not be found", comment: "")) - + } else { - + if let task = NCCommunicationBackground.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: metadata.creationDate as Date, dateModificationFile: metadata.date as Date, description: metadata.ocId, session: session!) { - + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, sessionError: "", sessionTaskIdentifier: task.taskIdentifier, status: NCGlobal.shared.metadataStatusUploading) - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId":metadata.ocId]) - + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId": metadata.ocId]) + completion(0, "") - + } else { - + NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) completion(NCGlobal.shared.errorInternalError, "task null") } } } - + func uploadComplete(fileName: String, serverUrl: String, ocId: String?, etag: String?, date: NSDate?, size: Int64, description: String?, task: URLSessionTask, errorCode: Int, errorDescription: String) { if delegate != nil { - delegate?.uploadComplete?(fileName: fileName, serverUrl: serverUrl, ocId: ocId, etag: etag, date: date, size:size, description: description, task: task, errorCode: errorCode, errorDescription: errorDescription) + delegate?.uploadComplete?(fileName: fileName, serverUrl: serverUrl, ocId: ocId, etag: etag, date: date, size: size, description: description, task: task, errorCode: errorCode, errorDescription: errorDescription) } else { - + guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(description) else { return } guard let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", metadata.account)) else { return } let ocIdTemp = metadata.ocId var errorDescription = errorDescription - + if errorCode == 0 && ocId != nil && size > 0 { - + let metadata = tableMetadata.init(value: metadata) - + NCUtilityFileSystem.shared.moveFileInBackground(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId), toPath: CCUtility.getDirectoryProviderStorageOcId(ocId)) - + metadata.uploadDate = date ?? NSDate() metadata.etag = etag ?? "" metadata.ocId = ocId! - + if let fileId = NCUtility.shared.ocIdToFileId(ocId: ocId) { metadata.fileId = fileId } - + metadata.session = "" metadata.sessionError = "" metadata.sessionTaskIdentifier = 0 metadata.status = NCGlobal.shared.metadataStatusNormal - + // Delete Asset on Photos album if tableAccount.autoUploadDeleteAssetLocalIdentifier && metadata.assetLocalIdentifier != "" && metadata.sessionSelector == NCGlobal.shared.selectorUploadAutoUpload { - metadata.deleteAssetLocalIdentifier = true; + metadata.deleteAssetLocalIdentifier = true } - + if CCUtility.getDisableLocalCacheAfterUpload() { CCUtility.removeFile(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)) } else { @@ -595,93 +602,103 @@ import Queuer } NCManageDatabase.shared.addMetadata(metadata) NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp)) - + #if !EXTENSION - self.getOcIdInBackgroundSession { (listOcId) in + self.getOcIdInBackgroundSession { listOcId in if listOcId.count == 0 && self.uploadRequest.count == 0 { let appDelegate = UIApplication.shared.delegate as! AppDelegate appDelegate.networkingProcessUpload?.startProcess() } } - CCUtility.setExif(metadata) { (latitude, longitude, location, date, lensMode) in }; + CCUtility.setExif(metadata) { _, _, _, _, _ in } #endif - + NCCommunicationCommon.shared.writeLog("Upload complete " + serverUrl + "/" + fileName + ", result: success(\(size) bytes)") - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId":metadata.ocId, "ocIdTemp":ocIdTemp, "errorCode":errorCode, "errorDescription":""]) - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "ocIdTemp": ocIdTemp, "errorCode": errorCode, "errorDescription": ""]) + } else { - + if errorCode == NSURLErrorCancelled || errorCode == NCGlobal.shared.errorRequestExplicityCancelled { - + CCUtility.removeFile(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)) NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadCancelFile, userInfo: ["ocId":metadata.ocId, "serverUrl":metadata.serverUrl, "account":metadata.account]) - + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadCancelFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account]) + } else if errorCode == 401 || errorCode == 403 { - + #if !EXTENSION NCNetworkingCheckRemoteUser.shared.checkRemoteUser(account: metadata.account, errorCode: errorCode, errorDescription: errorDescription) #endif - + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: nil, sessionError: errorDescription, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusUploadError) } else { - + if size == 0 { errorDescription = "File length 0" NCCommunicationCommon.shared.writeLog("Upload error 0 length " + serverUrl + "/" + fileName + ", result: success(\(size) bytes)") } - + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: nil, sessionError: errorDescription, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusUploadError) } - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId":metadata.ocId, "ocIdTemp":ocIdTemp, "errorCode":errorCode, "errorDescription":""]) + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "ocIdTemp": ocIdTemp, "errorCode": errorCode, "errorDescription": ""]) } - + #if !EXTENSION DispatchQueue.main.async { (UIApplication.shared.delegate as! AppDelegate).listProgress[metadata.ocId] = nil } #endif - + // Delete self.uploadMetadataInBackground[fileName+serverUrl] = nil } } - + func uploadProgress(_ progress: Float, totalBytes: Int64, totalBytesExpected: Int64, fileName: String, serverUrl: String, session: URLSession, task: URLSessionTask) { delegate?.uploadProgress?(progress, totalBytes: totalBytes, totalBytesExpected: totalBytesExpected, fileName: fileName, serverUrl: serverUrl, session: session, task: task) - + var metadata: tableMetadata? let description: String = task.taskDescription ?? "" - + if let metadataTmp = self.uploadMetadataInBackground[fileName+serverUrl] { metadata = metadataTmp - } else if let metadataTmp = NCManageDatabase.shared.getMetadataFromOcId(description){ + } else if let metadataTmp = NCManageDatabase.shared.getMetadataFromOcId(description) { self.uploadMetadataInBackground[fileName+serverUrl] = metadataTmp metadata = metadataTmp } - + if let metadata = metadata { - + #if !EXTENSION // add progress ocid let progressType = NCGlobal.progressType(progress: progress, totalBytes: totalBytes, totalBytesExpected: totalBytesExpected) DispatchQueue.main.async { (UIApplication.shared.delegate as! AppDelegate).listProgress[metadata.ocId] = progressType } #endif - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterProgressTask, userInfo: ["account":metadata.account, "ocId":metadata.ocId, "fileName":metadata.fileName, "serverUrl":serverUrl, "status":NSNumber(value: NCGlobal.shared.metadataStatusInUpload), "progress":NSNumber(value: progress), "totalBytes":NSNumber(value: totalBytes), "totalBytesExpected":NSNumber(value: totalBytesExpected)]) + + NotificationCenter.default.postOnMainThread( + name: NCGlobal.shared.notificationCenterProgressTask, + userInfo: [ + "account": metadata.account, + "ocId": metadata.ocId, + "fileName": metadata.fileName, + "serverUrl": serverUrl, + "status": NSNumber(value: NCGlobal.shared.metadataStatusInUpload), + "progress": NSNumber(value: progress), + "totalBytes": NSNumber(value: totalBytes), + "totalBytesExpected": NSNumber(value: totalBytesExpected)]) } } - - func getOcIdInBackgroundSession(completion: @escaping (_ listOcId: [String])->()) { - + + func getOcIdInBackgroundSession(completion: @escaping (_ listOcId: [String]) -> Void) { + var listOcId: [String] = [] - - sessionManagerBackground.getAllTasks(completionHandler: { (tasks) in + + sessionManagerBackground.getAllTasks(completionHandler: { tasks in for task in tasks { listOcId.append(task.description) } - self.sessionManagerBackgroundWWan.getAllTasks(completionHandler: { (tasks) in + self.sessionManagerBackgroundWWan.getAllTasks(completionHandler: { tasks in for task in tasks { listOcId.append(task.description) } @@ -689,44 +706,44 @@ import Queuer }) }) } - - //MARK: - Transfer (Download Upload) - - @objc func cancelTransferMetadata(_ metadata: tableMetadata, completion: @escaping ()->()) { - + + // MARK: - Transfer (Download Upload) + + @objc func cancelTransferMetadata(_ metadata: tableMetadata, completion: @escaping () -> Void) { + let metadata = tableMetadata.init(value: metadata) #if !EXTENSION // removed progress ocid DispatchQueue.main.async { (UIApplication.shared.delegate as! AppDelegate).listProgress[metadata.ocId] = nil } #endif - + if metadata.session.count == 0 { NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) return completion() } if metadata.session == NCCommunicationCommon.shared.sessionIdentifierDownload { - + NCNetworking.shared.cancelDownload(ocId: metadata.ocId, serverUrl: metadata.serverUrl, fileNameView: metadata.fileNameView) return completion() } - + if metadata.session == NCCommunicationCommon.shared.sessionIdentifierUpload { - + guard let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView) else { return } - + if let request = uploadRequest[fileNameLocalPath] { request.cancel() } else { CCUtility.removeFile(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)) NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadCancelFile, userInfo: ["ocId":metadata.ocId, "serverUrl":metadata.serverUrl, "account":metadata.account]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadCancelFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account]) } - + return completion() } - + var session: URLSession? if metadata.session == NCNetworking.shared.sessionIdentifierBackground { session = NCNetworking.shared.sessionManagerBackground @@ -735,12 +752,12 @@ import Queuer } if session == nil { NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadCancelFile, userInfo: ["ocId":metadata.ocId, "serverUrl":metadata.serverUrl, "account":metadata.account]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadCancelFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account]) return completion() } - - session?.getTasksWithCompletionHandler { (dataTasks, uploadTasks, downloadTasks) in - + + session?.getTasksWithCompletionHandler { _, uploadTasks, _ in + var cancel = false if metadata.session.count > 0 && metadata.session.contains("upload") { for task in uploadTasks { @@ -752,33 +769,32 @@ import Queuer if cancel == false { do { try FileManager.default.removeItem(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)) - } - catch { } + } catch { } NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadCancelFile, userInfo: ["ocId":metadata.ocId, "serverUrl":metadata.serverUrl, "account":metadata.account]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadCancelFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account]) } } completion() } } - - @objc func cancelAllTransfer(account: String, completion: @escaping ()->()) { - + + @objc func cancelAllTransfer(account: String, completion: @escaping () -> Void) { + NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "status == %d OR status == %d", account, NCGlobal.shared.metadataStatusWaitUpload, NCGlobal.shared.metadataStatusUploadError)) - + let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "status != %d", NCGlobal.shared.metadataStatusNormal)) - + var counter = 0 for metadata in metadatas { counter += 1 - if (metadata.status == NCGlobal.shared.metadataStatusWaitDownload || metadata.status == NCGlobal.shared.metadataStatusDownloadError) { - + if metadata.status == NCGlobal.shared.metadataStatusWaitDownload || metadata.status == NCGlobal.shared.metadataStatusDownloadError { + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: "", sessionError: "", sessionSelector: "", sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusNormal) } - + if metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusUploading { - + self.cancelTransferMetadata(metadata) { if counter == metadatas.count { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { @@ -788,124 +804,124 @@ import Queuer } } } - + #if !EXTENSION NCOperationQueue.shared.downloadCancelAll() #endif } - + func cancelAllDownloadTransfer() { - + let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "status != %d", NCGlobal.shared.metadataStatusNormal)) - + for metadata in metadatas { - if (metadata.status == NCGlobal.shared.metadataStatusWaitDownload || metadata.status == NCGlobal.shared.metadataStatusDownloadError) { - + if metadata.status == NCGlobal.shared.metadataStatusWaitDownload || metadata.status == NCGlobal.shared.metadataStatusDownloadError { + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: "", sessionError: "", sessionSelector: "", sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusNormal) } - + if metadata.status == NCGlobal.shared.metadataStatusDownloading && metadata.session == NCCommunicationCommon.shared.sessionIdentifierDownload { cancelDownload(ocId: metadata.ocId, serverUrl: metadata.serverUrl, fileNameView: metadata.fileNameView) } } - + #if !EXTENSION NCOperationQueue.shared.downloadCancelAll() #endif } - - //MARK: - WebDav Read file, folder - - @objc func readFolder(serverUrl: String, account: String, completion: @escaping (_ account: String, _ metadataFolder: tableMetadata?, _ metadatas: [tableMetadata]?, _ metadatasUpdate: [tableMetadata]?, _ metadatasLocalUpdate: [tableMetadata]?, _ metadatasDelete: [tableMetadata]?, _ errorCode: Int, _ errorDescription: String)->()) { - - NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "1", showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { (account, files, responseData, errorCode, errorDescription) in - - if errorCode == 0 { - - NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: true, account: account) { (metadataFolder, metadatasFolder, metadatas) in - + + // MARK: - WebDav Read file, folder + + @objc func readFolder(serverUrl: String, account: String, completion: @escaping (_ account: String, _ metadataFolder: tableMetadata?, _ metadatas: [tableMetadata]?, _ metadatasUpdate: [tableMetadata]?, _ metadatasLocalUpdate: [tableMetadata]?, _ metadatasDelete: [tableMetadata]?, _ errorCode: Int, _ errorDescription: String) -> Void) { + + NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "1", showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { account, files, _, errorCode, errorDescription in + + if errorCode == 0 { + + NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: true, account: account) { metadataFolder, metadatasFolder, metadatas in + // Add metadata folder NCManageDatabase.shared.addMetadata(tableMetadata.init(value: metadataFolder)) - + // Update directory NCManageDatabase.shared.addDirectory(encrypted: metadataFolder.e2eEncrypted, favorite: metadataFolder.favorite, ocId: metadataFolder.ocId, fileId: metadataFolder.fileId, etag: metadataFolder.etag, permissions: metadataFolder.permissions, serverUrl: serverUrl, account: metadataFolder.account) NCManageDatabase.shared.setDirectory(richWorkspace: metadataFolder.richWorkspace, serverUrl: serverUrl, account: metadataFolder.account) - + // Update sub directories NO Update richWorkspace for metadata in metadatasFolder { let serverUrl = metadata.serverUrl + "/" + metadata.fileName NCManageDatabase.shared.addDirectory(encrypted: metadata.e2eEncrypted, favorite: metadata.favorite, ocId: metadata.ocId, fileId: metadata.fileId, etag: nil, permissions: metadata.permissions, serverUrl: serverUrl, account: account) } - + let metadatasResult = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND status == %d", account, serverUrl, NCGlobal.shared.metadataStatusNormal)) let metadatasChanged = NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult, addCompareEtagLocal: true) - + completion(account, metadataFolder, metadatas, metadatasChanged.metadatasUpdate, metadatasChanged.metadatasLocalUpdate, metadatasChanged.metadatasDelete, errorCode, "") } - + } else { - + completion(account, nil, nil, nil, nil, nil, errorCode, errorDescription) } } } - - @objc func readFile(serverUrlFileName: String, account: String, completion: @escaping (_ account: String, _ metadata: tableMetadata?, _ errorCode: Int, _ errorDescription: String)->()) { - - NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { (account, files, responseData, errorCode, errorDescription) in + + @objc func readFile(serverUrlFileName: String, account: String, queue: DispatchQueue = NCCommunicationCommon.shared.backgroundQueue, completion: @escaping (_ account: String, _ metadata: tableMetadata?, _ errorCode: Int, _ errorDescription: String) -> Void) { + + NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: queue) { account, files, _, errorCode, errorDescription in if errorCode == 0 && files.count == 1 { - + let file = files[0] - let isEncrypted = CCUtility.isFolderEncrypted(file.serverUrl, e2eEncrypted:file.e2eEncrypted, account: account, urlBase: file.urlBase) + let isEncrypted = CCUtility.isFolderEncrypted(file.serverUrl, e2eEncrypted: file.e2eEncrypted, account: account, urlBase: file.urlBase) let metadata = NCManageDatabase.shared.convertNCFileToMetadata(file, isEncrypted: isEncrypted, account: account) - + completion(account, metadata, errorCode, errorDescription) - + } else { - + completion(account, nil, errorCode, errorDescription) } } } - - //MARK: - WebDav Search - - @objc func searchFiles(urlBase: String, user: String, literal: String, completion: @escaping (_ account: String, _ metadatas: [tableMetadata]?, _ errorCode: Int, _ errorDescription: String)->()) { - - NCCommunication.shared.searchLiteral(serverUrl: urlBase, depth: "infinity", literal: literal, showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { (account, files, errorCode, errorDescription) in - - if errorCode == 0 { - - NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: false, account: account) { (metadataFolder, metadatasFolder, metadatas) in - + + // MARK: - WebDav Search + + @objc func searchFiles(urlBase: String, user: String, literal: String, completion: @escaping (_ account: String, _ metadatas: [tableMetadata]?, _ errorCode: Int, _ errorDescription: String) -> Void) { + + NCCommunication.shared.searchLiteral(serverUrl: urlBase, depth: "infinity", literal: literal, showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { account, files, errorCode, errorDescription in + + if errorCode == 0 { + + NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: false, account: account) { _, metadatasFolder, metadatas in + // Update sub directories for metadata in metadatasFolder { let serverUrl = metadata.serverUrl + "/" + metadata.fileName NCManageDatabase.shared.addDirectory(encrypted: metadata.e2eEncrypted, favorite: metadata.favorite, ocId: metadata.ocId, fileId: metadata.fileId, etag: nil, permissions: metadata.permissions, serverUrl: serverUrl, account: account) } - + NCManageDatabase.shared.addMetadatas(metadatas) - - let metadatas = Array(metadatas.map { tableMetadata.init(value:$0) }) - + + let metadatas = Array(metadatas.map { tableMetadata.init(value: $0) }) + completion(account, metadatas, errorCode, errorDescription) } - + } else { - + completion(account, nil, errorCode, errorDescription) } } } - - //MARK: - WebDav Create Folder - @objc func createFolder(fileName: String, serverUrl: String, account: String, urlBase: String, overwrite: Bool = false, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - + // MARK: - WebDav Create Folder + + @objc func createFolder(fileName: String, serverUrl: String, account: String, urlBase: String, overwrite: Bool = false, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + let isDirectoryEncrypted = CCUtility.isFolderEncrypted(serverUrl, e2eEncrypted: false, account: account, urlBase: urlBase) - + if isDirectoryEncrypted { #if !EXTENSION NCNetworkingE2EE.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: account, urlBase: urlBase, completion: completion) @@ -914,59 +930,59 @@ import Queuer createFolderPlain(fileName: fileName, serverUrl: serverUrl, account: account, urlBase: urlBase, overwrite: overwrite, completion: completion) } } - - private func createFolderPlain(fileName: String, serverUrl: String, account: String, urlBase: String, overwrite: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - + + private func createFolderPlain(fileName: String, serverUrl: String, account: String, urlBase: String, overwrite: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + var fileNameFolder = CCUtility.removeForbiddenCharactersServer(fileName)! - - if (!overwrite) { + + if !overwrite { fileNameFolder = NCUtilityFileSystem.shared.createFileName(fileNameFolder, serverUrl: serverUrl, account: account) } if fileNameFolder.count == 0 { return completion(0, "") } let fileNameFolderUrl = serverUrl + "/" + fileNameFolder - - NCCommunication.shared.createFolder(fileNameFolderUrl) { (account, ocId, date, errorCode, errorDescription) in - + + NCCommunication.shared.createFolder(fileNameFolderUrl) { account, ocId, _, errorCode, errorDescription in + if errorCode == 0 { - - self.readFile(serverUrlFileName: fileNameFolderUrl, account: account) { (account, metadataFolder, errorCode, errorDescription) in - + + self.readFile(serverUrlFileName: fileNameFolderUrl, account: account) { account, metadataFolder, errorCode, errorDescription in + if errorCode == 0 { - + if let metadata = metadataFolder { - + NCManageDatabase.shared.addMetadata(metadata) NCManageDatabase.shared.addDirectory(encrypted: metadata.e2eEncrypted, favorite: metadata.favorite, ocId: metadata.ocId, fileId: metadata.fileId, etag: nil, permissions: metadata.permissions, serverUrl: fileNameFolderUrl, account: account) } - + if let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadataFolder?.ocId) { NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterCreateFolder, userInfo: ["ocId": metadata.ocId]) } } - + completion(errorCode, errorDescription) } - + } else if errorCode == 405 && overwrite { - + completion(0, "") - + } else { - + completion(errorCode, errorDescription) } } } - + func createFolder(assets: [PHAsset], selector: String, useSubFolder: Bool, account: String, urlBase: String) -> Bool { - + let serverUrl = NCManageDatabase.shared.getAccountAutoUploadDirectory(urlBase: urlBase, account: account) let fileName = NCManageDatabase.shared.getAccountAutoUploadFileName() let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: urlBase, account: account) var result = createFolderWithSemaphore(fileName: fileName, serverUrl: serverUrl, account: account, urlBase: urlBase) - + if useSubFolder && result { for dateSubFolder in CCUtility.createNameSubFolder(assets) { let fileName = (dateSubFolder as! NSString).lastPathComponent @@ -975,62 +991,62 @@ import Queuer if !result { break } } } - + return result } - + private func createFolderWithSemaphore(fileName: String, serverUrl: String, account: String, urlBase: String) -> Bool { - + var result: Bool = false let semaphore = Semaphore() - - NCNetworking.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: account, urlBase: urlBase, overwrite: true) { (errorCode, errorDescription) in + + NCNetworking.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: account, urlBase: urlBase, overwrite: true) { errorCode, _ in if errorCode == 0 { result = true } semaphore.continue() } - + if semaphore.wait() == .success { result = true } return result } - - //MARK: - WebDav Delete - @objc func deleteMetadata(_ metadata: tableMetadata, onlyLocalCache: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - - if (onlyLocalCache) { - + // MARK: - WebDav Delete + + @objc func deleteMetadata(_ metadata: tableMetadata, onlyLocalCache: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + + if onlyLocalCache { + var metadatas = [metadata] - + if metadata.directory { let serverUrl = metadata.serverUrl + "/" + metadata.fileName metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl BEGINSWITH %@ AND directory == false", metadata.account, serverUrl)) } - + for metadata in metadatas { - + NCManageDatabase.shared.deleteVideo(metadata: metadata) NCManageDatabase.shared.deleteLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) NCUtilityFileSystem.shared.deleteFile(filePath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)) - + if let metadataLivePhoto = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) { NCManageDatabase.shared.deleteLocalFile(predicate: NSPredicate(format: "ocId == %@", metadataLivePhoto.ocId)) NCUtilityFileSystem.shared.deleteFile(filePath: CCUtility.getDirectoryProviderStorageOcId(metadataLivePhoto.ocId)) } - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": metadata.ocId, "fileNameView": metadata.fileNameView, "classFile": metadata.classFile, "onlyLocalCache": true]) } return completion(0, "") } - + let isDirectoryEncrypted = CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase) let metadataLive = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) - + if isDirectoryEncrypted { #if !EXTENSION if metadataLive == nil { NCNetworkingE2EE.shared.deleteMetadata(metadata, completion: completion) } else { - NCNetworkingE2EE.shared.deleteMetadata(metadataLive!) { (errorCode, errorDescription) in + NCNetworkingE2EE.shared.deleteMetadata(metadataLive!) { errorCode, errorDescription in if errorCode == 0 { NCNetworkingE2EE.shared.deleteMetadata(metadata, completion: completion) } else { @@ -1043,7 +1059,7 @@ import Queuer if metadataLive == nil { self.deleteMetadataPlain(metadata, addCustomHeaders: nil, completion: completion) } else { - self.deleteMetadataPlain(metadataLive!, addCustomHeaders: nil) { (errorCode, errorDescription) in + self.deleteMetadataPlain(metadataLive!, addCustomHeaders: nil) { errorCode, errorDescription in if errorCode == 0 { self.deleteMetadataPlain(metadata, addCustomHeaders: nil, completion: completion) } else { @@ -1053,24 +1069,24 @@ import Queuer } } } - - func deleteMetadataPlain(_ metadata: tableMetadata, addCustomHeaders: [String: String]?, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - + + func deleteMetadataPlain(_ metadata: tableMetadata, addCustomHeaders: [String: String]?, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + // verify permission let permission = NCUtility.shared.permissionsContainsString(metadata.permissions, permissions: NCGlobal.shared.permissionCanDelete) if metadata.permissions != "" && permission == false { return completion(NCGlobal.shared.errorInternalError, "_no_permission_delete_file_") } - + let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName - NCCommunication.shared.deleteFileOrFolder(serverUrlFileName, customUserAgent: nil, addCustomHeaders: addCustomHeaders) { (account, errorCode, errorDescription) in - + NCCommunication.shared.deleteFileOrFolder(serverUrlFileName, customUserAgent: nil, addCustomHeaders: addCustomHeaders) { account, errorCode, errorDescription in + if errorCode == 0 || errorCode == NCGlobal.shared.errorResourceNotFound { - + do { try FileManager.default.removeItem(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)) } catch { } - + NCManageDatabase.shared.deleteVideo(metadata: metadata) NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) NCManageDatabase.shared.deleteLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) @@ -1078,20 +1094,20 @@ import Queuer if metadata.directory { NCManageDatabase.shared.deleteDirectoryAndSubDirectory(serverUrl: CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName), account: metadata.account) } - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": metadata.ocId, "fileNameView": metadata.fileNameView, "classFile": metadata.classFile, "onlyLocalCache": true]) } - + completion(errorCode, errorDescription) } } - - //MARK: - WebDav Favorite - @objc func favoriteMetadata(_ metadata: tableMetadata, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - + // MARK: - WebDav Favorite + + @objc func favoriteMetadata(_ metadata: tableMetadata, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + if let metadataLive = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) { - favoriteMetadataPlain(metadataLive) { (errorCode, errorDescription) in + favoriteMetadataPlain(metadataLive) { errorCode, errorDescription in if errorCode == 0 { self.favoriteMetadataPlain(metadata, completion: completion) } else { @@ -1102,39 +1118,39 @@ import Queuer favoriteMetadataPlain(metadata, completion: completion) } } - - private func favoriteMetadataPlain(_ metadata: tableMetadata, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - + + private func favoriteMetadataPlain(_ metadata: tableMetadata, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + let fileName = CCUtility.returnFileNamePath(fromFileName: metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, account: metadata.account)! let favorite = !metadata.favorite let ocId = metadata.ocId - - NCCommunication.shared.setFavorite(fileName: fileName, favorite: favorite) { (account, errorCode, errorDescription) in - + + NCCommunication.shared.setFavorite(fileName: fileName, favorite: favorite) { account, errorCode, errorDescription in + if errorCode == 0 && metadata.account == account { - + NCManageDatabase.shared.setMetadataFavorite(ocId: metadata.ocId, favorite: favorite) - + #if !EXTENSION if favorite { NCOperationQueue.shared.synchronizationMetadata(metadata, selector: NCGlobal.shared.selectorReadFile) } #endif - + if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterFavoriteFile, userInfo: ["ocId": metadata.ocId]) } } - + completion(errorCode, errorDescription) } } - - @objc func listingFavoritescompletion(selector: String, completion: @escaping (_ account: String, _ metadatas: [tableMetadata]?, _ errorCode: Int, _ errorDescription: String)->()) { - NCCommunication.shared.listingFavorites(showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { (account, files, errorCode, errorDescription) in - + + @objc func listingFavoritescompletion(selector: String, completion: @escaping (_ account: String, _ metadatas: [tableMetadata]?, _ errorCode: Int, _ errorDescription: String) -> Void) { + NCCommunication.shared.listingFavorites(showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { account, files, errorCode, errorDescription in + if errorCode == 0 { - NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: false, account: account) { (_, _, metadatas) in + NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: false, account: account) { _, _, metadatas in NCManageDatabase.shared.updateMetadatasFavorite(account: account, metadatas: metadatas) if selector != NCGlobal.shared.selectorListingFavorite { #if !EXTENSION @@ -1150,11 +1166,11 @@ import Queuer } } } - - //MARK: - WebDav Rename - @objc func renameMetadata(_ metadata: tableMetadata, fileNameNew: String, viewController: UIViewController?, completion: @escaping (_ errorCode: Int, _ errorDescription: String?)->()) { - + // MARK: - WebDav Rename + + @objc func renameMetadata(_ metadata: tableMetadata, fileNameNew: String, viewController: UIViewController?, completion: @escaping (_ errorCode: Int, _ errorDescription: String?) -> Void) { + let isDirectoryEncrypted = CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase) let metadataLive = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) let fileNameNewLive = (fileNameNew as NSString).deletingPathExtension + ".mov" @@ -1164,7 +1180,7 @@ import Queuer if metadataLive == nil { NCNetworkingE2EE.shared.renameMetadata(metadata, fileNameNew: fileNameNew, completion: completion) } else { - NCNetworkingE2EE.shared.renameMetadata(metadataLive!, fileNameNew: fileNameNewLive) { (errorCode, errorDescription) in + NCNetworkingE2EE.shared.renameMetadata(metadataLive!, fileNameNew: fileNameNewLive) { errorCode, errorDescription in if errorCode == 0 { NCNetworkingE2EE.shared.renameMetadata(metadata, fileNameNew: fileNameNew, completion: completion) } else { @@ -1177,7 +1193,7 @@ import Queuer if metadataLive == nil { renameMetadataPlain(metadata, fileNameNew: fileNameNew, completion: completion) } else { - renameMetadataPlain(metadataLive!, fileNameNew: fileNameNewLive) { (errorCode, errorDescription) in + renameMetadataPlain(metadataLive!, fileNameNew: fileNameNewLive) { errorCode, errorDescription in if errorCode == 0 { self.renameMetadataPlain(metadata, fileNameNew: fileNameNew, completion: completion) } else { @@ -1187,9 +1203,9 @@ import Queuer } } } - - private func renameMetadataPlain(_ metadata: tableMetadata, fileNameNew: String, completion: @escaping (_ errorCode: Int, _ errorDescription: String?)->()) { - + + private func renameMetadataPlain(_ metadata: tableMetadata, fileNameNew: String, completion: @escaping (_ errorCode: Int, _ errorDescription: String?) -> Void) { + let permission = NCUtility.shared.permissionsContainsString(metadata.permissions, permissions: NCGlobal.shared.permissionCanRename) if !(metadata.permissions == "") && !permission { return completion(NCGlobal.shared.errorInternalError, "_no_permission_modify_file_") @@ -1200,40 +1216,40 @@ import Queuer if fileNameNew.count == 0 || fileNameNew == metadata.fileNameView { return completion(0, "") } - + let fileNamePath = metadata.serverUrl + "/" + metadata.fileName let fileNameToPath = metadata.serverUrl + "/" + fileNameNew let ocId = metadata.ocId - - NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: fileNamePath, serverUrlFileNameDestination: fileNameToPath, overwrite: false) { (account, errorCode, errorDescription) in - + + NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: fileNamePath, serverUrlFileNameDestination: fileNameToPath, overwrite: false) { account, errorCode, errorDescription in + if errorCode == 0 { - + NCManageDatabase.shared.renameMetadata(fileNameTo: fileNameNew, ocId: ocId) - + if metadata.directory { - + let serverUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName)! let serverUrlTo = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: fileNameNew)! if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)) { - + NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, serverUrlTo: serverUrlTo, etag: "", ocId: nil, fileId: nil, encrypted: directory.e2eEncrypted, richWorkspace: nil, account: metadata.account) } - + } else { - + let ext = (metadata.fileName as NSString).pathExtension let extNew = (fileNameNew as NSString).pathExtension - + if ext != extNew { - + if let path = CCUtility.getDirectoryProviderStorageOcId(ocId) { NCUtilityFileSystem.shared.deleteFile(filePath: path) } NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced, userInfo: ["serverUrl": metadata.serverUrl]) } else { - + NCManageDatabase.shared.setLocalFile(ocId: ocId, fileName: fileNameNew, etag: nil) // Move file system let atPath = CCUtility.getDirectoryProviderStorageOcId(ocId) + "/" + metadata.fileName @@ -1243,22 +1259,22 @@ import Queuer } catch { } } } - + if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterRenameFile, userInfo: ["ocId": metadata.ocId]) } } - + completion(errorCode, errorDescription) } } - - //MARK: - WebDav Move - - @objc func moveMetadata(_ metadata: tableMetadata, serverUrlTo: String, overwrite: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String?)->()) { - + + // MARK: - WebDav Move + + @objc func moveMetadata(_ metadata: tableMetadata, serverUrlTo: String, overwrite: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String?) -> Void) { + if let metadataLive = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) { - moveMetadataPlain(metadataLive, serverUrlTo: serverUrlTo, overwrite: overwrite) { (errorCode, errorDescription) in + moveMetadataPlain(metadataLive, serverUrlTo: serverUrlTo, overwrite: overwrite) { errorCode, errorDescription in if errorCode == 0 { self.moveMetadataPlain(metadata, serverUrlTo: serverUrlTo, overwrite: overwrite, completion: completion) } else { @@ -1270,40 +1286,40 @@ import Queuer } } - private func moveMetadataPlain(_ metadata: tableMetadata, serverUrlTo: String, overwrite: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String?)->()) { - + private func moveMetadataPlain(_ metadata: tableMetadata, serverUrlTo: String, overwrite: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String?) -> Void) { + let permission = NCUtility.shared.permissionsContainsString(metadata.permissions, permissions: NCGlobal.shared.permissionCanRename) if !(metadata.permissions == "") && !permission { return completion(NCGlobal.shared.errorInternalError, "_no_permission_modify_file_") } - + let serverUrlFrom = metadata.serverUrl let serverUrlFileNameSource = metadata.serverUrl + "/" + metadata.fileName let serverUrlFileNameDestination = serverUrlTo + "/" + metadata.fileName - - NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileNameDestination, overwrite: overwrite) { (account, errorCode, errorDescription) in - + + NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileNameDestination, overwrite: overwrite) { account, errorCode, errorDescription in + if errorCode == 0 { - + if metadata.directory { NCManageDatabase.shared.deleteDirectoryAndSubDirectory(serverUrl: CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName), account: account) } - + NCManageDatabase.shared.moveMetadata(ocId: metadata.ocId, serverUrlTo: serverUrlTo) NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterMoveFile, userInfo: ["ocId": metadata.ocId, "serverUrlFrom": serverUrlFrom]) } - + completion(errorCode, errorDescription) } } - - //MARK: - WebDav Copy - - @objc func copyMetadata(_ metadata: tableMetadata, serverUrlTo: String, overwrite: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String?)->()) { - + + // MARK: - WebDav Copy + + @objc func copyMetadata(_ metadata: tableMetadata, serverUrlTo: String, overwrite: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String?) -> Void) { + if let metadataLive = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) { - copyMetadataPlain(metadataLive, serverUrlTo: serverUrlTo, overwrite: overwrite) { (errorCode, errorDescription) in + copyMetadataPlain(metadataLive, serverUrlTo: serverUrlTo, overwrite: overwrite) { errorCode, errorDescription in if errorCode == 0 { self.copyMetadataPlain(metadata, serverUrlTo: serverUrlTo, overwrite: overwrite, completion: completion) } else { @@ -1315,39 +1331,39 @@ import Queuer } } - private func copyMetadataPlain(_ metadata: tableMetadata, serverUrlTo: String, overwrite: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String?)->()) { - + private func copyMetadataPlain(_ metadata: tableMetadata, serverUrlTo: String, overwrite: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String?) -> Void) { + let permission = NCUtility.shared.permissionsContainsString(metadata.permissions, permissions: NCGlobal.shared.permissionCanRename) if !(metadata.permissions == "") && !permission { return completion(NCGlobal.shared.errorInternalError, "_no_permission_modify_file_") } - + let serverUrlFileNameSource = metadata.serverUrl + "/" + metadata.fileName let serverUrlFileNameDestination = serverUrlTo + "/" + metadata.fileName - - NCCommunication.shared.copyFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileNameDestination, overwrite: overwrite) { (account, errorCode, errorDescription) in - + + NCCommunication.shared.copyFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileNameDestination, overwrite: overwrite) { _, errorCode, errorDescription in + if errorCode == 0 { - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterCopyFile, userInfo: ["ocId": metadata.ocId, "serverUrlTo": serverUrlTo]) } - + completion(errorCode, errorDescription) } } - - //MARK: - Direct Download - func getVideoUrl(metadata: tableMetadata, completition: @escaping (_ url: URL?)->()) { - + // MARK: - Direct Download + + func getVideoUrl(metadata: tableMetadata, completition: @escaping (_ url: URL?) -> Void) { + if CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { - + completition(URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView))) - + } else { - - NCCommunication.shared.getDirectDownload(fileId: metadata.fileId) { account, url, errorCode, errorDescription in - + + NCCommunication.shared.getDirectDownload(fileId: metadata.fileId) { _, url, errorCode, _ in + if errorCode == 0 && url != nil { if let url = URL(string: url!) { completition(url) @@ -1360,9 +1376,9 @@ import Queuer } } } - - //MARK: - TEST API - + + // MARK: - TEST API + /* @objc public func getDirectDownload(urlBase: String, username: String, password: String, fileId: String, customUserAgent: String? = nil, completionHandler: @escaping (_ token: String?, _ errorCode: Int, _ errorDescription: String) -> Void) { diff --git a/iOSClient/Networking/NCNetworkingCheckRemoteUser.swift b/iOSClient/Networking/NCNetworkingCheckRemoteUser.swift index 5bc9e0352..e68d2a72a 100644 --- a/iOSClient/Networking/NCNetworkingCheckRemoteUser.swift +++ b/iOSClient/Networking/NCNetworkingCheckRemoteUser.swift @@ -28,69 +28,69 @@ import NCCommunication let instance = NCNetworkingCheckRemoteUser() return instance }() - + let appDelegate = UIApplication.shared.delegate as! AppDelegate var checkRemoteUserInProgress = false @objc func checkRemoteUser(account: String, errorCode: Int, errorDescription: String) { - + if self.checkRemoteUserInProgress { return } else { self.checkRemoteUserInProgress = true } - + let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesVersionMajor) guard let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) else { self.checkRemoteUserInProgress = false return } - + if serverVersionMajor >= NCGlobal.shared.nextcloudVersion17 { - + if errorCode == 401 { - + let token = CCUtility.getPassword(account)! if token == "" { self.checkRemoteUserInProgress = false return } - - NCCommunication.shared.getRemoteWipeStatus(serverUrl: tableAccount.urlBase, token: token) { (account, wipe, errorCode, errorDescriptiuon) in - + + NCCommunication.shared.getRemoteWipeStatus(serverUrl: tableAccount.urlBase, token: token) { account, wipe, errorCode, _ in + if wipe { - + self.appDelegate.deleteAccount(account, wipe: true) NCContentPresenter.shared.messageNotification(tableAccount.user, description: "_wipe_account_", delay: NCGlobal.shared.dismissAfterSecondLong, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError, priority: .max) - NCCommunication.shared.setRemoteWipeCompletition(serverUrl: tableAccount.urlBase, token: token) { (account, errorCode, errorDescription) in print("wipe") } - + NCCommunication.shared.setRemoteWipeCompletition(serverUrl: tableAccount.urlBase, token: token) { _, _, _ in print("wipe") } + } else { - + if UIApplication.shared.applicationState == .active && NCCommunication.shared.isNetworkReachable() { let description = String.localizedStringWithFormat(NSLocalizedString("_error_check_remote_user_", comment: ""), tableAccount.user, tableAccount.urlBase) NCContentPresenter.shared.messageNotification("_error_", description: description, delay: NCGlobal.shared.dismissAfterSecondLong, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) CCUtility.setPassword(account, password: nil) } } - + self.checkRemoteUserInProgress = false } - + } else { - + NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecondLong, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + self.checkRemoteUserInProgress = false } - + } else if CCUtility.getPassword(account) != "" { - + if UIApplication.shared.applicationState == .active && NCCommunication.shared.isNetworkReachable() { let description = String.localizedStringWithFormat(NSLocalizedString("_error_check_remote_user_", comment: ""), tableAccount.user, tableAccount.urlBase) NCContentPresenter.shared.messageNotification("_error_", description: description, delay: NCGlobal.shared.dismissAfterSecondLong, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) CCUtility.setPassword(account, password: nil) } - + self.checkRemoteUserInProgress = false } } diff --git a/iOSClient/Networking/NCNetworkingChunkedUpload.swift b/iOSClient/Networking/NCNetworkingChunkedUpload.swift index d045c9f1b..f9a134c7a 100644 --- a/iOSClient/Networking/NCNetworkingChunkedUpload.swift +++ b/iOSClient/Networking/NCNetworkingChunkedUpload.swift @@ -26,167 +26,178 @@ import NCCommunication import Queuer extension NCNetworking { - - internal func uploadChunkedFile(metadata: tableMetadata, start: @escaping () -> Void, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - + + internal func uploadChunkedFile(metadata: tableMetadata, start: @escaping () -> Void, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + let directoryProviderStorageOcId = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)! let chunkFolder = NCManageDatabase.shared.getChunkFolder(account: metadata.account, ocId: metadata.ocId) let chunkFolderPath = metadata.urlBase + "/" + NCUtilityFileSystem.shared.getWebDAV(account: metadata.account) + "/uploads/" + metadata.userId + "/" + chunkFolder let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! let chunkSize = CCUtility.getChunkSize() - + var uploadErrorCode: Int = 0 var uploadErrorDescription: String = "" var filesNames = NCManageDatabase.shared.getChunks(account: metadata.account, ocId: metadata.ocId) if filesNames.count == 0 { - + filesNames = NCCommunicationCommon.shared.chunkedFile(inputDirectory: directoryProviderStorageOcId, outputDirectory: directoryProviderStorageOcId, fileName: metadata.fileName, chunkSizeMB: chunkSize) - + if filesNames.count > 0 { NCManageDatabase.shared.addChunks(account: metadata.account, ocId: metadata.ocId, chunkFolder: chunkFolder, fileNames: filesNames) } else { - NCContentPresenter.shared.messageNotification("_error_", description: "_err_file_not_found_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode:NCGlobal.shared.errorReadFile) + NCContentPresenter.shared.messageNotification("_error_", description: "_err_file_not_found_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorReadFile) NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) return completion(uploadErrorCode, uploadErrorDescription) } - + } else { - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl":metadata.serverUrl]) + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl": metadata.serverUrl]) } NCContentPresenter.shared.noteTop(text: NSLocalizedString("_upload_chunk_", comment: ""), image: nil, type: NCContentPresenter.messageType.info, delay: NCGlobal.shared.dismissAfterSecond, priority: .max) - - createChunkedFolder(chunkFolderPath: chunkFolderPath, account: metadata.account) { (errorCode, errorDescription) in - + + createChunkedFolder(chunkFolderPath: chunkFolderPath, account: metadata.account) { errorCode, errorDescription in + start() if errorCode == 0 { - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId": metadata.ocId]) - + for fileName in filesNames { - + let serverUrlFileName = chunkFolderPath + "/" + fileName let fileNameChunkLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: fileName)! - + var size: Int64? if let tableChunk = NCManageDatabase.shared.getChunk(account: metadata.account, fileName: fileName) { size = tableChunk.size - NCUtilityFileSystem.shared.getFileSize(filePath: fileNameChunkLocalPath) } - + let semaphore = Semaphore() - - NCCommunication.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameChunkLocalPath, requestHandler: { (request) in - + + NCCommunication.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameChunkLocalPath, requestHandler: { request in + self.uploadRequest[fileNameLocalPath] = request - - }, taskHandler: { (task) in - + + }, taskHandler: { task in + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, sessionError: "", sessionTaskIdentifier: task.taskIdentifier, status: NCGlobal.shared.metadataStatusUploading) - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId":metadata.ocId]) - + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId": metadata.ocId]) + NCCommunicationCommon.shared.writeLog("Upload chunk: " + fileName) - - }, progressHandler: { (progress) in - + + }, progressHandler: { progress in + if let size = size { - + let totalBytesExpected = size + progress.completedUnitCount let totalBytes = metadata.size let fractionCompleted = Float(totalBytesExpected) / Float(totalBytes) - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterProgressTask, object: nil, userInfo: ["account":metadata.account, "ocId":metadata.ocId, "fileName":metadata.fileName, "serverUrl":metadata.serverUrl, "status":NSNumber(value: NCGlobal.shared.metadataStatusInUpload), "progress":NSNumber(value: fractionCompleted), "totalBytes":NSNumber(value: totalBytes), "totalBytesExpected":NSNumber(value: totalBytesExpected)]) + + NotificationCenter.default.postOnMainThread( + name: NCGlobal.shared.notificationCenterProgressTask, + object: nil, + userInfo: [ + "account": metadata.account, + "ocId": metadata.ocId, + "fileName": metadata.fileName, + "serverUrl": metadata.serverUrl, + "status": NSNumber(value: NCGlobal.shared.metadataStatusInUpload), + "progress": NSNumber(value: fractionCompleted), + "totalBytes": NSNumber(value: totalBytes), + "totalBytesExpected": NSNumber(value: totalBytesExpected)]) } - - }) { (_, _, _, _, _, _, _, errorCode, errorDescription) in - + + }) { _, _, _, _, _, _, _, errorCode, errorDescription in + self.uploadRequest[fileNameLocalPath] = nil uploadErrorCode = errorCode uploadErrorDescription = errorDescription semaphore.continue() } - + semaphore.wait() - + if uploadErrorCode == 0 { NCManageDatabase.shared.deleteChunk(account: metadata.account, ocId: metadata.ocId, fileName: fileName) } else { break } } - + if uploadErrorCode == 0 { - + // Assembling the chunks let serverUrlFileNameSource = chunkFolderPath + "/.file" let pathServerUrl = CCUtility.returnPathfromServerUrl(metadata.serverUrl, urlBase: metadata.urlBase, account: metadata.account)! let serverUrlFileNameDestination = metadata.urlBase + "/" + NCUtilityFileSystem.shared.getWebDAV(account: metadata.account) + "/files/" + metadata.userId + pathServerUrl + "/" + metadata.fileName - - var addCustomHeaders: [String:String] = [:] + + var addCustomHeaders: [String: String] = [:] let creationDate = "\(metadata.creationDate.timeIntervalSince1970)" let modificationDate = "\(metadata.date.timeIntervalSince1970)" - + addCustomHeaders["X-OC-CTime"] = creationDate addCustomHeaders["X-OC-MTime"] = modificationDate - NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileNameDestination, overwrite: true, addCustomHeaders: addCustomHeaders) { (_, errorCode, errorDescription) in - + NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileNameDestination, overwrite: true, addCustomHeaders: addCustomHeaders) { _, errorCode, errorDescription in + NCCommunicationCommon.shared.writeLog("Assembling chunk with error code: \(errorCode)") - + if errorCode == 0 { - + let serverUrl = metadata.serverUrl NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) NCManageDatabase.shared.deleteChunks(account: metadata.account, ocId: metadata.ocId) NCUtilityFileSystem.shared.deleteFile(filePath: directoryProviderStorageOcId) - self.readFile(serverUrlFileName: serverUrlFileNameDestination, account: metadata.account) { (_, metadata, _, _) in - + self.readFile(serverUrlFileName: serverUrlFileNameDestination, account: metadata.account) { _, metadata, _, _ in + if errorCode == 0, let metadata = metadata { - + NCManageDatabase.shared.addMetadata(metadata) - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl":serverUrl]) - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl": serverUrl]) + } else { - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced, userInfo: ["serverUrl": serverUrl]) } - + completion(errorCode, errorDescription) } - + } else { - + self.uploadChunkFileError(metadata: metadata, chunkFolderPath: chunkFolderPath, directoryProviderStorageOcId: directoryProviderStorageOcId, errorCode: errorCode, errorDescription: errorDescription) completion(errorCode, errorDescription) } } - + } else { - + self.uploadChunkFileError(metadata: metadata, chunkFolderPath: chunkFolderPath, directoryProviderStorageOcId: directoryProviderStorageOcId, errorCode: uploadErrorCode, errorDescription: uploadErrorDescription) completion(errorCode, errorDescription) } - + } else { - + self.uploadChunkFileError(metadata: metadata, chunkFolderPath: chunkFolderPath, directoryProviderStorageOcId: directoryProviderStorageOcId, errorCode: errorCode, errorDescription: errorDescription) completion(errorCode, errorDescription) } } } - - private func createChunkedFolder(chunkFolderPath: String, account: String, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - - NCCommunication.shared.readFileOrFolder(serverUrlFileName: chunkFolderPath, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { (_, _, _, errorCode, errorDescription) in - + + private func createChunkedFolder(chunkFolderPath: String, account: String, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + + NCCommunication.shared.readFileOrFolder(serverUrlFileName: chunkFolderPath, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { _, _, _, errorCode, errorDescription in + if errorCode == 0 { completion(0, "") } else if errorCode == NCGlobal.shared.errorResourceNotFound { - NCCommunication.shared.createFolder(chunkFolderPath, queue: NCCommunicationCommon.shared.backgroundQueue) { (_, _, _, errorCode, errorDescription) in + NCCommunication.shared.createFolder(chunkFolderPath, queue: NCCommunicationCommon.shared.backgroundQueue) { _, _, _, errorCode, errorDescription in completion(errorCode, errorDescription) } } else { @@ -196,26 +207,26 @@ extension NCNetworking { } private func uploadChunkFileError(metadata: tableMetadata, chunkFolderPath: String, directoryProviderStorageOcId: String, errorCode: Int, errorDescription: String) { - + var errorDescription = errorDescription - + NCCommunicationCommon.shared.writeLog("Upload chunk error code: \(errorCode)") - + if errorCode == NSURLErrorCancelled || errorCode == NCGlobal.shared.errorRequestExplicityCancelled { - + // Delete chunk folder - NCCommunication.shared.deleteFileOrFolder(chunkFolderPath) { (_, _, _) in } - + NCCommunication.shared.deleteFileOrFolder(chunkFolderPath) { _, _, _ in } + NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) NCManageDatabase.shared.deleteChunks(account: metadata.account, ocId: metadata.ocId) NCUtilityFileSystem.shared.deleteFile(filePath: directoryProviderStorageOcId) - - NCCommunication.shared.deleteFileOrFolder(chunkFolderPath) { (_, _, _) in } - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadCancelFile, userInfo: ["ocId":metadata.ocId, "serverUrl":metadata.serverUrl, "account":metadata.account]) - + + NCCommunication.shared.deleteFileOrFolder(chunkFolderPath) { _, _, _ in } + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadCancelFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account]) + } else { - + // NO report for the connection lost if errorCode == NCGlobal.shared.errorConnectionLost { errorDescription = "" @@ -223,10 +234,10 @@ extension NCNetworking { let description = errorDescription + " code: \(errorCode)" NCContentPresenter.shared.messageNotification("_error_", description: description, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError) } - + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: nil, sessionError: errorDescription, sessionTaskIdentifier: NCGlobal.shared.metadataStatusNormal, status: NCGlobal.shared.metadataStatusUploadError) } - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId":metadata.ocId, "ocIdTemp":metadata.ocId, "errorCode":errorCode, "errorDescription":""]) + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "ocIdTemp": metadata.ocId, "errorCode": errorCode, "errorDescription": ""]) } } diff --git a/iOSClient/Networking/NCNetworkingE2EE.swift b/iOSClient/Networking/NCNetworkingE2EE.swift index 767ad9a39..ae1789216 100644 --- a/iOSClient/Networking/NCNetworkingE2EE.swift +++ b/iOSClient/Networking/NCNetworkingE2EE.swift @@ -30,43 +30,43 @@ import Alamofire let instance = NCNetworkingE2EE() return instance }() - - //MARK: - WebDav Create Folder - - func createFolder(fileName: String, serverUrl: String, account: String, urlBase: String, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - + + // MARK: - WebDav Create Folder + + func createFolder(fileName: String, serverUrl: String, account: String, urlBase: String, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + var fileNameFolder = CCUtility.removeForbiddenCharactersServer(fileName)! var fileNameFolderUrl = "" var fileNameIdentifier = "" var key: NSString? var initializationVector: NSString? - + fileNameFolder = NCUtilityFileSystem.shared.createFileName(fileNameFolder, serverUrl: serverUrl, account: account) if fileNameFolder.count == 0 { return completion(0, "") } fileNameIdentifier = CCUtility.generateRandomIdentifier() fileNameFolderUrl = serverUrl + "/" + fileNameIdentifier - - self.lock(account: account, serverUrl: serverUrl) { (directory, e2eToken, errorCode, errorDescription) in + + self.lock(account: account, serverUrl: serverUrl) { directory, e2eToken, errorCode, errorDescription in if errorCode == 0 && e2eToken != nil && directory != nil { - - NCCommunication.shared.createFolder(fileNameFolderUrl, addCustomHeaders: ["e2e-token" : e2eToken!]) { (account, ocId, date, errorCode, errorDescription) in + + NCCommunication.shared.createFolder(fileNameFolderUrl, addCustomHeaders: ["e2e-token": e2eToken!]) { account, ocId, _, errorCode, errorDescription in if errorCode == 0 { guard let fileId = NCUtility.shared.ocIdToFileId(ocId: ocId) else { // unlock if let tableLock = NCManageDatabase.shared.getE2ETokenLock(account: account, serverUrl: serverUrl) { - NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { (_, _, _, _) in } + NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { _, _, _, _ in } } return completion(NCGlobal.shared.errorInternalError, "Error convert ocId") } - NCCommunication.shared.markE2EEFolder(fileId: fileId, delete: false) { (account, errorCode, errorDescription) in + NCCommunication.shared.markE2EEFolder(fileId: fileId, delete: false) { account, errorCode, errorDescription in if errorCode == 0 { - + let object = tableE2eEncryption() - + NCEndToEndEncryption.sharedManager()?.encryptkey(&key, initializationVector: &initializationVector) - + object.account = account object.authenticationTag = nil object.fileName = fileNameFolder @@ -74,7 +74,7 @@ import Alamofire object.fileNamePath = "" object.key = key! as String object.initializationVector = initializationVector! as String - + if let result = NCManageDatabase.shared.getE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl)) { object.metadataKey = result.metadataKey object.metadataKeyIndex = result.metadataKeyIndex @@ -85,33 +85,33 @@ import Alamofire object.mimeType = "httpd/unix-directory" object.serverUrl = serverUrl object.version = 1 - - let _ = NCManageDatabase.shared.addE2eEncryption(object) - - self.sendE2EMetadata(account: account, serverUrl: serverUrl, fileNameRename: nil, fileNameNewRename: nil, deleteE2eEncryption: nil, urlBase: urlBase) { (e2eToken, errorCode, errorDescription) in + + _ = NCManageDatabase.shared.addE2eEncryption(object) + + self.sendE2EMetadata(account: account, serverUrl: serverUrl, fileNameRename: nil, fileNameNewRename: nil, deleteE2eEncryption: nil, urlBase: urlBase) { e2eToken, errorCode, errorDescription in // unlock if let tableLock = NCManageDatabase.shared.getE2ETokenLock(account: account, serverUrl: serverUrl) { - NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { (_, _, _, _) in } + NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { _, _, _, _ in } } if errorCode == 0 { NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterCreateFolder, userInfo: nil) } completion(errorCode, errorDescription) } - + } else { // unlock if let tableLock = NCManageDatabase.shared.getE2ETokenLock(account: account, serverUrl: serverUrl) { - NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { (_, _, _, _) in } + NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { _, _, _, _ in } } completion(errorCode, errorDescription) } } - + } else { // unlock if let tableLock = NCManageDatabase.shared.getE2ETokenLock(account: account, serverUrl: serverUrl) { - NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { (_, _, _, _) in } + NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { _, _, _, _ in } } completion(errorCode, errorDescription) } @@ -121,29 +121,29 @@ import Alamofire } } } - - //MARK: - WebDav Delete - - func deleteMetadata(_ metadata: tableMetadata, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - - self.lock(account:metadata.account, serverUrl: metadata.serverUrl) { (directory, e2eToken, errorCode, errorDescription) in + + // MARK: - WebDav Delete + + func deleteMetadata(_ metadata: tableMetadata, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + + self.lock(account: metadata.account, serverUrl: metadata.serverUrl) { directory, e2eToken, errorCode, errorDescription in if errorCode == 0 && e2eToken != nil && directory != nil { let deleteE2eEncryption = NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameIdentifier == %@", metadata.account, metadata.serverUrl, metadata.fileName) - NCNetworking.shared.deleteMetadataPlain(metadata, addCustomHeaders: ["e2e-token" :e2eToken!]) { (errorCode, errorDescription) in - + NCNetworking.shared.deleteMetadataPlain(metadata, addCustomHeaders: ["e2e-token": e2eToken!]) { errorCode, errorDescription in + let home = NCUtilityFileSystem.shared.getHomeServer(account: metadata.account) if metadata.serverUrl != home { - self.sendE2EMetadata(account: metadata.account, serverUrl: metadata.serverUrl, fileNameRename: nil, fileNameNewRename: nil, deleteE2eEncryption: deleteE2eEncryption, urlBase: metadata.urlBase) { (e2eToken, errorCode, errorDescription) in + self.sendE2EMetadata(account: metadata.account, serverUrl: metadata.serverUrl, fileNameRename: nil, fileNameNewRename: nil, deleteE2eEncryption: deleteE2eEncryption, urlBase: metadata.urlBase) { e2eToken, errorCode, errorDescription in // unlock if let tableLock = NCManageDatabase.shared.getE2ETokenLock(account: metadata.account, serverUrl: metadata.serverUrl) { - NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { (_, _, _, _) in } + NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { _, _, _, _ in } } completion(errorCode, errorDescription) } } else { // unlock if let tableLock = NCManageDatabase.shared.getE2ETokenLock(account: metadata.account, serverUrl: metadata.serverUrl) { - NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { (_, _, _, _) in } + NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { _, _, _, _ in } } completion(errorCode, errorDescription) } @@ -153,61 +153,61 @@ import Alamofire } } } - - //MARK: - WebDav Rename - - func renameMetadata(_ metadata: tableMetadata, fileNameNew: String, completion: @escaping (_ errorCode: Int, _ errorDescription: String?)->()) { - + + // MARK: - WebDav Rename + + func renameMetadata(_ metadata: tableMetadata, fileNameNew: String, completion: @escaping (_ errorCode: Int, _ errorDescription: String?) -> Void) { + // verify if exists the new fileName if NCManageDatabase.shared.getE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@", metadata.account, metadata.serverUrl, fileNameNew)) != nil { - + completion(NCGlobal.shared.errorInternalError, "_file_already_exists_") } else { - - self.sendE2EMetadata(account: metadata.account, serverUrl: metadata.serverUrl, fileNameRename: metadata.fileName, fileNameNewRename: fileNameNew, deleteE2eEncryption: nil, urlBase: metadata.urlBase) { (e2eToken, errorCode, errorDescription) in - + + self.sendE2EMetadata(account: metadata.account, serverUrl: metadata.serverUrl, fileNameRename: metadata.fileName, fileNameNewRename: fileNameNew, deleteE2eEncryption: nil, urlBase: metadata.urlBase) { e2eToken, errorCode, errorDescription in + if errorCode == 0 { NCManageDatabase.shared.setMetadataFileNameView(serverUrl: metadata.serverUrl, fileName: metadata.fileName, newFileNameView: fileNameNew, account: metadata.account) - + // Move file system let atPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId) + "/" + metadata.fileNameView let toPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId) + "/" + fileNameNew do { try FileManager.default.moveItem(atPath: atPath, toPath: toPath) } catch { } - + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterRenameFile, userInfo: ["ocId": metadata.ocId]) } - + // unlock if let tableLock = NCManageDatabase.shared.getE2ETokenLock(account: metadata.account, serverUrl: metadata.serverUrl) { - NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { (_, _, _, _) in } + NCCommunication.shared.lockE2EEFolder(fileId: tableLock.fileId, e2eToken: tableLock.e2eToken, method: "DELETE") { _, _, _, _ in } } - + completion(errorCode, errorDescription) } } } - - //MARK: - Upload - - func upload(metadata: tableMetadata, start: @escaping () -> Void, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) { - + + // MARK: - Upload + + func upload(metadata: tableMetadata, start: @escaping () -> Void, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) { + let objectE2eEncryption = tableE2eEncryption() var key: NSString?, initializationVector: NSString?, authenticationTag: NSString? let ocIdTemp = metadata.ocId let serverUrl = metadata.serverUrl - + // Verify max size if metadata.size > NCGlobal.shared.e2eeMaxFileSize { NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp)) - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId":metadata.ocId, "ocIdTemp":ocIdTemp, "errorCode":NCGlobal.shared.errorInternalError, "errorDescription":"E2E Error file too big"]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "ocIdTemp": ocIdTemp, "errorCode": NCGlobal.shared.errorInternalError, "errorDescription": "E2E Error file too big"]) start() return completion(NCGlobal.shared.errorInternalError, "E2E Error file too big") } - + // Update metadata var metadata = tableMetadata.init(value: metadata) metadata.fileName = CCUtility.generateRandomIdentifier()! @@ -215,19 +215,19 @@ import Alamofire metadata.session = NCCommunicationCommon.shared.sessionIdentifierUpload metadata.sessionError = "" NCManageDatabase.shared.addMetadata(metadata) - + let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileName)! let fileNameLocalPathRequest = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! let serverUrlFileName = serverUrl + "/" + metadata.fileName - + if NCEndToEndEncryption.sharedManager()?.encryptFileName(metadata.fileNameView, fileNameIdentifier: metadata.fileName, directory: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId), key: &key, initializationVector: &initializationVector, authenticationTag: &authenticationTag) == false { - + NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp)) - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId":metadata.ocId, "ocIdTemp":ocIdTemp, "errorCode":NCGlobal.shared.errorInternalError, "errorDescription":"_e2e_error_create_encrypted_"]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "ocIdTemp": ocIdTemp, "errorCode": NCGlobal.shared.errorInternalError, "errorDescription": "_e2e_error_create_encrypted_"]) start() return completion(NCGlobal.shared.errorInternalError, "_e2e_error_create_encrypted_") } - + if let result = NCManageDatabase.shared.getE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, serverUrl)) { objectE2eEncryption.metadataKey = result.metadataKey objectE2eEncryption.metadataKeyIndex = result.metadataKeyIndex @@ -236,7 +236,7 @@ import Alamofire objectE2eEncryption.metadataKey = key!.base64EncodedString() objectE2eEncryption.metadataKeyIndex = 0 } - + objectE2eEncryption.account = metadata.account objectE2eEncryption.authenticationTag = authenticationTag as String? objectE2eEncryption.fileName = metadata.fileNameView @@ -247,185 +247,188 @@ import Alamofire objectE2eEncryption.mimeType = metadata.contentType objectE2eEncryption.serverUrl = serverUrl objectE2eEncryption.version = 1 - + NCManageDatabase.shared.addE2eEncryption(objectE2eEncryption) - + if let getMetadata = NCManageDatabase.shared.getMetadataFromOcId(ocIdTemp) { metadata = getMetadata } else { start() return completion(NCGlobal.shared.errorInternalError, "_e2e_error_create_encrypted_") } - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["ocId":metadata.ocId, "serverUrl":metadata.serverUrl]) - + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl]) + NCContentPresenter.shared.noteTop(text: NSLocalizedString("_upload_e2ee_", comment: ""), image: nil, type: NCContentPresenter.messageType.info, delay: NCGlobal.shared.dismissAfterSecond, priority: .max) - - NCNetworkingE2EE.shared.sendE2EMetadata(account: metadata.account, serverUrl: serverUrl, fileNameRename: nil, fileNameNewRename: nil, deleteE2eEncryption: nil, urlBase: metadata.urlBase, upload: true) { (e2eToken, errorCode, errorDescription) in - + + NCNetworkingE2EE.shared.sendE2EMetadata(account: metadata.account, serverUrl: serverUrl, fileNameRename: nil, fileNameNewRename: nil, deleteE2eEncryption: nil, urlBase: metadata.urlBase, upload: true) { e2eToken, errorCode, errorDescription in + start() - + if errorCode == 0 && e2eToken != nil { - - NCCommunication.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: metadata.date as Date, dateModificationFile: metadata.date as Date, addCustomHeaders: ["e2e-token":e2eToken!], requestHandler: { (request) in - + + NCCommunication.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: metadata.date as Date, dateModificationFile: metadata.date as Date, addCustomHeaders: ["e2e-token": e2eToken!], requestHandler: { request in + NCNetworking.shared.uploadRequest[fileNameLocalPathRequest] = request NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: nil, sessionError: nil, sessionSelector: nil, sessionTaskIdentifier: nil, status: NCGlobal.shared.metadataStatusUploading) - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId":metadata.ocId]) - - }, taskHandler: { (_) in - - }, progressHandler: { (progress) in - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterProgressTask, userInfo: ["account":metadata.account, "ocId":metadata.ocId, "fileName":metadata.fileName, "serverUrl":serverUrl, "status":NSNumber(value: NCGlobal.shared.metadataStatusInUpload), "progress":NSNumber(value: progress.fractionCompleted), "totalBytes":NSNumber(value: progress.totalUnitCount), "totalBytesExpected":NSNumber(value: progress.completedUnitCount)]) - - }) { (account, ocId, etag, date, size, allHeaderFields, error, errorCode, errorDescription) in - + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId": metadata.ocId]) + + }, taskHandler: { _ in + + }, progressHandler: { progress in + + NotificationCenter.default.postOnMainThread( + name: NCGlobal.shared.notificationCenterProgressTask, + userInfo: [ + "account": metadata.account, + "ocId": metadata.ocId, + "fileName": metadata.fileName, + "serverUrl": serverUrl, + "status": NSNumber(value: NCGlobal.shared.metadataStatusInUpload), + "progress": NSNumber(value: progress.fractionCompleted), + "totalBytes": NSNumber(value: progress.totalUnitCount), + "totalBytesExpected": NSNumber(value: progress.completedUnitCount)]) + + }) { account, ocId, etag, date, _, _, error, errorCode, errorDescription in + NCNetworking.shared.uploadRequest[fileNameLocalPath] = nil - + if let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) { - + let metadata = tableMetadata.init(value: metadata) - + if error?.isExplicitlyCancelledError ?? false { - + CCUtility.removeFile(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)) NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId":metadata.ocId, "ocIdTemp":ocIdTemp, "errorCode":errorCode, "errorDescription":""]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "ocIdTemp": ocIdTemp, "errorCode": errorCode, "errorDescription": ""]) completion(0, "") } else if errorCode == 0 && ocId != nil { - + NCUtilityFileSystem.shared.moveFileInBackground(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId), toPath: CCUtility.getDirectoryProviderStorageOcId(ocId)) - + metadata.date = date ?? NSDate() metadata.etag = etag ?? "" metadata.ocId = ocId! - + metadata.session = "" metadata.sessionError = "" metadata.sessionTaskIdentifier = 0 metadata.status = NCGlobal.shared.metadataStatusNormal - + NCManageDatabase.shared.addMetadata(metadata) NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp)) NCManageDatabase.shared.addLocalFile(metadata: metadata) - + NCUtility.shared.createImageFrom(fileName: metadata.fileNameView, ocId: metadata.ocId, etag: metadata.etag, classFile: metadata.classFile) - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId":metadata.ocId, "ocIdTemp":ocIdTemp ,"errorCode":errorCode, "errorDescription":""]) - + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "ocIdTemp": ocIdTemp, "errorCode": errorCode, "errorDescription": ""]) + } else { - + if errorCode == 401 || errorCode == 403 { - + #if !EXTENSION NCNetworkingCheckRemoteUser.shared.checkRemoteUser(account: metadata.account, errorCode: errorCode, errorDescription: errorDescription) #endif NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: nil, sessionError: errorDescription, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusUploadError) - - } else if errorCode == Int(CFNetworkErrors.cfurlErrorServerCertificateUntrusted.rawValue) { - - if let host = URL(string: metadata.urlBase)?.host { - NCNetworking.shared.certificatesError = host - } - NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: nil, sessionError: errorDescription, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusUploadError) - + } else { - + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: nil, sessionError: errorDescription, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusUploadError) } - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId":metadata.ocId, "ocIdTemp":ocIdTemp, "errorCode":errorCode, "errorDescription":""]) + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "ocIdTemp": ocIdTemp, "errorCode": errorCode, "errorDescription": ""]) } } - - NCNetworkingE2EE.shared.unlock(account: metadata.account, serverUrl: serverUrl) { (_, _, _, _) in + + NCNetworkingE2EE.shared.unlock(account: metadata.account, serverUrl: serverUrl) { _, _, _, _ in completion(errorCode, errorDescription) } } - + } else { - + if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocIdTemp) { NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: nil, sessionError: errorDescription, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusUploadError) - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId":metadata.ocId, "ocIdTemp":ocIdTemp, "errorCode":errorCode, "errorDescription":errorDescription]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadedFile, userInfo: ["ocId": metadata.ocId, "ocIdTemp": ocIdTemp, "errorCode": errorCode, "errorDescription": errorDescription]) } completion(errorCode, errorDescription) } } } - - //MARK: - E2EE - - @objc func lock(account:String, serverUrl: String, completion: @escaping (_ direcrtory: tableDirectory?, _ e2eToken: String?, _ errorCode: Int, _ errorDescription: String?)->()) { - + + // MARK: - E2EE + + @objc func lock(account: String, serverUrl: String, completion: @escaping (_ direcrtory: tableDirectory?, _ e2eToken: String?, _ errorCode: Int, _ errorDescription: String?) -> Void) { + var e2eToken: String? - + guard let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl)) else { return completion(nil, nil, 0, "") } - + if let tableLock = NCManageDatabase.shared.getE2ETokenLock(account: account, serverUrl: serverUrl) { e2eToken = tableLock.e2eToken } - - NCCommunication.shared.lockE2EEFolder(fileId: directory.fileId, e2eToken: e2eToken, method: "POST") { (account, e2eToken, errorCode, errorDescription) in + + NCCommunication.shared.lockE2EEFolder(fileId: directory.fileId, e2eToken: e2eToken, method: "POST") { account, e2eToken, errorCode, errorDescription in if errorCode == 0 && e2eToken != nil { NCManageDatabase.shared.setE2ETokenLock(account: account, serverUrl: serverUrl, fileId: directory.fileId, e2eToken: e2eToken!) } completion(directory, e2eToken, errorCode, errorDescription) } } - - @objc func unlock(account:String, serverUrl: String, completion: @escaping (_ direcrtory: tableDirectory?, _ e2eToken: String?, _ errorCode: Int, _ errorDescription: String?)->()) { - + + @objc func unlock(account: String, serverUrl: String, completion: @escaping (_ direcrtory: tableDirectory?, _ e2eToken: String?, _ errorCode: Int, _ errorDescription: String?) -> Void) { + var e2eToken: String? - + guard let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl)) else { return completion(nil, nil, 0, "") } - + if let tableLock = NCManageDatabase.shared.getE2ETokenLock(account: account, serverUrl: serverUrl) { e2eToken = tableLock.e2eToken } - - NCCommunication.shared.lockE2EEFolder(fileId: directory.fileId, e2eToken: e2eToken, method: "DELETE") { (account, e2eToken, errorCode, errorDescription) in + + NCCommunication.shared.lockE2EEFolder(fileId: directory.fileId, e2eToken: e2eToken, method: "DELETE") { account, e2eToken, errorCode, errorDescription in if errorCode == 0 { NCManageDatabase.shared.deteleE2ETokenLock(account: account, serverUrl: serverUrl) } completion(directory, e2eToken, errorCode, errorDescription) } } - - @objc func sendE2EMetadata(account: String, serverUrl: String, fileNameRename: String?, fileNameNewRename: String?, deleteE2eEncryption : NSPredicate?, urlBase: String, upload: Bool = false, completion: @escaping (_ e2eToken: String?, _ errorCode: Int, _ errorDescription: String)->()) { - - self.lock(account: account, serverUrl: serverUrl) { (directory, e2eToken, errorCode, errorDescription) in + + @objc func sendE2EMetadata(account: String, serverUrl: String, fileNameRename: String?, fileNameNewRename: String?, deleteE2eEncryption: NSPredicate?, urlBase: String, upload: Bool = false, completion: @escaping (_ e2eToken: String?, _ errorCode: Int, _ errorDescription: String) -> Void) { + + self.lock(account: account, serverUrl: serverUrl) { directory, e2eToken, errorCode, errorDescription in if errorCode == 0 && e2eToken != nil && directory != nil { - - NCCommunication.shared.getE2EEMetadata(fileId: directory!.fileId, e2eToken: e2eToken) { (account, e2eMetadata, errorCode, errorDescription) in + + NCCommunication.shared.getE2EEMetadata(fileId: directory!.fileId, e2eToken: e2eToken) { account, e2eMetadata, errorCode, errorDescription in var method = "POST" var e2eMetadataNew: String? - + if errorCode == 0 && e2eMetadata != nil { if !NCEndToEndMetadata.shared.decoderMetadata(e2eMetadata!, privateKey: CCUtility.getEndToEndPrivateKey(account), serverUrl: serverUrl, account: account, urlBase: urlBase) { return completion(e2eToken, NCGlobal.shared.errorInternalError, NSLocalizedString("_e2e_error_encode_metadata_", comment: "")) } method = "PUT" } - + // Rename - if (fileNameRename != nil && fileNameNewRename != nil) { + if fileNameRename != nil && fileNameNewRename != nil { NCManageDatabase.shared.renameFileE2eEncryption(serverUrl: serverUrl, fileNameIdentifier: fileNameRename!, newFileName: fileNameNewRename!, newFileNamePath: CCUtility.returnFileNamePath(fromFileName: fileNameNewRename!, serverUrl: serverUrl, urlBase: urlBase, account: account)) } - + // Delete if deleteE2eEncryption != nil { NCManageDatabase.shared.deleteE2eEncryption(predicate: deleteE2eEncryption!) } - + // Rebuild metadata for send it let tableE2eEncryption = NCManageDatabase.shared.getE2eEncryptions(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl)) if tableE2eEncryption != nil { @@ -433,13 +436,13 @@ import Alamofire } else { method = "DELETE" } - - NCCommunication.shared.putE2EEMetadata(fileId: directory!.fileId, e2eToken: e2eToken!, e2eMetadata: e2eMetadataNew, method: method) { (account, e2eMetadata, errorCode, errorDescription) in + + NCCommunication.shared.putE2EEMetadata(fileId: directory!.fileId, e2eToken: e2eToken!, e2eMetadata: e2eMetadataNew, method: method) { account, _, errorCode, errorDescription in if upload { completion(e2eToken, errorCode, errorDescription) } else { - self.unlock(account: account, serverUrl: serverUrl) { (_, e2eToken, _, _) in + self.unlock(account: account, serverUrl: serverUrl) { _, e2eToken, _, _ in completion(e2eToken, errorCode, errorDescription) } } @@ -451,5 +454,3 @@ import Alamofire } } } - - diff --git a/iOSClient/Networking/NCNetworkingProcessUpload.swift b/iOSClient/Networking/NCNetworkingProcessUpload.swift index 0bd7ec556..018295a4a 100644 --- a/iOSClient/Networking/NCNetworkingProcessUpload.swift +++ b/iOSClient/Networking/NCNetworkingProcessUpload.swift @@ -23,30 +23,31 @@ import UIKit import NCCommunication +import Photos class NCNetworkingProcessUpload: NSObject { let appDelegate = UIApplication.shared.delegate as! AppDelegate var timerProcess: Timer? - + let maxConcurrentOperationUpload = 5 - + override init() { super.init() startTimer() } - + @objc func startProcess() { if timerProcess?.isValid ?? false { process() } } - + func startTimer() { timerProcess?.invalidate() timerProcess = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(process), userInfo: nil, repeats: true) } - + func stopTimer() { timerProcess?.invalidate() } @@ -54,22 +55,22 @@ class NCNetworkingProcessUpload: NSObject { @objc private func process() { if appDelegate.account == "" { return } - + var counterUpload: Int = 0 let sessionSelectors = [NCGlobal.shared.selectorUploadFile, NCGlobal.shared.selectorUploadAutoUpload, NCGlobal.shared.selectorUploadAutoUploadAll] - + let metadatasUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "status == %d OR status == %d", NCGlobal.shared.metadataStatusInUpload, NCGlobal.shared.metadataStatusUploading)) counterUpload = metadatasUpload.count - + stopTimer() - + print("[LOG] PROCESS-UPLOAD \(counterUpload)") - - NCNetworking.shared.getOcIdInBackgroundSession { (listOcId) in - + + NCNetworking.shared.getOcIdInBackgroundSession { listOcId in + for sessionSelector in sessionSelectors { if counterUpload < self.maxConcurrentOperationUpload { - + let limit = self.maxConcurrentOperationUpload - counterUpload var predicate = NSPredicate() if UIApplication.shared.applicationState == .background { @@ -81,20 +82,20 @@ class NCNetworkingProcessUpload: NSObject { if metadatas.count > 0 { NCCommunicationCommon.shared.writeLog("PROCESS-UPLOAD find \(metadatas.count) items") } - + for metadata in metadatas { - + // Is already in upload background? skipped if listOcId.contains(metadata.ocId) { NCCommunicationCommon.shared.writeLog("Process auto upload skipped file: \(metadata.serverUrl)/\(metadata.fileNameView), because is already in session.") continue } - + // Session Extension ? skipped if metadata.session == NCNetworking.shared.sessionIdentifierBackgroundExtension { continue } - + // Is already in upload E2EE / CHUNK ? exit [ ONLY ONE IN QUEUE ] for metadata in metadatasUpload { if metadata.chunk || metadata.e2eEncrypted { @@ -102,13 +103,13 @@ class NCNetworkingProcessUpload: NSObject { return } } - + // Chunk if metadata.chunk && UIApplication.shared.applicationState == .active { if let metadata = NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusInUpload) { NCNetworking.shared.upload(metadata: metadata) { // start - } completion: { (_, _) in + } completion: { _, _ in DispatchQueue.main.async { self.startTimer() } @@ -118,13 +119,13 @@ class NCNetworkingProcessUpload: NSObject { } return } - + // E2EE if metadata.e2eEncrypted && UIApplication.shared.applicationState == .active { if let metadata = NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusInUpload) { NCNetworking.shared.upload(metadata: metadata) { // start - } completion: { (_, _) in + } completion: { _, _ in DispatchQueue.main.async { self.startTimer() } @@ -134,33 +135,35 @@ class NCNetworkingProcessUpload: NSObject { } return } - + counterUpload += 1 if let metadata = NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusInUpload) { NCNetworking.shared.upload(metadata: metadata) { // start - } completion: { (_, _) in + } completion: { _, _ in // completion } } } - + } else { self.startTimer() return } } - + // No upload available ? --> Retry Upload in Error if counterUpload == 0 { let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "status == %d", NCGlobal.shared.metadataStatusUploadError)) for metadata in metadatas { - NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: NCNetworking.shared.sessionIdentifierBackground, sessionError: "", sessionTaskIdentifier: 0 ,status: NCGlobal.shared.metadataStatusWaitUpload) + NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: NCNetworking.shared.sessionIdentifierBackground, sessionError: "", sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusWaitUpload) } } + + // verify delete Asset Local Identifiers in auto upload (DELETE Photos album) - if (counterUpload == 0 && self.appDelegate.passcodeViewController == nil) { + if (counterUpload == 0 && !self.appDelegate.isPasscodePresented()) { self.deleteAssetLocalIdentifiers(account: self.appDelegate.account, sessionSelector: NCGlobal.shared.selectorUploadAutoUpload) { self.startTimer() } @@ -169,54 +172,54 @@ class NCNetworkingProcessUpload: NSObject { } } } - - private func deleteAssetLocalIdentifiers(account: String, sessionSelector: String, completition: @escaping () -> ()) { - + + private func deleteAssetLocalIdentifiers(account: String, sessionSelector: String, completition: @escaping () -> Void) { + if UIApplication.shared.applicationState != .active { completition() return } let metadatasSessionUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND session CONTAINS[cd] %@", account, "upload")) - if metadatasSessionUpload.count > 0 { + if !metadatasSessionUpload.isEmpty { completition() return } let localIdentifiers = NCManageDatabase.shared.getAssetLocalIdentifiersUploaded(account: account, sessionSelector: sessionSelector) - if localIdentifiers.count == 0 { + if localIdentifiers.isEmpty { completition() return } let assets = PHAsset.fetchAssets(withLocalIdentifiers: localIdentifiers, options: nil) - + PHPhotoLibrary.shared().performChanges({ PHAssetChangeRequest.deleteAssets(assets as NSFastEnumeration) - }, completionHandler: { success, error in + }, completionHandler: { _, _ in DispatchQueue.main.async { NCManageDatabase.shared.clearAssetLocalIdentifiers(localIdentifiers, account: account) completition() } }) } - - //MARK: - - + + // MARK: - + @objc func createProcessUploads(metadatas: [tableMetadata], verifyAlreadyExists: Bool = false) { - + var metadatasForUpload: [tableMetadata] = [] - + for metadata in metadatas { - + if verifyAlreadyExists { if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ && serverUrl == %@ && fileName == %@ && session != ''", metadata.account, metadata.serverUrl, metadata.fileName)) != nil { continue } } - + // E2EE if CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase) { metadata.e2eEncrypted = true } - + // CHUNCK let chunckSize = CCUtility.getChunkSize() * 1000000 if chunckSize == 0 || metadata.size <= chunckSize { @@ -227,20 +230,26 @@ class NCNetworkingProcessUpload: NSObject { metadatasForUpload.append(tableMetadata.init(value: metadata)) } } - + NCManageDatabase.shared.addMetadatas(metadatasForUpload) - + startProcess() } - - //MARK: - + + // MARK: - @objc func verifyUploadZombie() { - + var session: URLSession? - + // 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)) + 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)) { @@ -248,26 +257,26 @@ class NCNetworkingProcessUpload: NSObject { } } } - + // 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 + + session?.getAllTasks(completionHandler: { tasks in for task in tasks { if task.taskIdentifier == metadata.sessionTaskIdentifier { taskUpload = task } } - + 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) @@ -275,7 +284,7 @@ class NCNetworkingProcessUpload: NSObject { } }) } - + // metadataStatusUploading OR metadataStatusInUpload (FOREGROUND) let metadatasUploading = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "session == %@ AND (status == %d OR status == %d)", NCCommunicationCommon.shared.sessionIdentifierUpload, NCGlobal.shared.metadataStatusUploading, NCGlobal.shared.metadataStatusInUpload)) for metadata in metadatasUploading { @@ -286,4 +295,3 @@ class NCNetworkingProcessUpload: NSObject { } } } - diff --git a/iOSClient/Networking/NCOperationQueue.swift b/iOSClient/Networking/NCOperationQueue.swift index 0869333b9..82be80822 100644 --- a/iOSClient/Networking/NCOperationQueue.swift +++ b/iOSClient/Networking/NCOperationQueue.swift @@ -21,7 +21,6 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // - import UIKit import Queuer import NCCommunication @@ -31,7 +30,7 @@ import NCCommunication let instance = NCOperationQueue() return instance }() - + private var downloadQueue = Queuer(name: "downloadQueue", maxConcurrentOperationCount: 5, qualityOfService: .default) private let deleteQueue = Queuer(name: "deleteQueue", maxConcurrentOperationCount: 1, qualityOfService: .default) private let copyMoveQueue = Queuer(name: "copyMoveQueue", maxConcurrentOperationCount: 1, qualityOfService: .default) @@ -49,16 +48,16 @@ import NCCommunication downloadThumbnailCancelAll() downloadAvatarCancelAll() } - + // Download file - + func download(metadata: tableMetadata, selector: String) { - for operation in downloadQueue.operations as! [NCOperationDownload] { + for operation in downloadQueue.operations as! [NCOperationDownload] { if operation.metadata.ocId == metadata.ocId { return } } - downloadQueue.addOperation(NCOperationDownload.init(metadata: metadata, selector: selector)) + downloadQueue.addOperation(NCOperationDownload(metadata: metadata, selector: selector)) } @objc func downloadCancelAll() { downloadQueue.cancelAll() @@ -67,23 +66,23 @@ import NCCommunication return downloadQueue.operationCount } @objc func downloadExists(metadata: tableMetadata) -> Bool { - for operation in downloadQueue.operations as! [NCOperationDownload] { + for operation in downloadQueue.operations as! [NCOperationDownload] { if operation.metadata.ocId == metadata.ocId { return true } } return false } - + // Delete file - + @objc func delete(metadata: tableMetadata, onlyLocalCache: Bool) { - for operation in deleteQueue.operations as! [NCOperationDelete] { + for operation in deleteQueue.operations as! [NCOperationDelete] { if operation.metadata.ocId == metadata.ocId { return } } - deleteQueue.addOperation(NCOperationDelete.init(metadata: metadata, onlyLocalCache: onlyLocalCache)) + deleteQueue.addOperation(NCOperationDelete(metadata: metadata, onlyLocalCache: onlyLocalCache)) } @objc func deleteCancelAll() { deleteQueue.cancelAll() @@ -91,16 +90,16 @@ import NCCommunication @objc func deleteCount() -> Int { return deleteQueue.operationCount } - + // Copy Move file - + @objc func copyMove(metadata: tableMetadata, serverUrl: String, overwrite: Bool, move: Bool) { - for operation in copyMoveQueue.operations as! [NCOperationCopyMove] { + for operation in copyMoveQueue.operations as! [NCOperationCopyMove] { if operation.metadata.ocId == metadata.ocId { return } } - copyMoveQueue.addOperation(NCOperationCopyMove.init(metadata: metadata, serverUrlTo: serverUrl, overwrite: overwrite, move: move)) + copyMoveQueue.addOperation(NCOperationCopyMove(metadata: metadata, serverUrlTo: serverUrl, overwrite: overwrite, move: move)) } @objc func copyMoveCancelAll() { copyMoveQueue.cancelAll() @@ -108,45 +107,45 @@ import NCCommunication @objc func copyMoveCount() -> Int { return copyMoveQueue.operationCount } - + // Synchronization - + @objc func synchronizationMetadata(_ metadata: tableMetadata, selector: String) { for operation in synchronizationQueue.operations as! [NCOperationSynchronization] { if operation.metadata.ocId == metadata.ocId { return } } - synchronizationQueue.addOperation(NCOperationSynchronization.init(metadata: metadata, selector: selector)) + synchronizationQueue.addOperation(NCOperationSynchronization(metadata: metadata, selector: selector)) } @objc func synchronizationCancelAll() { synchronizationQueue.cancelAll() } - + // Download Thumbnail - + @objc func downloadThumbnail(metadata: tableMetadata, placeholder: Bool, cell: UIView?, view: UIView?) { - + let cell: NCCellProtocol? = cell as? NCCellProtocol - + if placeholder { if metadata.iconName.count > 0 { - cell?.filePreviewImageView?.image = UIImage.init(named: metadata.iconName) + cell?.filePreviewImageView?.image = UIImage(named: metadata.iconName) } else { cell?.filePreviewImageView?.image = NCBrandColor.cacheImages.file } } - + if metadata.hasPreview && metadata.status == NCGlobal.shared.metadataStatusNormal && (!CCUtility.fileProviderStoragePreviewIconExists(metadata.ocId, etag: metadata.etag)) { for operation in downloadThumbnailQueue.operations as! [NCOperationDownloadThumbnail] { if operation.metadata.ocId == metadata.ocId { return } } - downloadThumbnailQueue.addOperation(NCOperationDownloadThumbnail.init(metadata: metadata, cell: cell, view: view)) + downloadThumbnailQueue.addOperation(NCOperationDownloadThumbnail(metadata: metadata, cell: cell, view: view)) } } - + func cancelDownloadThumbnail(metadata: tableMetadata) { for operation in downloadThumbnailQueue.operations as! [NCOperationDownloadThumbnail] { if operation.metadata.ocId == metadata.ocId { @@ -154,17 +153,17 @@ import NCCommunication } } } - + @objc func downloadThumbnailCancelAll() { downloadThumbnailQueue.cancelAll() } - + // Download Avatar - + func downloadAvatar(user: String, dispalyName: String?, fileName: String, cell: NCCellProtocol, view: UIView?) { let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName - + if let image = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) { cell.fileAvatarImageView?.image = image return @@ -182,9 +181,9 @@ import NCCommunication return } } - downloadAvatarQueue.addOperation(NCOperationDownloadAvatar.init(user: user, fileName: fileName, fileNameLocalPath: fileNameLocalPath, cell: cell, view: view)) + downloadAvatarQueue.addOperation(NCOperationDownloadAvatar(user: user, fileName: fileName, fileNameLocalPath: fileNameLocalPath, cell: cell, view: view)) } - + func cancelDownloadAvatar(user: String) { for operation in downloadAvatarQueue.operations as! [NCOperationDownloadAvatar] { if operation.user == user { @@ -192,52 +191,52 @@ import NCCommunication } } } - + @objc func downloadAvatarCancelAll() { downloadAvatarQueue.cancelAll() } } -//MARK: - +// MARK: - class NCOperationDownload: ConcurrentOperation { - + var metadata: tableMetadata var selector: String - + init(metadata: tableMetadata, selector: String) { self.metadata = tableMetadata.init(value: metadata) self.selector = selector } - + override func start() { if isCancelled { self.finish() } else { - NCNetworking.shared.download(metadata: metadata, selector: self.selector) { (_) in + NCNetworking.shared.download(metadata: metadata, selector: self.selector) { _ in self.finish() } } } } -//MARK: - +// MARK: - class NCOperationDelete: ConcurrentOperation { - + var metadata: tableMetadata var onlyLocalCache: Bool - + init(metadata: tableMetadata, onlyLocalCache: Bool) { self.metadata = tableMetadata.init(value: metadata) self.onlyLocalCache = onlyLocalCache } - + override func start() { if isCancelled { self.finish() } else { - NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: onlyLocalCache) { (errorCode, errorDescription) in + NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: onlyLocalCache) { errorCode, errorDescription in if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } @@ -247,10 +246,10 @@ class NCOperationDelete: ConcurrentOperation { } } -//MARK: - +// MARK: - class NCOperationCopyMove: ConcurrentOperation { - + var metadata: tableMetadata var serverUrlTo: String var overwrite: Bool @@ -262,20 +261,20 @@ class NCOperationCopyMove: ConcurrentOperation { self.overwrite = overwrite self.move = move } - + override func start() { if isCancelled { self.finish() } else { if move { - NCNetworking.shared.moveMetadata(metadata, serverUrlTo: serverUrlTo, overwrite: overwrite) { (errorCode, errorDescription) in + NCNetworking.shared.moveMetadata(metadata, serverUrlTo: serverUrlTo, overwrite: overwrite) { errorCode, errorDescription in if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } self.finish() } } else { - NCNetworking.shared.copyMetadata(metadata, serverUrlTo: serverUrlTo, overwrite: overwrite) { (errorCode, errorDescription) in + NCNetworking.shared.copyMetadata(metadata, serverUrlTo: serverUrlTo, overwrite: overwrite) { errorCode, errorDescription in if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } @@ -286,14 +285,14 @@ class NCOperationCopyMove: ConcurrentOperation { } } -//MARK: - +// MARK: - class NCOperationSynchronization: ConcurrentOperation { - + var metadata: tableMetadata var selector: String var download: Bool - + init(metadata: tableMetadata, selector: String) { self.metadata = tableMetadata.init(value: metadata) self.selector = selector @@ -303,30 +302,30 @@ class NCOperationSynchronization: ConcurrentOperation { self.download = false } } - + override func start() { if isCancelled { self.finish() } else { if metadata.directory { - + let serverUrl = metadata.serverUrl + "/" + metadata.fileName let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, serverUrl)) - NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles()) { (account, files, responseData, errorCode, errorDescription) in + NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles()) { account, files, _, errorCode, _ in if (errorCode == 0) && (directory?.etag != files.first?.etag || self.selector == NCGlobal.shared.selectorDownloadAllFile) { - - NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "1", showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { (account, files, responseData, errorCode, errorDescription) in - + + NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "1", showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { account, files, _, errorCode, _ in + if errorCode == 0 { - - NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: true, account: account) { (metadataFolder, metadatasFolder, metadatas) in - + + NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: true, account: account) { metadataFolder, _, metadatas in + let metadatasResult = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND status == %d", account, serverUrl, NCGlobal.shared.metadataStatusNormal)) - + if self.selector == NCGlobal.shared.selectorDownloadAllFile { - + NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult) for metadata in metadatas { @@ -338,9 +337,9 @@ class NCOperationSynchronization: ConcurrentOperation { } } } - + } else { - + let metadatasChanged = NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult, addExistsInLocal: self.download, addCompareEtagLocal: true, addDirectorySynchronized: true) for metadata in metadatasChanged.metadatasUpdate { @@ -348,25 +347,25 @@ class NCOperationSynchronization: ConcurrentOperation { NCOperationQueue.shared.synchronizationMetadata(metadata, selector: self.selector) } } - + for metadata in metadatasChanged.metadatasLocalUpdate { NCOperationQueue.shared.download(metadata: metadata, selector: self.selector) } } - + // Update etag directory NCManageDatabase.shared.addDirectory(encrypted: metadataFolder.e2eEncrypted, favorite: metadataFolder.favorite, ocId: metadataFolder.ocId, fileId: metadataFolder.fileId, etag: metadataFolder.etag, permissions: metadataFolder.permissions, serverUrl: serverUrl, account: metadataFolder.account) } - + } else if errorCode == NCGlobal.shared.errorResourceNotFound && self.metadata.directory { NCManageDatabase.shared.deleteDirectoryAndSubDirectory(serverUrl: self.metadata.serverUrl, account: self.metadata.account) } - + self.finish() } - + } else { - + let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl)) for metadata in metadatas { if metadata.directory { @@ -377,11 +376,11 @@ class NCOperationSynchronization: ConcurrentOperation { } } } - + self.finish() } } - + } else { if NCManageDatabase.shared.isDownloadMetadata(metadata, download: self.download) { NCOperationQueue.shared.download(metadata: metadata, selector: self.selector) @@ -392,17 +391,17 @@ class NCOperationSynchronization: ConcurrentOperation { } } -//MARK: - +// MARK: - class NCOperationDownloadThumbnail: ConcurrentOperation { - + var metadata: tableMetadata var cell: NCCellProtocol? var view: UIView? var fileNamePath: String = "" var fileNamePreviewLocalPath: String = "" var fileNameIconLocalPath: String = "" - + init(metadata: tableMetadata, cell: NCCellProtocol?, view: UIView?) { self.metadata = tableMetadata.init(value: metadata) self.cell = cell @@ -411,7 +410,7 @@ class NCOperationDownloadThumbnail: ConcurrentOperation { self.fileNamePreviewLocalPath = CCUtility.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)! self.fileNameIconLocalPath = CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)! } - + override func start() { if isCancelled { @@ -421,40 +420,47 @@ class NCOperationDownloadThumbnail: ConcurrentOperation { if FileManager.default.fileExists(atPath: fileNameIconLocalPath) && FileManager.default.fileExists(atPath: fileNamePreviewLocalPath) { etagResource = metadata.etagResource } - NCCommunication.shared.downloadPreview(fileNamePathOrFileId: fileNamePath, fileNamePreviewLocalPath: fileNamePreviewLocalPath , widthPreview: NCGlobal.shared.sizePreview, heightPreview: NCGlobal.shared.sizePreview, fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon, etag: etagResource, queue: NCCommunicationCommon.shared.backgroundQueue) { (account, imagePreview, imageIcon, imageOriginal, etag, errorCode, errorDescription) in - - if errorCode == 0 && imageIcon != nil { - NCManageDatabase.shared.setMetadataEtagResource(ocId: self.metadata.ocId, etagResource: etag) - DispatchQueue.main.async { - if self.metadata.ocId == self.cell?.fileObjectId { - if let filePreviewImageView = self.cell?.filePreviewImageView { - UIView.transition(with: filePreviewImageView, - duration: 0.75, - options: .transitionCrossDissolve, - animations: { filePreviewImageView.image = imageIcon! }, - completion: nil) - } - } else { - if self.view is UICollectionView { - (self.view as? UICollectionView)?.reloadData() - } else if self.view is UITableView{ - (self.view as? UITableView)?.reloadData() + NCCommunication.shared.downloadPreview( + fileNamePathOrFileId: fileNamePath, + fileNamePreviewLocalPath: fileNamePreviewLocalPath, + widthPreview: NCGlobal.shared.sizePreview, + heightPreview: NCGlobal.shared.sizePreview, + fileNameIconLocalPath: fileNameIconLocalPath, + sizeIcon: NCGlobal.shared.sizeIcon, + etag: etagResource, + queue: NCCommunicationCommon.shared.backgroundQueue) { _, _, imageIcon, _, etag, errorCode, _ in + + if errorCode == 0 && imageIcon != nil { + NCManageDatabase.shared.setMetadataEtagResource(ocId: self.metadata.ocId, etagResource: etag) + DispatchQueue.main.async { + if self.metadata.ocId == self.cell?.fileObjectId { + if let filePreviewImageView = self.cell?.filePreviewImageView { + UIView.transition(with: filePreviewImageView, + duration: 0.75, + options: .transitionCrossDissolve, + animations: { filePreviewImageView.image = imageIcon! }, + completion: nil) + } + } else { + if self.view is UICollectionView { + (self.view as? UICollectionView)?.reloadData() + } else if self.view is UITableView { + (self.view as? UITableView)?.reloadData() + } } + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedThumbnail, userInfo: ["ocId": self.metadata.ocId]) } - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedThumbnail, userInfo: ["ocId": self.metadata.ocId]) } + self.finish() } - self.finish() - } } } } -//MARK: - +// MARK: - class NCOperationDownloadAvatar: ConcurrentOperation { - let appDelegate = UIApplication.shared.delegate as! AppDelegate var user: String var fileName: String var etag: String? @@ -470,27 +476,27 @@ class NCOperationDownloadAvatar: ConcurrentOperation { self.view = view self.etag = NCManageDatabase.shared.getTableAvatar(fileName: fileName)?.etag } - + override func start() { if isCancelled { self.finish() } else { - NCCommunication.shared.downloadAvatar(user: user, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: self.etag, queue: NCCommunicationCommon.shared.backgroundQueue) { (account, imageAvatar, imageOriginal, etag, errorCode, errorMessage) in - + NCCommunication.shared.downloadAvatar(user: user, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: self.etag, queue: NCCommunicationCommon.shared.backgroundQueue) { _, imageAvatar, _, etag, errorCode, _ in + if errorCode == 0, let imageAvatar = imageAvatar, let etag = etag { - + NCManageDatabase.shared.addAvatar(fileName: self.fileName, etag: etag) DispatchQueue.main.async { if self.user == self.cell.fileUser { - if let avatarImageView = self.cell?.fileAvatarImageView { + if let avatarImageView = self.cell?.fileAvatarImageView { UIView.transition(with: avatarImageView, duration: 0.75, options: .transitionCrossDissolve) { avatarImageView.image = imageAvatar } completion: { _ in if self.view is UICollectionView { (self.view as? UICollectionView)?.reloadData() - } else if self.view is UITableView{ + } else if self.view is UITableView { (self.view as? UITableView)?.reloadData() } } @@ -498,17 +504,17 @@ class NCOperationDownloadAvatar: ConcurrentOperation { } else { if self.view is UICollectionView { (self.view as? UICollectionView)?.reloadData() - } else if self.view is UITableView{ + } else if self.view is UITableView { (self.view as? UITableView)?.reloadData() } } } - + } else if errorCode == NCGlobal.shared.errorNotModified { - + NCManageDatabase.shared.setAvatarLoaded(fileName: self.fileName) } - + self.finish() } } diff --git a/iOSClient/Networking/NCService.swift b/iOSClient/Networking/NCService.swift index 38cee25df..0084bdd7f 100644 --- a/iOSClient/Networking/NCService.swift +++ b/iOSClient/Networking/NCService.swift @@ -30,29 +30,29 @@ class NCService: NSObject { let instance = NCService() return instance }() - + let appDelegate = UIApplication.shared.delegate as! AppDelegate - - //MARK: - - + + // MARK: - + @objc public func startRequestServicesServer() { - + NCManageDatabase.shared.clearAllAvatarLoaded() - + if appDelegate.account == "" { return } - + self.addInternalTypeIdentifier() self.requestUserProfile() self.requestServerStatus() } - //MARK: - - + // MARK: - + func addInternalTypeIdentifier() { // txt NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "text/plain", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorText, iconName: NCCommunicationCommon.typeIconFile.document.rawValue, name: "markdown") - + // html NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "text/html", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorText, iconName: NCCommunicationCommon.typeIconFile.document.rawValue, name: "markdown") @@ -62,41 +62,41 @@ class NCService: NSObject { // document: text NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "org.oasis-open.opendocument.text", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorCollabora, iconName: NCCommunicationCommon.typeIconFile.document.rawValue, name: "document") - NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "org.openxmlformats.wordprocessingml.document", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorOnlyoffice ,iconName: NCCommunicationCommon.typeIconFile.document.rawValue, name: "document") + NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "org.openxmlformats.wordprocessingml.document", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorOnlyoffice, iconName: NCCommunicationCommon.typeIconFile.document.rawValue, name: "document") NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "com.microsoft.word.doc", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorQuickLook, iconName: NCCommunicationCommon.typeIconFile.document.rawValue, name: "document") NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "com.apple.iwork.pages.pages", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorQuickLook, iconName: NCCommunicationCommon.typeIconFile.document.rawValue, name: "pages") - + // document: sheet NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "org.oasis-open.opendocument.spreadsheet", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorCollabora, iconName: NCCommunicationCommon.typeIconFile.xls.rawValue, name: "sheet") NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "org.openxmlformats.spreadsheetml.sheet", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorOnlyoffice, iconName: NCCommunicationCommon.typeIconFile.xls.rawValue, name: "sheet") NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "com.microsoft.excel.xls", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorQuickLook, iconName: NCCommunicationCommon.typeIconFile.xls.rawValue, name: "sheet") NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "com.apple.iwork.numbers.numbers", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorQuickLook, iconName: NCCommunicationCommon.typeIconFile.xls.rawValue, name: "numbers") - + // document: presentation NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "org.oasis-open.opendocument.presentation", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorCollabora, iconName: NCCommunicationCommon.typeIconFile.ppt.rawValue, name: "presentation") NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "org.openxmlformats.presentationml.presentation", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorOnlyoffice, iconName: NCCommunicationCommon.typeIconFile.ppt.rawValue, name: "presentation") NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "com.microsoft.powerpoint.ppt", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorQuickLook, iconName: NCCommunicationCommon.typeIconFile.ppt.rawValue, name: "presentation") NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: "com.apple.iwork.keynote.key", classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorQuickLook, iconName: NCCommunicationCommon.typeIconFile.ppt.rawValue, name: "keynote") } - + private func requestUserProfile() { - + if appDelegate.account == "" { return } - - NCCommunication.shared.getUserProfile(queue: NCCommunicationCommon.shared.backgroundQueue) { (account, userProfile, errorCode, errorDescription) in - + + NCCommunication.shared.getUserProfile(queue: NCCommunicationCommon.shared.backgroundQueue) { account, userProfile, errorCode, errorDescription in + if errorCode == 0 && account == self.appDelegate.account { - + // Update User (+ userProfile.id) & active account & account network guard let tableAccount = NCManageDatabase.shared.setAccountUserProfile(userProfile!) else { - NCContentPresenter.shared.messageNotification("Account", description: "Internal error : account not found on DB", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError, priority: .max) + NCContentPresenter.shared.messageNotification("Account", description: "Internal error : account not found on DB", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError, priority: .max) return } self.appDelegate.settingAccount(tableAccount.account, urlBase: tableAccount.urlBase, user: tableAccount.user, userId: tableAccount.userId, password: CCUtility.getPassword(tableAccount.account)) // Synchronize favorite - NCNetworking.shared.listingFavoritescompletion(selector: NCGlobal.shared.selectorReadFile) { (_, _, _, _) in } + NCNetworking.shared.listingFavoritescompletion(selector: NCGlobal.shared.selectorReadFile) { _, _, _, _ in } // Synchronize Offline self.synchronizeOffline(account: tableAccount.account) @@ -106,33 +106,33 @@ class NCService: NSObject { let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName let etag = NCManageDatabase.shared.getTableAvatar(fileName: fileName)?.etag - NCCommunication.shared.downloadAvatar(user: tableAccount.userId, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: etag, queue: NCCommunicationCommon.shared.backgroundQueue) { (account, image, imageOriginal, etag, errorCode, errorMessage) in + NCCommunication.shared.downloadAvatar(user: tableAccount.userId, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: etag, queue: NCCommunicationCommon.shared.backgroundQueue) { _, _, _, etag, errorCode, _ in if let etag = etag, errorCode == 0 { NCManageDatabase.shared.addAvatar(fileName: fileName, etag: etag) NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadAvatar, userInfo: nil) } else if errorCode == NCGlobal.shared.errorNotModified { - + NCManageDatabase.shared.setAvatarLoaded(fileName: fileName) } } self.requestServerCapabilities() - + } else { - + if errorCode == 401 || errorCode == 403 { NCNetworkingCheckRemoteUser.shared.checkRemoteUser(account: account, errorCode: errorCode, errorDescription: errorDescription) } } } } - + private func requestServerStatus() { - - NCCommunication.shared.getServerStatus(serverUrl: appDelegate.urlBase, queue: NCCommunicationCommon.shared.backgroundQueue) { (serverProductName, serverVersion, versionMajor, versionMinor, versionMicro, extendedSupport, errorCode, errorMessage) in - + + NCCommunication.shared.getServerStatus(serverUrl: appDelegate.urlBase, queue: NCCommunicationCommon.shared.backgroundQueue) { serverProductName, _, versionMajor, _, _, extendedSupport, errorCode, _ in + if errorCode == 0 && extendedSupport == false { - + if serverProductName == "owncloud" { NCContentPresenter.shared.messageNotification("_warning_", description: "_warning_owncloud_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorInternalError, priority: .max) } else if versionMajor <= NCGlobal.shared.nextcloud_unsupported_version { @@ -141,32 +141,32 @@ class NCService: NSObject { } } } - + private func requestServerCapabilities() { - + if appDelegate.account == "" { return } - - NCCommunication.shared.getCapabilities(queue: NCCommunicationCommon.shared.backgroundQueue) { (account, data, errorCode, errorDescription) in - + + NCCommunication.shared.getCapabilities(queue: NCCommunicationCommon.shared.backgroundQueue) { account, data, errorCode, errorDescription in + if errorCode == 0 && data != nil { - + NCManageDatabase.shared.addCapabilitiesJSon(data!, account: account) - + let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesVersionMajor) - + // Setup communication if serverVersionMajor > 0 { NCCommunicationCommon.shared.setup(nextcloudVersion: serverVersionMajor) } NCCommunicationCommon.shared.setup(webDav: NCUtilityFileSystem.shared.getWebDAV(account: account)) - + // Theming NCBrandColor.shared.settingThemingColor(account: account) - + // File Sharing let isFilesSharingEnabled = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingApiEnabled, exists: false) if isFilesSharingEnabled { - NCCommunication.shared.readShares(parameters: NCCShareParameter(), queue: NCCommunicationCommon.shared.backgroundQueue) { (account, shares, errorCode, ErrorDescription) in + NCCommunication.shared.readShares(parameters: NCCShareParameter(), queue: NCCommunicationCommon.shared.backgroundQueue) { account, shares, errorCode, errorDescription in if errorCode == 0 { NCManageDatabase.shared.deleteTableShare(account: account) if shares != nil { @@ -174,33 +174,33 @@ class NCService: NSObject { } self.appDelegate.shares = NCManageDatabase.shared.getTableShares(account: account) } else { - NCContentPresenter.shared.messageNotification("_share_", description: ErrorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) + NCContentPresenter.shared.messageNotification("_share_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } } } - + let comments = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFilesComments, exists: false) let activity = NCManageDatabase.shared.getCapabilitiesServerArray(account: account, elements: NCElementsJSON.shared.capabilitiesActivity) - + if !isFilesSharingEnabled && !comments && activity == nil { self.appDelegate.disableSharesView = true } else { self.appDelegate.disableSharesView = false } - + // Text direct editor detail if serverVersionMajor >= NCGlobal.shared.nextcloudVersion18 { - NCCommunication.shared.NCTextObtainEditorDetails(queue: NCCommunicationCommon.shared.backgroundQueue) { (account, editors, creators, errorCode, errorMessage) in + NCCommunication.shared.NCTextObtainEditorDetails(queue: NCCommunicationCommon.shared.backgroundQueue) { account, editors, creators, errorCode, _ in if errorCode == 0 && account == self.appDelegate.account { NCManageDatabase.shared.addDirectEditing(account: account, editors: editors, creators: creators) } } } - + // External file Server let isExternalSitesServerEnabled = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesExternalSitesExists, exists: true) - if (isExternalSitesServerEnabled) { - NCCommunication.shared.getExternalSite(queue: NCCommunicationCommon.shared.backgroundQueue) { (account, externalSites, errorCode, errorDescription) in + if isExternalSitesServerEnabled { + NCCommunication.shared.getExternalSite(queue: NCCommunicationCommon.shared.backgroundQueue) { account, externalSites, errorCode, _ in if errorCode == 0 && account == self.appDelegate.account { NCManageDatabase.shared.deleteExternalSites(account: account) for externalSite in externalSites { @@ -208,15 +208,15 @@ class NCService: NSObject { } } } - + } else { NCManageDatabase.shared.deleteExternalSites(account: account) } - + // User Status let userStatus = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesUserStatusEnabled, exists: false) if userStatus { - NCCommunication.shared.getUserStatus(queue: NCCommunicationCommon.shared.backgroundQueue) { (account, clearAt, icon, message, messageId, messageIsPredefined, status, statusIsUserDefined, userId, errorCode, errorDescription) in + NCCommunication.shared.getUserStatus(queue: NCCommunicationCommon.shared.backgroundQueue) { account, clearAt, icon, message, messageId, messageIsPredefined, status, statusIsUserDefined, userId, errorCode, _ in if errorCode == 0 && account == self.appDelegate.account && userId == self.appDelegate.userId { NCManageDatabase.shared.setAccountUserStatus(userStatusClearAt: clearAt, userStatusIcon: icon, userStatusMessage: message, userStatusMessageId: messageId, userStatusMessageIsPredefined: messageIsPredefined, userStatusStatus: status, userStatusStatusIsUserDefined: statusIsUserDefined, account: account) } @@ -226,14 +226,14 @@ class NCService: NSObject { // Added UTI for Collabora if let richdocumentsMimetypes = NCManageDatabase.shared.getCapabilitiesServerArray(account: account, elements: NCElementsJSON.shared.capabilitiesRichdocumentsMimetypes) { for mimeType in richdocumentsMimetypes { - NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: mimeType, classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorCollabora, iconName: NCCommunicationCommon.typeIconFile.document.rawValue, name: "document") + NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: mimeType, classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: NCGlobal.shared.editorCollabora, iconName: NCCommunicationCommon.typeIconFile.document.rawValue, name: "document") } } - + // Added UTI for ONLYOFFICE & Text if let directEditingCreators = NCManageDatabase.shared.getDirectEditingCreators(account: account) { for directEditing in directEditingCreators { - NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: directEditing.mimetype, classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: directEditing.editor, iconName: NCCommunicationCommon.typeIconFile.document.rawValue, name: "document") + NCCommunicationCommon.shared.addInternalTypeIdentifier(typeIdentifier: directEditing.mimetype, classFile: NCCommunicationCommon.typeClassFile.document.rawValue, editor: directEditing.editor, iconName: NCCommunicationCommon.typeIconFile.document.rawValue, name: "document") } } @@ -242,23 +242,23 @@ class NCService: NSObject { // if (isHandwerkcloudEnabled) { // self.requestHC() // } - + } else if errorCode != 0 { - + NCBrandColor.shared.settingThemingColor(account: account) - + if errorCode == 401 || errorCode == 403 { NCNetworkingCheckRemoteUser.shared.checkRemoteUser(account: account, errorCode: errorCode, errorDescription: errorDescription) } - + } else { NCBrandColor.shared.settingThemingColor(account: account) } } } - + @objc func synchronizeOffline(account: String) { - + // Synchronize Offline Directory if let directories = NCManageDatabase.shared.getTablesDirectory(predicate: NSPredicate(format: "account == %@ AND offline == true", account), sorted: "serverUrl", ascending: true) { for directory: tableDirectory in directories { @@ -268,7 +268,7 @@ class NCService: NSObject { NCOperationQueue.shared.synchronizationMetadata(metadata, selector: NCGlobal.shared.selectorDownloadFile) } } - + // Synchronize Offline Files let files = NCManageDatabase.shared.getTableLocalFiles(predicate: NSPredicate(format: "account == %@ AND offline == true", account), sorted: "fileName", ascending: true) for file: tableLocalFile in files { @@ -278,9 +278,9 @@ class NCService: NSObject { NCOperationQueue.shared.synchronizationMetadata(metadata, selector: NCGlobal.shared.selectorDownloadFile) } } - - //MARK: - Thirt Part - + + // MARK: - Thirt Part + private func requestHC() { } diff --git a/iOSClient/Notification/NCNotification.swift b/iOSClient/Notification/NCNotification.swift index 06a94508a..bbe9eb8a1 100644 --- a/iOSClient/Notification/NCNotification.swift +++ b/iOSClient/Notification/NCNotification.swift @@ -27,7 +27,7 @@ import NCCommunication import SwiftyJSON class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmptyDataSetDelegate { - + let appDelegate = UIApplication.shared.delegate as! AppDelegate var notifications: [NCCommunicationNotifications] = [] var emptyDataSet: NCEmptyDataSet? @@ -36,7 +36,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty override func viewDidLoad() { super.viewDidLoad() - + title = NSLocalizedString("_notification_", comment: "") view.backgroundColor = NCBrandColor.shared.systemBackground @@ -45,91 +45,91 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty tableView.estimatedRowHeight = 50.0 tableView.allowsSelection = false tableView.backgroundColor = NCBrandColor.shared.systemBackground - + // Empty let offset = (self.navigationController?.navigationBar.bounds.height ?? 0) - 20 - emptyDataSet = NCEmptyDataSet.init(view: tableView, offset: -offset, delegate: self) - + emptyDataSet = NCEmptyDataSet(view: tableView, offset: -offset, delegate: self) + NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil) - + changeTheming() } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + appDelegate.activeViewController = self - + // NotificationCenter.default.addObserver(self, selector: #selector(initialize), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil) } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + getNetwokingNotification() } - + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil) } - + @objc func viewClose() { self.dismiss(animated: true, completion: nil) } - + // MARK: - NotificationCenter @objc func initialize() { getNetwokingNotification() } - + @objc func changeTheming() { tableView.reloadData() } - + // MARK: - Empty - + func emptyDataSetView(_ view: NCEmptyView) { - - view.emptyImage.image = UIImage.init(named: "bell")?.image(color: .gray, size: UIScreen.main.bounds.width) + + view.emptyImage.image = UIImage(named: "bell")?.image(color: .gray, size: UIScreen.main.bounds.width) view.emptyTitle.text = NSLocalizedString("_no_notification_", comment: "") view.emptyDescription.text = "" } - + // MARK: - Table @objc func reloadDatasource() { self.tableView.reloadData() } - + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { emptyDataSet?.numberOfItemsInSection(notifications.count, section: section) return notifications.count } - + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = self.tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! NCNotificationCell cell.delegate = self - + let notification = notifications[indexPath.row] let urlIcon = URL(string: notification.icon) var image: UIImage? - + if let urlIcon = urlIcon { let pathFileName = String(CCUtility.getDirectoryUserData()) + "/" + urlIcon.deletingPathExtension().lastPathComponent + ".png" image = UIImage(contentsOfFile: pathFileName) } - + if let image = image { cell.icon.image = image.imageColor(NCBrandColor.shared.brandElement) } else { cell.icon.image = NCUtility.shared.loadImage(named: "bell", color: NCBrandColor.shared.brandElement) } - + // Avatar cell.avatar.isHidden = true cell.avatarLeadingMargin.constant = 10 @@ -149,7 +149,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty NCOperationQueue.shared.downloadAvatar(user: user, dispalyName: json["user"]?["name"].string, fileName: fileName, cell: cell, view: tableView) } } - + cell.date.text = DateFormatter.localizedString(from: notification.date as Date, dateStyle: .medium, timeStyle: .medium) cell.notification = notification cell.date.text = CCUtility.dateDiff(notification.date as Date) @@ -182,24 +182,24 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty let jsonActions = JSON(actions).array { if jsonActions.count == 1 { let action = jsonActions[0] - + cell.primary.isEnabled = true cell.primary.isHidden = false cell.primary.setTitle(action["label"].stringValue, for: .normal) - + } else if jsonActions.count == 2 { - + cell.primary.isEnabled = true cell.primary.isHidden = false - + cell.secondary.isEnabled = true cell.secondary.isHidden = false - + for action in jsonActions { - + let label = action["label"].stringValue let primary = action["primary"].boolValue - + if primary { cell.primary.setTitle(label, for: .normal) } else { @@ -213,7 +213,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty cell.primaryWidth.constant = buttonWidth cell.secondaryWidth.constant = buttonWidth } - + return cell } @@ -228,9 +228,9 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty .firstIndex(where: { $0.idNotification == notification.idNotification }) { self.notifications.remove(at: index) } - + self.reloadDatasource() - + } else if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } else { @@ -241,7 +241,8 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty func tapAction(with notification: NCCommunicationNotifications, label: String) { if notification.app == "spreed", - let talkUrl = URL(string: "nextcloudtalk://open-conversation?server=\(appDelegate.urlBase)&user=\(appDelegate.userId)&withRoomToken=\(notification.objectId)"), + let roomToken = notification.objectId.split(separator: "/").first, + let talkUrl = URL(string: "nextcloudtalk://open-conversation?server=\(appDelegate.urlBase)&user=\(appDelegate.userId)&withRoomToken=\(roomToken)"), UIApplication.shared.canOpenURL(talkUrl) { UIApplication.shared.open(talkUrl) } else if let actions = notification.actions, @@ -272,30 +273,30 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty } } // else: Action not found } - + // MARK: - Load notification networking - + func getNetwokingNotification() { - + NCUtility.shared.startActivityIndicator(backgroundView: self.navigationController?.view, blurEffect: true) - NCCommunication.shared.getNotifications() { (account, notifications, errorCode, errorDescription) in - + NCCommunication.shared.getNotifications { account, notifications, errorCode, _ in + if errorCode == 0 && account == self.appDelegate.account { - + self.notifications.removeAll() let sortedListOfNotifications = (notifications! as NSArray).sortedArray(using: [NSSortDescriptor(key: "date", ascending: false)]) - + for notification in sortedListOfNotifications { if let icon = (notification as! NCCommunicationNotifications).icon { - NCUtility.shared.convertSVGtoPNGWriteToUserData(svgUrlString: icon, fileName: nil, width: 25, rewrite: false, account: self.appDelegate.account, closure: { (imageNamePath) in }) - } + NCUtility.shared.convertSVGtoPNGWriteToUserData(svgUrlString: icon, fileName: nil, width: 25, rewrite: false, account: self.appDelegate.account, closure: { _ in }) + } self.notifications.append(notification as! NCCommunicationNotifications) } - + self.reloadDatasource() } - + NCUtility.shared.stopActivityIndicator() } } @@ -304,9 +305,9 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty // MARK: - class NCNotificationCell: UITableViewCell, NCCellProtocol { - - @IBOutlet weak var icon : UIImageView! - @IBOutlet weak var avatar : UIImageView! + + @IBOutlet weak var icon: UIImageView! + @IBOutlet weak var avatar: UIImageView! @IBOutlet weak var date: UILabel! @IBOutlet weak var subject: UILabel! @IBOutlet weak var message: UILabel! @@ -316,13 +317,13 @@ class NCNotificationCell: UITableViewCell, NCCellProtocol { @IBOutlet weak var avatarLeadingMargin: NSLayoutConstraint! @IBOutlet weak var primaryWidth: NSLayoutConstraint! @IBOutlet weak var secondaryWidth: NSLayoutConstraint! - + private var user = "" - var delegate: NCNotificationCellDelegate? + weak var delegate: NCNotificationCellDelegate? var notification: NCCommunicationNotifications? - - var filePreviewImageView : UIImageView? { + + var filePreviewImageView: UIImageView? { get { return nil } @@ -345,16 +346,16 @@ class NCNotificationCell: UITableViewCell, NCCellProtocol { user = newValue ?? "" } } - + override func awakeFromNib() { super.awakeFromNib() } - + @IBAction func touchUpInsideRemove(_ sender: Any) { guard let notification = notification else { return } delegate?.tapRemove(with: notification) } - + @IBAction func touchUpInsidePrimary(_ sender: Any) { guard let notification = notification, let button = sender as? UIButton, @@ -362,7 +363,7 @@ class NCNotificationCell: UITableViewCell, NCCellProtocol { else { return } delegate?.tapAction(with: notification, label: label) } - + @IBAction func touchUpInsideSecondary(_ sender: Any) { guard let notification = notification, let button = sender as? UIButton, @@ -372,7 +373,7 @@ class NCNotificationCell: UITableViewCell, NCCellProtocol { } } -protocol NCNotificationCellDelegate { +protocol NCNotificationCellDelegate: AnyObject { func tapRemove(with notification: NCCommunicationNotifications) func tapAction(with notification: NCCommunicationNotifications, label: String) } diff --git a/iOSClient/Offline/NCOffline.swift b/iOSClient/Offline/NCOffline.swift index ab9f501e9..1baaddc2b 100644 --- a/iOSClient/Offline/NCOffline.swift +++ b/iOSClient/Offline/NCOffline.swift @@ -24,80 +24,80 @@ import UIKit import NCCommunication -class NCOffline: NCCollectionViewCommon { - +class NCOffline: NCCollectionViewCommon { + // MARK: - View Life Cycle required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - + titleCurrentFolder = NSLocalizedString("_manage_file_offline_", comment: "") layoutKey = NCGlobal.shared.layoutViewOffline enableSearchBar = true - emptyImage = UIImage.init(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width) + emptyImage = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width) emptyTitle = "_files_no_files_" emptyDescription = "_tutorial_offline_view_" } - + // MARK: - DataSource + NC Endpoint override func reloadDataSource() { super.reloadDataSource() - + DispatchQueue.global().async { - + var ocIds: [String] = [] - + if !self.isSearching { - + if self.serverUrl == "" { - + if let directories = NCManageDatabase.shared.getTablesDirectory(predicate: NSPredicate(format: "account == %@ AND offline == true", self.appDelegate.account), sorted: "serverUrl", ascending: true) { for directory: tableDirectory in directories { ocIds.append(directory.ocId) } } - + let files = NCManageDatabase.shared.getTableLocalFiles(predicate: NSPredicate(format: "account == %@ AND offline == true", self.appDelegate.account), sorted: "fileName", ascending: true) for file: tableLocalFile in files { ocIds.append(file.ocId) } - + self.metadatasSource = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND ocId IN %@", self.appDelegate.account, ocIds)) - + } else { - + self.metadatasSource = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl)) } } - - self.dataSource = NCDataSource.init(metadatasSource: self.metadatasSource, sort: self.layoutForView?.sort, ascending: self.layoutForView?.ascending, directoryOnTop: self.layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) - + + self.dataSource = NCDataSource(metadatasSource: self.metadatasSource, sort: self.layoutForView?.sort, ascending: self.layoutForView?.ascending, directoryOnTop: self.layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) + DispatchQueue.main.async { self.refreshControl.endRefreshing() self.collectionView.reloadData() } } } - + override func reloadDataSourceNetwork(forced: Bool = false) { super.reloadDataSourceNetwork(forced: forced) - + if isSearching { networkSearch() return } - + if serverUrl == "" { - + self.reloadDataSource() - + } else { - + isReloadDataSourceNetworkInProgress = true collectionView?.reloadData() - - networkReadFolder(forced: forced) { (tableDirectory, metadatas, metadatasUpdate, metadatasDelete, errorCode, errorDescription) in + + networkReadFolder(forced: forced) { tableDirectory, metadatas, metadatasUpdate, metadatasDelete, errorCode, _ in if errorCode == 0 { for metadata in metadatas ?? [] { if !metadata.directory { @@ -107,7 +107,7 @@ class NCOffline: NCCollectionViewCommon { } } } - + DispatchQueue.main.async { self.refreshControl.endRefreshing() self.isReloadDataSourceNetworkInProgress = false diff --git a/iOSClient/Recent/NCRecent.swift b/iOSClient/Recent/NCRecent.swift index b8ef71215..f85d2370d 100644 --- a/iOSClient/Recent/NCRecent.swift +++ b/iOSClient/Recent/NCRecent.swift @@ -24,52 +24,52 @@ import UIKit import NCCommunication -class NCRecent: NCCollectionViewCommon { - +class NCRecent: NCCollectionViewCommon { + // MARK: - View Life Cycle required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - + titleCurrentFolder = NSLocalizedString("_recent_", comment: "") layoutKey = NCGlobal.shared.layoutViewRecent enableSearchBar = false - emptyImage = UIImage.init(named: "recent")?.image(color: .gray, size: UIScreen.main.bounds.width) + emptyImage = UIImage(named: "recent")?.image(color: .gray, size: UIScreen.main.bounds.width) emptyTitle = "_files_no_files_" emptyDescription = "" } - + // MARK: - Collection View - + override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.width, height: 0) } - + // MARK: - DataSource + NC Endpoint - + override func reloadDataSource() { super.reloadDataSource() - + DispatchQueue.global().async { - + self.metadatasSource = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "account == %@", self.appDelegate.account), page: 1, limit: 100, sorted: "date", ascending: false) - self.dataSource = NCDataSource.init(metadatasSource: self.metadatasSource, directoryOnTop: false, favoriteOnTop: false) - + self.dataSource = NCDataSource(metadatasSource: self.metadatasSource, directoryOnTop: false, favoriteOnTop: false) + DispatchQueue.main.async { self.refreshControl.endRefreshing() self.collectionView.reloadData() } } } - + override func reloadDataSourceNetwork(forced: Bool = false) { super.reloadDataSourceNetwork(forced: forced) - + if isSearching { networkSearch() return } - + let requestBodyRecent = """ <?xml version=\"1.0\"?> @@ -131,21 +131,21 @@ class NCRecent: NCCollectionViewCommon { </d:basicsearch> </d:searchrequest> """ - + let dateFormatter = DateFormatter() - dateFormatter.locale = Locale.init(identifier: "en_US_POSIX") + dateFormatter.locale = Locale(identifier: "en_US_POSIX") dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ" let lessDateString = dateFormatter.string(from: Date()) let requestBody = String(format: requestBodyRecent, "/files/"+appDelegate.userId, lessDateString) - + isReloadDataSourceNetworkInProgress = true collectionView?.reloadData() - - NCCommunication.shared.searchBodyRequest(serverUrl: appDelegate.urlBase, requestBody: requestBody, showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { (account, files, errorCode, errorDescription) in - + + NCCommunication.shared.searchBodyRequest(serverUrl: appDelegate.urlBase, requestBody: requestBody, showHiddenFiles: CCUtility.getShowHiddenFiles(), queue: NCCommunicationCommon.shared.backgroundQueue) { account, files, errorCode, _ in + if errorCode == 0 { - NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: false, account: account) { (metadataFolder, metadatasFolder, metadatas) in - + NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: false, account: account) { _, metadatasFolder, metadatas in + // Update sub directories for metadata in metadatasFolder { let serverUrl = metadata.serverUrl + "/" + metadata.fileName @@ -153,7 +153,7 @@ class NCRecent: NCCollectionViewCommon { } // Add metadatas NCManageDatabase.shared.addMetadatas(metadatas) - + self.reloadDataSource() } } else { @@ -161,7 +161,7 @@ class NCRecent: NCCollectionViewCommon { self.collectionView?.reloadData() } } - + DispatchQueue.main.async { self.refreshControl.endRefreshing() self.isReloadDataSourceNetworkInProgress = false @@ -169,4 +169,3 @@ class NCRecent: NCCollectionViewCommon { } } } - diff --git a/iOSClient/Rename file/NCRenameFile.swift b/iOSClient/Rename file/NCRenameFile.swift index ec22ae739..017c15d3c 100644 --- a/iOSClient/Rename file/NCRenameFile.swift +++ b/iOSClient/Rename file/NCRenameFile.swift @@ -24,7 +24,7 @@ import UIKit import NCCommunication -public protocol NCRenameFileDelegate { +public protocol NCRenameFileDelegate: AnyObject { func rename(fileName: String, fileNameNew: String) } @@ -46,62 +46,62 @@ class NCRenameFile: UIViewController, UITextFieldDelegate { let width: CGFloat = 300 let height: CGFloat = 310 - + var metadata: tableMetadata? var fileName: String? var imagePreview: UIImage? var disableChangeExt: Bool = false - var delegate: NCRenameFileDelegate? - + weak var delegate: NCRenameFileDelegate? + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + if let metadata = self.metadata { - + if metadata.directory { titleLabel.text = NSLocalizedString("_rename_folder_", comment: "") } else { titleLabel.text = NSLocalizedString("_rename_file_", comment: "") } - + fileNameWithoutExt.text = (metadata.fileNameView as NSString).deletingPathExtension fileNameWithoutExt.delegate = self fileNameWithoutExt.becomeFirstResponder() - + ext.text = (metadata.fileNameView as NSString).pathExtension ext.delegate = self if disableChangeExt { ext.isEnabled = false ext.textColor = .lightGray } - + previewFile.image = imagePreview previewFile.layer.cornerRadius = 10 previewFile.layer.masksToBounds = true if metadata.directory { - + if imagePreview == nil { previewFile.image = NCBrandColor.cacheImages.folder } - + ext.isHidden = true point.isHidden = true fileNameWithoutExtTrailingContraint.constant = 20 - + } else { - + if imagePreview == nil { previewFile.image = NCBrandColor.cacheImages.file } - + fileNameWithoutExtTrailingContraint.constant = 90 } - + } else if let fileName = self.fileName { - + titleLabel.text = NSLocalizedString("_rename_file_", comment: "") fileNameWithoutExt.text = (fileName as NSString).deletingPathExtension @@ -111,7 +111,7 @@ class NCRenameFile: UIViewController, UITextFieldDelegate { ext.text = (fileName as NSString).pathExtension ext.delegate = self - + if imagePreview == nil { previewFile.image = NCBrandColor.cacheImages.file } else { @@ -120,96 +120,96 @@ class NCRenameFile: UIViewController, UITextFieldDelegate { previewFile.layer.cornerRadius = 10 previewFile.layer.masksToBounds = true } - + cancelButton.setTitle(NSLocalizedString("_cancel_", comment: ""), for: .normal) renameButton.setTitle(NSLocalizedString("_rename_", comment: ""), for: .normal) } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + if metadata == nil && fileName == nil { dismiss(animated: true) } - + fileNameWithoutExt.selectAll(nil) } - + func textFieldShouldReturn(_ textField: UITextField) -> Bool { - + textField.resignFirstResponder() rename(textField) return true } - + // MARK: - Action - + @IBAction func cancel(_ sender: Any) { - + dismiss(animated: true) } - + @IBAction func rename(_ sender: Any) { var fileNameWithoutExtNew = "" var extNew = "" var fileNameNew = "" - + if let metadata = self.metadata { - + if fileNameWithoutExt.text == nil || fileNameWithoutExt.text?.count == 0 { self.fileNameWithoutExt.text = (metadata.fileNameView as NSString).deletingPathExtension return } else { fileNameWithoutExtNew = fileNameWithoutExt.text! } - + if metadata.directory { - + fileNameNew = fileNameWithoutExtNew renameMetadata(metadata, fileNameNew: fileNameNew) - + } else { - + if ext.text == nil || ext.text?.count == 0 { self.ext.text = (metadata.fileNameView as NSString).pathExtension return } else { extNew = ext.text! } - + if extNew != metadata.ext { - + let message = String(format: NSLocalizedString("_rename_ext_message_", comment: ""), extNew, metadata.ext) let alertController = UIAlertController(title: NSLocalizedString("_rename_ext_title_", comment: ""), message: message, preferredStyle: .alert) - + var title = NSLocalizedString("_use_", comment: "") + " ." + extNew - alertController.addAction(UIAlertAction(title: title, style: .default, handler: { action in - + alertController.addAction(UIAlertAction(title: title, style: .default, handler: { _ in + fileNameNew = fileNameWithoutExtNew + "." + extNew self.renameMetadata(metadata, fileNameNew: fileNameNew) })) - + title = NSLocalizedString("_keep_", comment: "") + " ." + metadata.ext - alertController.addAction(UIAlertAction(title: title, style: .default, handler: { action in + alertController.addAction(UIAlertAction(title: title, style: .default, handler: { _ in self.ext.text = (metadata.fileNameView as NSString).pathExtension })) - + self.present(alertController, animated: true) - + } else { - + fileNameNew = fileNameWithoutExtNew + "." + extNew renameMetadata(metadata, fileNameNew: fileNameNew) } } - + } else if let fileName = self.fileName { - + if fileNameWithoutExt.text == nil || fileNameWithoutExt.text?.count == 0 { fileNameWithoutExt.text = (fileName as NSString).deletingPathExtension return @@ -217,29 +217,29 @@ class NCRenameFile: UIViewController, UITextFieldDelegate { ext.text = (fileName as NSString).pathExtension return } - + fileNameNew = (fileNameWithoutExt.text ?? "") + "." + (ext.text ?? "") self.delegate?.rename(fileName: fileName, fileNameNew: fileNameNew) self.dismiss(animated: true) } } - + // MARK: - Networking func renameMetadata(_ metadata: tableMetadata, fileNameNew: String) { - + NCUtility.shared.startActivityIndicator(backgroundView: nil, blurEffect: true) - - NCNetworking.shared.renameMetadata(metadata, fileNameNew: fileNameNew, viewController: self) { (errorCode, errorDescription) in - + + NCNetworking.shared.renameMetadata(metadata, fileNameNew: fileNameNew, viewController: self) { errorCode, errorDescription in + NCUtility.shared.stopActivityIndicator() - + if errorCode == 0 { - + self.dismiss(animated: true) - + } else { - + NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } } diff --git a/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift b/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift index d63556a71..ee58eb7d2 100644 --- a/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift +++ b/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift @@ -28,81 +28,81 @@ import NCCommunication let appDelegate = UIApplication.shared.delegate as! AppDelegate - @objc func createViewerNextcloudText(serverUrl: String,viewController: UIViewController) { - + @objc func createViewerNextcloudText(serverUrl: String, viewController: UIViewController) { + if !NCCommunication.shared.isNetworkReachable() { NCContentPresenter.shared.messageNotification("_error_", description: "_go_online_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorInternalError) - return; + return } - + guard let directEditingCreator = NCManageDatabase.shared.getDirectEditingCreators(predicate: NSPredicate(format: "account == %@ AND editor == 'text'", appDelegate.account))?.first else { return } - + NCUtility.shared.startActivityIndicator(backgroundView: viewController.view, blurEffect: true) - + let fileNamePath = CCUtility.returnFileNamePath(fromFileName: NCGlobal.shared.fileNameRichWorkspace, serverUrl: serverUrl, urlBase: appDelegate.urlBase, account: appDelegate.account)! - NCCommunication.shared.NCTextCreateFile(fileNamePath: fileNamePath, editorId: directEditingCreator.editor, creatorId: directEditingCreator.identifier ,templateId: "") { (account, url, errorCode, errorMessage) in - + NCCommunication.shared.NCTextCreateFile(fileNamePath: fileNamePath, editorId: directEditingCreator.editor, creatorId: directEditingCreator.identifier, templateId: "") { account, url, errorCode, errorMessage in + NCUtility.shared.stopActivityIndicator() - + if errorCode == 0 && account == self.appDelegate.account { - - if let viewerRichWorkspaceWebView = UIStoryboard.init(name: "NCViewerRichWorkspace", bundle: nil).instantiateViewController(withIdentifier: "NCViewerRichWorkspaceWebView") as? NCViewerRichWorkspaceWebView { - + + if let viewerRichWorkspaceWebView = UIStoryboard(name: "NCViewerRichWorkspace", bundle: nil).instantiateViewController(withIdentifier: "NCViewerRichWorkspaceWebView") as? NCViewerRichWorkspaceWebView { + viewerRichWorkspaceWebView.url = url! viewerRichWorkspaceWebView.presentationController?.delegate = viewController as? UIAdaptivePresentationControllerDelegate - + viewController.present(viewerRichWorkspaceWebView, animated: true, completion: nil) } - + } else if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorMessage, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: errorCode) } } } - + @objc func openViewerNextcloudText(serverUrl: String, viewController: UIViewController) { - + if !NCCommunication.shared.isNetworkReachable() { - + NCContentPresenter.shared.messageNotification("_error_", description: "_go_online_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorInternalError) - return; + return } - + if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView LIKE[c] %@", appDelegate.account, serverUrl, NCGlobal.shared.fileNameRichWorkspace.lowercased())) { - + if metadata.url == "" { - + NCUtility.shared.startActivityIndicator(backgroundView: viewController.view, blurEffect: true) - + let fileNamePath = CCUtility.returnFileNamePath(fromFileName: metadata.fileName, serverUrl: metadata.serverUrl, urlBase: appDelegate.urlBase, account: appDelegate.account)! - NCCommunication.shared.NCTextOpenFile(fileNamePath: fileNamePath, editor: "text") { (account, url, errorCode, errorMessage) in - + NCCommunication.shared.NCTextOpenFile(fileNamePath: fileNamePath, editor: "text") { account, url, errorCode, errorMessage in + NCUtility.shared.stopActivityIndicator() - + if errorCode == 0 && account == self.appDelegate.account { - - if let viewerRichWorkspaceWebView = UIStoryboard.init(name: "NCViewerRichWorkspace", bundle: nil).instantiateViewController(withIdentifier: "NCViewerRichWorkspaceWebView") as? NCViewerRichWorkspaceWebView { - + + if let viewerRichWorkspaceWebView = UIStoryboard(name: "NCViewerRichWorkspace", bundle: nil).instantiateViewController(withIdentifier: "NCViewerRichWorkspaceWebView") as? NCViewerRichWorkspaceWebView { + viewerRichWorkspaceWebView.url = url! viewerRichWorkspaceWebView.metadata = metadata viewerRichWorkspaceWebView.presentationController?.delegate = viewController as? UIAdaptivePresentationControllerDelegate - + viewController.present(viewerRichWorkspaceWebView, animated: true, completion: nil) } - + } else if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorMessage, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: errorCode) } } - + } else { - - if let viewerRichWorkspaceWebView = UIStoryboard.init(name: "NCViewerRichWorkspace", bundle: nil).instantiateViewController(withIdentifier: "NCViewerRichWorkspaceWebView") as? NCViewerRichWorkspaceWebView { - + + if let viewerRichWorkspaceWebView = UIStoryboard(name: "NCViewerRichWorkspace", bundle: nil).instantiateViewController(withIdentifier: "NCViewerRichWorkspaceWebView") as? NCViewerRichWorkspaceWebView { + viewerRichWorkspaceWebView.url = metadata.url viewerRichWorkspaceWebView.metadata = metadata viewerRichWorkspaceWebView.presentationController?.delegate = viewController as? UIAdaptivePresentationControllerDelegate - + viewController.present(viewerRichWorkspaceWebView, animated: true, completion: nil) } } diff --git a/iOSClient/RichWorkspace/NCViewerRichWorkspace.swift b/iOSClient/RichWorkspace/NCViewerRichWorkspace.swift index 210f74854..7ba567793 100644 --- a/iOSClient/RichWorkspace/NCViewerRichWorkspace.swift +++ b/iOSClient/RichWorkspace/NCViewerRichWorkspace.swift @@ -28,7 +28,7 @@ import MarkdownKit @objc class NCViewerRichWorkspace: UIViewController, UIAdaptivePresentationControllerDelegate { @IBOutlet weak var textView: UITextView! - + private let appDelegate = UIApplication.shared.delegate as! AppDelegate private let richWorkspaceCommon = NCRichWorkspaceCommon() private var markdownParser = MarkdownParser() @@ -36,32 +36,32 @@ import MarkdownKit @objc public var richWorkspaceText: String = "" @objc public var serverUrl: String = "" - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + view.backgroundColor = NCBrandColor.shared.systemBackground presentationController?.delegate = self - + let closeItem = UIBarButtonItem(title: NSLocalizedString("_back_", comment: ""), style: .plain, target: self, action: #selector(closeItemTapped(_:))) self.navigationItem.leftBarButtonItem = closeItem - + let editItem = UIBarButtonItem(image: UIImage(named: "actionSheetModify"), style: UIBarButtonItem.Style.plain, target: self, action: #selector(editItemAction(_:))) self.navigationItem.rightBarButtonItem = editItem - + markdownParser = MarkdownParser(font: UIFont.systemFont(ofSize: 15), color: NCBrandColor.shared.label) markdownParser.header.font = UIFont.systemFont(ofSize: 25) textView.attributedText = markdownParser.parse(richWorkspaceText) textViewColor = NCBrandColor.shared.label } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - - NCNetworking.shared.readFile(serverUrlFileName: serverUrl, account: appDelegate.account) { (account, metadata, errorCode, errorDescription) in - + + NCNetworking.shared.readFile(serverUrlFileName: serverUrl, account: appDelegate.account) { account, metadata, errorCode, _ in + if errorCode == 0 && account == self.appDelegate.account { guard let metadata = metadata else { return } NCManageDatabase.shared.setDirectory(richWorkspace: metadata.richWorkspace, serverUrl: self.serverUrl, account: account) @@ -75,17 +75,17 @@ import MarkdownKit } } } - + public func presentationControllerWillDismiss(_ presentationController: UIPresentationController) { self.viewWillAppear(true) } - + @objc func closeItemTapped(_ sender: UIBarButtonItem) { self.dismiss(animated: false, completion: nil) } - + @IBAction func editItemAction(_ sender: Any) { - + richWorkspaceCommon.openViewerNextcloudText(serverUrl: serverUrl, viewController: self) } } diff --git a/iOSClient/RichWorkspace/NCViewerRichWorkspaceWebView.swift b/iOSClient/RichWorkspace/NCViewerRichWorkspaceWebView.swift index 699ec3874..9e9d5799e 100644 --- a/iOSClient/RichWorkspace/NCViewerRichWorkspaceWebView.swift +++ b/iOSClient/RichWorkspace/NCViewerRichWorkspaceWebView.swift @@ -25,11 +25,10 @@ import UIKit import WebKit class NCViewerRichWorkspaceWebView: UIViewController, WKNavigationDelegate, WKScriptMessageHandler { - + @IBOutlet weak var webView: WKWebView! @IBOutlet weak var webViewBottomConstraint: NSLayoutConstraint! - let appDelegate = UIApplication.shared.delegate as! AppDelegate @objc var metadata: tableMetadata? @objc var url: String = "" @@ -37,23 +36,23 @@ class NCViewerRichWorkspaceWebView: UIViewController, WKNavigationDelegate, WKSc override func viewDidLoad() { super.viewDidLoad() - - let userAgent : String = CCUtility.getUserAgent() - + + let userAgent: String = CCUtility.getUserAgent() + NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: UIResponder.keyboardDidShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) - + var request = URLRequest(url: URL(string: url)!) request.addValue("true", forHTTPHeaderField: "OCS-APIRequest") let language = NSLocale.preferredLanguages[0] as String request.addValue(language, forHTTPHeaderField: "Accept-Language") - + webView.configuration.userContentController.add(self, name: "DirectEditingMobileInterface") webView.navigationDelegate = self webView.customUserAgent = userAgent webView.load(request) } - + @objc func keyboardDidShow(notification: Notification) { let safeAreaInsetsBottom = UIApplication.shared.keyWindow!.safeAreaInsets.bottom guard let info = notification.userInfo else { return } @@ -61,67 +60,67 @@ class NCViewerRichWorkspaceWebView: UIViewController, WKNavigationDelegate, WKSc let keyboardFrame = frameInfo.cgRectValue webViewBottomConstraint.constant = keyboardFrame.size.height - safeAreaInsetsBottom } - + @objc func keyboardWillHide(notification: Notification) { webViewBottomConstraint.constant = 0 } - - //MARK: - + + // MARK: - public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - - if (message.name == "DirectEditingMobileInterface") { - + + if message.name == "DirectEditingMobileInterface" { + if message.body as? String == "close" { - + if #available(iOS 13.0, *) { self.presentationController?.delegate?.presentationControllerWillDismiss?(self.presentationController!) } - + dismiss(animated: true) { NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterCloseRichWorkspaceWebView, userInfo: nil) } } - + if message.body as? String == "share" { - if (metadata != nil) { - NCFunctionCenter.shared.openShare(ViewController: self, metadata: metadata!, indexPage: .sharing) + if metadata != nil { + NCFunctionCenter.shared.openShare(viewController: self, metadata: metadata!, indexPage: .sharing) } } - + if message.body as? String == "loading" { print("loading") } - + if message.body as? String == "loaded" { print("loaded") } - + if message.body as? String == "paste" { self.paste(self) } } } - - //MARK: - + + // MARK: - public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if let serverTrust = challenge.protectionSpace.serverTrust { completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust)) } else { - completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil); + completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil) } } - + public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - print("didStartProvisionalNavigation"); + print("didStartProvisionalNavigation") } - + public func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { - print("didReceiveServerRedirectForProvisionalNavigation"); + print("didReceiveServerRedirectForProvisionalNavigation") } - + public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - print("didFinish"); + print("didFinish") } } diff --git a/iOSClient/ScanDocument/ScanCell.swift b/iOSClient/ScanDocument/ScanCell.swift index 4d0a27844..560efc8d3 100755 --- a/iOSClient/ScanDocument/ScanCell.swift +++ b/iOSClient/ScanDocument/ScanCell.swift @@ -24,7 +24,7 @@ import UIKit class ScanCell: UICollectionViewCell { - + @IBOutlet weak var customImageView: UIImageView! @IBOutlet weak var customLabel: UILabel! @IBOutlet weak var delete: UIButton! diff --git a/iOSClient/ScanDocument/ScanCollectionView.swift b/iOSClient/ScanDocument/ScanCollectionView.swift index 52da3c215..ad96a50b4 100755 --- a/iOSClient/ScanDocument/ScanCollectionView.swift +++ b/iOSClient/ScanDocument/ScanCollectionView.swift @@ -25,17 +25,17 @@ import UIKit @available(iOS 13.0, *) class DragDropViewController: UIViewController { - - //Data Source for collectionViewSource + + // Data Source for collectionViewSource private var itemsSource: [String] = [] - - //Data Source for collectionViewDestination + + // Data Source for collectionViewDestination private var imagesDestination: [UIImage] = [] private var itemsDestination: [String] = [] - + private let appDelegate = UIApplication.shared.delegate as! AppDelegate - //MARK: Outlets + // MARK: Outlets @IBOutlet weak var collectionViewSource: UICollectionView! @IBOutlet weak var collectionViewDestination: UICollectionView! @IBOutlet weak var cancel: UIBarButtonItem! @@ -52,14 +52,14 @@ class DragDropViewController: UIViewController { case bn } private var filter: typeFilter = typeFilter.original - + override var canBecomeFirstResponder: Bool { return true } - + // MARK: - View Life Cycle - + override func viewDidLoad() { super.viewDidLoad() - + view.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground navigationItem.title = NSLocalizedString("_scanned_images_", comment: "") @@ -71,12 +71,12 @@ class DragDropViewController: UIViewController { collectionViewDestination.dragInteractionEnabled = true collectionViewDestination.dropDelegate = self collectionViewDestination.dragDelegate = self - collectionViewDestination.reorderingCadence = .fast //default value - .immediate + collectionViewDestination.reorderingCadence = .fast // default value - .immediate collectionViewDestination.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground cancel.title = NSLocalizedString("_cancel_", comment: "") save.title = NSLocalizedString("_save_", comment: "") - + labelTitlePDFzone.text = NSLocalizedString("_scan_label_document_zone_", comment: "") labelTitlePDFzone.backgroundColor = NCBrandColor.shared.systemGray6 labelTitlePDFzone.textColor = NCBrandColor.shared.label @@ -87,86 +87,85 @@ class DragDropViewController: UIViewController { add.setImage(UIImage(named: "plus")?.image(color: NCBrandColor.shared.label, size: 25), for: .normal) transferDown.setImage(UIImage(named: "transferDown")?.image(color: NCBrandColor.shared.label, size: 25), for: .normal) - + let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture(recognizer:))) collectionViewSource.addGestureRecognizer(longPressRecognizer) let longPressRecognizerPlus = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture(recognizer:))) add.addGestureRecognizer(longPressRecognizerPlus) - + collectionViewSource.reloadData() collectionViewDestination.reloadData() - + loadImage() } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - + add.setImage(UIImage(named: "plus")?.image(color: NCBrandColor.shared.label, size: 25), for: .normal) transferDown.setImage(UIImage(named: "transferDown")?.image(color: NCBrandColor.shared.label, size: 25), for: .normal) } - - //MARK: Button Action + + // MARK: Button Action @IBAction func cancelAction(sender: UIBarButtonItem) { self.dismiss(animated: true, completion: nil) } - + @IBAction func saveAction(sender: UIBarButtonItem) { - + if imagesDestination.count > 0 { - + var images: [UIImage] = [] let serverUrl = appDelegate.activeServerUrl for image in imagesDestination { images.append(filter(image: image)!) } - + // if let directory = CCUtility.getDirectoryScanDocuments() { // serverUrl = directory // } - - let formViewController = NCCreateFormUploadScanDocument.init(serverUrl: serverUrl, arrayImages: images) + + let formViewController = NCCreateFormUploadScanDocument(serverUrl: serverUrl, arrayImages: images) self.navigationController?.pushViewController(formViewController, animated: true) } } - + @IBAction func add(sender: UIButton) { - + NCCreateScanDocument.shared.openScannerDocument(viewController: self) } - + @IBAction func transferDown(sender: UIButton) { - + for fileName in itemsSource { - + if !itemsDestination.contains(fileName) { - + let fileNamePathAt = CCUtility.getDirectoryScan() + "/" + fileName - + guard let data = try? Data(contentsOf: URL(fileURLWithPath: fileNamePathAt)) else { return } guard let image = UIImage(data: data) else { return } - + imagesDestination.append(image) itemsDestination.append(fileName) } } - + // Save button if imagesDestination.count == 0 { save.isEnabled = false } else { save.isEnabled = true } - + collectionViewDestination.reloadData() } - + @IBAction func indexChanged(_ sender: AnyObject) { - - switch segmentControlFilter.selectedSegmentIndex - { + + switch segmentControlFilter.selectedSegmentIndex { case 0: filter = typeFilter.original case 1: @@ -176,12 +175,12 @@ class DragDropViewController: UIViewController { default: break } - + collectionViewDestination.reloadData() } - + func loadImage() { - + itemsSource.removeAll() do { @@ -195,11 +194,11 @@ class DragDropViewController: UIViewController { } catch { print(error.localizedDescription) } - + itemsSource = itemsSource.sorted() - + collectionViewSource.reloadData() - + // Save button if imagesDestination.count == 0 { save.isEnabled = false @@ -207,162 +206,161 @@ class DragDropViewController: UIViewController { save.isEnabled = true } } - - //MARK: Private Methods - + + // MARK: Private Methods + func filter(image: UIImage) -> UIImage? { - + var inputContrast: Double = 0 - + if filter == typeFilter.original { return image } - + if filter == typeFilter.grayScale { inputContrast = 1 } - + if filter == typeFilter.bn { inputContrast = 4 } - + let ciImage = CIImage(image: image)! let imageFilter = ciImage.applyingFilter("CIColorControls", parameters: ["inputSaturation": 0, "inputContrast": inputContrast]) - - let context:CIContext = CIContext.init(options: nil) - let cgImage:CGImage = context.createCGImage(imageFilter, from: imageFilter.extent)! - let image:UIImage = UIImage.init(cgImage: cgImage) + + let context: CIContext = CIContext(options: nil) + let cgImage: CGImage = context.createCGImage(imageFilter, from: imageFilter.extent)! + let image: UIImage = UIImage(cgImage: cgImage) return image } - + /// This method moves a cell from source indexPath to destination indexPath within the same collection view. It works for only 1 item. If multiple items selected, no reordering happens. /// /// - Parameters: /// - coordinator: coordinator obtained from performDropWith: UICollectionViewDropDelegate method /// - destinationIndexPath: indexpath of the collection view where the user drops the element /// - collectionView: collectionView in which reordering needs to be done. - + private func reorderItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView) { - + let items = coordinator.items - + if items.count == 1, let item = items.first, let sourceIndexPath = item.sourceIndexPath { - + var dIndexPath = destinationIndexPath - + if dIndexPath.row >= collectionView.numberOfItems(inSection: 0) { dIndexPath.row = collectionView.numberOfItems(inSection: 0) - 1 } - + collectionView.performBatchUpdates({ - + if collectionView === collectionViewDestination { - + imagesDestination.remove(at: sourceIndexPath.row) imagesDestination.insert(item.dragItem.localObject as! UIImage, at: dIndexPath.row) - + let fileName = itemsDestination[sourceIndexPath.row] itemsDestination.remove(at: sourceIndexPath.row) itemsDestination.insert(fileName, at: dIndexPath.row) - + } else { - + itemsSource.remove(at: sourceIndexPath.row) itemsSource.insert(item.dragItem.localObject as! String, at: dIndexPath.row) } - + collectionView.deleteItems(at: [sourceIndexPath]) collectionView.insertItems(at: [dIndexPath]) }) - + coordinator.drop(items.first!.dragItem, toItemAt: dIndexPath) } } - + /// This method copies a cell from source indexPath in 1st collection view to destination indexPath in 2nd collection view. It works for multiple items. /// /// - Parameters: /// - coordinator: coordinator obtained from performDropWith: UICollectionViewDropDelegate method /// - destinationIndexPath: indexpath of the collection view where the user drops the element /// - collectionView: collectionView in which reordering needs to be done. - - private func copyItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView) - { + + private func copyItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView) { collectionView.performBatchUpdates({ - + var indexPaths: [IndexPath] = [] - + for (index, item) in coordinator.items.enumerated() { - + let indexPath = IndexPath(row: destinationIndexPath.row + index, section: destinationIndexPath.section) - + if collectionView === collectionViewDestination { - + let fileName = item.dragItem.localObject as! String let fileNamePathAt = CCUtility.getDirectoryScan() + "/" + fileName - + guard let data = try? Data(contentsOf: URL(fileURLWithPath: fileNamePathAt)) else { return } guard let image = UIImage(data: data) else { return } - + imagesDestination.insert(image, at: indexPath.row) itemsDestination.insert(fileName, at: indexPath.row) - + } else { - + // NOT PERMITTED return } - + indexPaths.append(indexPath) } - + collectionView.insertItems(at: indexPaths) }) } - + // MARK: - UIGestureRecognizerv - Paste - + @objc func handleLongPressGesture(recognizer: UIGestureRecognizer) { - + if recognizer.state == UIGestureRecognizer.State.began { - + self.becomeFirstResponder() - + let pasteboard = UIPasteboard.general - + if let recognizerView = recognizer.view, let recognizerSuperView = recognizerView.superview, pasteboard.hasImages { - + UIMenuController.shared.menuItems = [UIMenuItem(title: "Paste", action: #selector(pasteImage))] UIMenuController.shared.setTargetRect(recognizerView.frame, in: recognizerSuperView) - UIMenuController.shared.setMenuVisible(true, animated:true) + UIMenuController.shared.setMenuVisible(true, animated: true) } } } - + override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { if action == #selector(pasteImage) { return true } return false } - + @objc func pasteImage() { - + let pasteboard = UIPasteboard.general - + if pasteboard.hasImages { - + let fileName = CCUtility.createFileName("scan.png", fileDate: Date(), fileType: PHAssetMediaType.image, keyFileName: NCGlobal.shared.keyFileNameMask, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: true)! let fileNamePath = CCUtility.getDirectoryScan() + "/" + fileName - + guard let image = pasteboard.image?.fixedOrientation() else { return } - + do { try image.pngData()?.write(to: NSURL.fileURL(withPath: fileNamePath), options: .atomic) } catch { @@ -377,79 +375,79 @@ class DragDropViewController: UIViewController { // MARK: - UICollectionViewDataSource Methods @available(iOS 13.0, *) -extension DragDropViewController : UICollectionViewDataSource { - +extension DragDropViewController: UICollectionViewDataSource { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - + return collectionView == collectionViewSource ? itemsSource.count : imagesDestination.count } - + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - + if collectionView == collectionViewSource { - + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell1", for: indexPath) as! ScanCell - + let fileNamePath = CCUtility.getDirectoryScan() + "/" + itemsSource[indexPath.row] - + guard let data = try? Data(contentsOf: URL(fileURLWithPath: fileNamePath)) else { return cell } - + guard var image = UIImage(data: data) else { return cell } - + let imageWidthInPixels = image.size.width * image.scale let imageHeightInPixels = image.size.height * image.scale - + // 72 DPI - if imageWidthInPixels > 595 || imageHeightInPixels > 842 { + if imageWidthInPixels > 595 || imageHeightInPixels > 842 { image = image.resizeImage(size: CGSize(width: 595, height: 842), isAspectRation: true) ?? image } - + cell.customImageView?.image = image cell.delete.action(for: .touchUpInside) { sender in - - let buttonPosition:CGPoint = (sender as! UIButton).convert(.zero, to: self.collectionViewSource) + + let buttonPosition: CGPoint = (sender as! UIButton).convert(.zero, to: self.collectionViewSource) if let indexPath = self.collectionViewSource.indexPathForItem(at: buttonPosition) { - + let fileNameAtPath = CCUtility.getDirectoryScan() + "/" + self.itemsSource[indexPath.row] CCUtility.removeFile(atPath: fileNameAtPath) self.itemsSource.remove(at: indexPath.row) - + self.collectionViewSource.reloadData() } } return cell - + } else { - + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell2", for: indexPath) as! ScanCell - + var image = imagesDestination[indexPath.row] - + let imageWidthInPixels = image.size.width * image.scale let imageHeightInPixels = image.size.height * image.scale - + // 72 DPI - if imageWidthInPixels > 595 || imageHeightInPixels > 842 { + if imageWidthInPixels > 595 || imageHeightInPixels > 842 { image = image.resizeImage(size: CGSize(width: 595, height: 842), isAspectRation: true) ?? image } - + cell.customImageView?.image = self.filter(image: image) cell.customLabel.text = NSLocalizedString("_scan_document_pdf_page_", comment: "") + " " + "\(indexPath.row+1)" cell.delete.action(for: .touchUpInside) { sender in - - let buttonPosition:CGPoint = (sender as! UIButton).convert(.zero, to: self.collectionViewDestination) + + let buttonPosition: CGPoint = (sender as! UIButton).convert(.zero, to: self.collectionViewDestination) if let indexPath = self.collectionViewDestination.indexPathForItem(at: buttonPosition) { - + self.imagesDestination.remove(at: indexPath.row) self.itemsDestination.remove(at: indexPath.row) - + self.collectionViewDestination.reloadData() - + // Save button if self.imagesDestination.count == 0 { self.save.isEnabled = false @@ -459,17 +457,17 @@ extension DragDropViewController : UICollectionViewDataSource { } } cell.rotate.action(for: .touchUpInside) { sender in - - let buttonPosition:CGPoint = (sender as! UIButton).convert(.zero, to: self.collectionViewDestination) + + let buttonPosition: CGPoint = (sender as! UIButton).convert(.zero, to: self.collectionViewDestination) if let indexPath = self.collectionViewDestination.indexPathForItem(at: buttonPosition) { - + let image = self.imagesDestination[indexPath.row] self.imagesDestination[indexPath.row] = image.rotate(radians: .pi/2)! - + self.collectionViewDestination.reloadData() } } - + return cell } } @@ -481,20 +479,20 @@ extension UIImage { // Trim off the extremely small float value to prevent core graphics from rounding it up newSize.width = floor(newSize.width) newSize.height = floor(newSize.height) - + UIGraphicsBeginImageContextWithOptions(newSize, true, self.scale) let context = UIGraphicsGetCurrentContext()! - + // Move origin to middle context.translateBy(x: newSize.width/2, y: newSize.height/2) // Rotate around middle context.rotate(by: CGFloat(radians)) // Draw the image at its center self.draw(in: CGRect(x: -self.size.width/2, y: -self.size.height/2, width: self.size.width, height: self.size.height)) - + let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() - + return newImage } } @@ -502,10 +500,9 @@ extension UIImage { // MARK: - UICollectionViewDragDelegate Methods @available(iOS 13.0, *) -extension DragDropViewController : UICollectionViewDragDelegate -{ +extension DragDropViewController: UICollectionViewDragDelegate { func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { - + if collectionView == collectionViewSource { let item = itemsSource[indexPath.row] let itemProvider = NSItemProvider(object: item as NSString) @@ -521,42 +518,42 @@ extension DragDropViewController : UICollectionViewDragDelegate let dragItem = UIDragItem(itemProvider: itemProvider) dragItem.localObject = item - + return [dragItem] } } - + func collectionView(_ collectionView: UICollectionView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem] { - + if collectionView == collectionViewSource { let item = itemsSource[indexPath.row] let itemProvider = NSItemProvider(object: item as NSString) let dragItem = UIDragItem(itemProvider: itemProvider) - + dragItem.localObject = item - + return [dragItem] - + } else { let item = imagesDestination[indexPath.row] let itemProvider = NSItemProvider(object: item as UIImage) let dragItem = UIDragItem(itemProvider: itemProvider) - + dragItem.localObject = item - + return [dragItem] } } - + func collectionView(_ collectionView: UICollectionView, dragPreviewParametersForItemAt indexPath: IndexPath) -> UIDragPreviewParameters? { - + let previewParameters = UIDragPreviewParameters() if collectionView == collectionViewSource { previewParameters.visiblePath = UIBezierPath(rect: CGRect(x: 20, y: 20, width: 100, height: 100)) } else { previewParameters.visiblePath = UIBezierPath(rect: CGRect(x: 20, y: 20, width: 80, height: 80)) } - + return previewParameters } } @@ -564,25 +561,25 @@ extension DragDropViewController : UICollectionViewDragDelegate // MARK: - UICollectionViewDropDelegate Methods @available(iOS 13.0, *) -extension DragDropViewController : UICollectionViewDropDelegate { - +extension DragDropViewController: UICollectionViewDropDelegate { + func collectionView(_ collectionView: UICollectionView, canHandle session: UIDropSession) -> Bool { - - return true //session.canLoadObjects(ofClass: NSString.self) + + return true // session.canLoadObjects(ofClass: NSString.self) } - + func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal { - + if collectionView == collectionViewSource { - + if collectionView.hasActiveDrag { return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath) } else { return UICollectionViewDropProposal(operation: .forbidden) } - + } else { - + if collectionView.hasActiveDrag { return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath) } else { @@ -590,51 +587,51 @@ extension DragDropViewController : UICollectionViewDropDelegate { } } } - + func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) { - + let destinationIndexPath: IndexPath - + switch coordinator.proposal.operation { - + case .move: - + if let indexPath = coordinator.destinationIndexPath { - + destinationIndexPath = indexPath - + } else { - + // Get last index path of table view. let section = collectionView.numberOfSections - 1 let row = collectionView.numberOfItems(inSection: section) - + destinationIndexPath = IndexPath(row: row, section: section) } self.reorderItems(coordinator: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView) - + break - + case .copy: - + // Get last index path of table view. let section = collectionView.numberOfSections - 1 let row = collectionView.numberOfItems(inSection: section) - + destinationIndexPath = IndexPath(row: row, section: section) self.copyItems(coordinator: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView) - + break - + default: return } } - + func collectionView(_ collectionView: UICollectionView, dropSessionDidEnd session: UIDropSession) { - + collectionViewDestination.reloadData() - + // Save button if imagesDestination.count == 0 { save.isEnabled = false @@ -643,4 +640,3 @@ extension DragDropViewController : UICollectionViewDropDelegate { } } } - diff --git a/iOSClient/Security/NCEndToEndMetadata.swift b/iOSClient/Security/NCEndToEndMetadata.swift index 91d0e9163..6c87d431e 100644 --- a/iOSClient/Security/NCEndToEndMetadata.swift +++ b/iOSClient/Security/NCEndToEndMetadata.swift @@ -24,37 +24,37 @@ import UIKit import NCCommunication -class NCEndToEndMetadata : NSObject { +class NCEndToEndMetadata: NSObject { struct e2eMetadata: Codable { - + struct metadataKeyCodable: Codable { - + let metadataKeys: [String: String] let version: Int } - + struct sharingCodable: Codable { - + let recipient: [String: String] } - + struct encryptedFileAttributes: Codable { - + let key: String let filename: String let mimetype: String let version: Int } - + struct filesCodable: Codable { - + let initializationVector: String let authenticationTag: String? let metadataKey: Int // Number of metadataKey let encrypted: String // encryptedFileAttributes } - + let files: [String: filesCodable] let metadata: metadataKeyCodable let sharing: sharingCodable? @@ -64,137 +64,137 @@ class NCEndToEndMetadata : NSObject { let instance = NCEndToEndMetadata() return instance }() - + // -------------------------------------------------------------------------------------------- // MARK: Encode / Decode JSON Metadata // -------------------------------------------------------------------------------------------- - + @objc func encoderMetadata(_ recordsE2eEncryption: [tableE2eEncryption], privateKey: String, serverUrl: String) -> String? { - - let jsonEncoder = JSONEncoder.init() + + let jsonEncoder = JSONEncoder() var files: [String: e2eMetadata.filesCodable] = [:] var version = 1 var metadataKeysDictionary: [String: String] = [:] - + for recordE2eEncryption in recordsE2eEncryption { - + // *** metadataKey *** - + // Encode64 for Android compatibility let metadatakey = (recordE2eEncryption.metadataKey.data(using: .utf8)?.base64EncodedString())! - + guard let metadataKeyEncryptedData = NCEndToEndEncryption.sharedManager().encryptAsymmetricString(metadatakey, publicKey: nil, privateKey: privateKey) else { return nil } - + let metadataKeyEncryptedBase64 = metadataKeyEncryptedData.base64EncodedString() - + metadataKeysDictionary["\(recordE2eEncryption.metadataKeyIndex)"] = metadataKeyEncryptedBase64 - + // *** File *** - + let encrypted = e2eMetadata.encryptedFileAttributes(key: recordE2eEncryption.key, filename: recordE2eEncryption.fileName, mimetype: recordE2eEncryption.mimeType, version: recordE2eEncryption.version) - + do { - + // Create "encrypted" let encryptedJsonData = try jsonEncoder.encode(encrypted) let encryptedJsonString = String(data: encryptedJsonData, encoding: .utf8) - + guard let encryptedEncryptedJson = NCEndToEndEncryption.sharedManager().encryptEncryptedJson(encryptedJsonString, key: recordE2eEncryption.metadataKey) else { print("Serious internal error in encoding metadata") return nil } - + let e2eMetadataFilesKey = e2eMetadata.filesCodable(initializationVector: recordE2eEncryption.initializationVector, authenticationTag: recordE2eEncryption.authenticationTag, metadataKey: 0, encrypted: encryptedEncryptedJson) - + files.updateValue(e2eMetadataFilesKey, forKey: recordE2eEncryption.fileNameIdentifier) - + } catch let error { print("Serious internal error in encoding metadata ("+error.localizedDescription+")") return nil } - + version = recordE2eEncryption.version } // Create Json metadataKeys - //e2eMetadataKey = e2eMetadata.metadataKeyCodable(metadataKeys: ["0":metadataKeyEncryptedBase64], version: version) + // e2eMetadataKey = e2eMetadata.metadataKeyCodable(metadataKeys: ["0":metadataKeyEncryptedBase64], version: version) let e2eMetadataKey = e2eMetadata.metadataKeyCodable(metadataKeys: metadataKeysDictionary, version: version) - + // Create final Json e2emetadata let e2emetadata = e2eMetadata(files: files, metadata: e2eMetadataKey, sharing: nil) - + do { - + let jsonData = try jsonEncoder.encode(e2emetadata) let jsonString = String(data: jsonData, encoding: .utf8) print("JSON String : " + jsonString!) - + return jsonString - + } catch let error { print("Serious internal error in encoding metadata ("+error.localizedDescription+")") return nil } } - + @discardableResult @objc func decoderMetadata(_ e2eMetaDataJSON: String, privateKey: String, serverUrl: String, account: String, urlBase: String) -> Bool { - - let jsonDecoder = JSONDecoder.init() + + let jsonDecoder = JSONDecoder() let data = e2eMetaDataJSON.data(using: .utf8) - //let dataQuickLook = (data as! NSData) - + // let dataQuickLook = (data as! NSData) + do { - + // *** metadataKey *** - + let decode = try jsonDecoder.decode(e2eMetadata.self, from: data!) - + let files = decode.files let metadata = decode.metadata - //let sharing = decode.sharing ---> V 2.0 + // let sharing = decode.sharing ---> V 2.0 var metadataKeysDictionary: [String: String] = [:] - + for metadataKeyDictionaryEncrypted in metadata.metadataKeys { - - guard let metadataKeyEncryptedData : NSData = NSData(base64Encoded: metadataKeyDictionaryEncrypted.value, options: NSData.Base64DecodingOptions(rawValue: 0)) else { + + guard let metadataKeyEncryptedData: NSData = NSData(base64Encoded: metadataKeyDictionaryEncrypted.value, options: NSData.Base64DecodingOptions(rawValue: 0)) else { return false } - + guard let metadataKeyBase64 = NCEndToEndEncryption.sharedManager().decryptAsymmetricData(metadataKeyEncryptedData as Data?, privateKey: privateKey) else { return false } - + // Initialize a `Data` from a Base-64 encoded String let metadataKeyBase64Data = Data(base64Encoded: metadataKeyBase64, options: NSData.Base64DecodingOptions(rawValue: 0))! let metadataKey = String(data: metadataKeyBase64Data, encoding: .utf8) - + metadataKeysDictionary[metadataKeyDictionaryEncrypted.key] = metadataKey } - + // *** File *** - + for file in files { - + let fileNameIdentifier = file.key let filesCodable = file.value as e2eMetadata.filesCodable - + let encrypted = filesCodable.encrypted let metadataKey = metadataKeysDictionary["\(filesCodable.metadataKey)"] - + guard let encryptedFileAttributesJson = NCEndToEndEncryption.sharedManager().decryptEncryptedJson(encrypted, key: metadataKey) else { return false } - + do { let encryptedFileAttributes = try jsonDecoder.decode(e2eMetadata.encryptedFileAttributes.self, from: encryptedFileAttributesJson.data(using: .utf8)!) if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND fileName == %@", account, fileNameIdentifier)) { let metadata = tableMetadata.init(value: metadata) - + let object = tableE2eEncryption() - + object.account = account object.authenticationTag = filesCodable.authenticationTag ?? "" object.fileName = encryptedFileAttributes.filename @@ -207,37 +207,37 @@ class NCEndToEndMetadata : NSObject { object.mimeType = encryptedFileAttributes.mimetype object.serverUrl = serverUrl object.version = encryptedFileAttributes.version - + // If exists remove records NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND fileNamePath == %@", object.account, object.fileNamePath)) NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND fileNameIdentifier == %@", object.account, object.fileNameIdentifier)) - + // Write file parameter for decrypted on DB NCManageDatabase.shared.addE2eEncryption(object) - + // Update metadata on tableMetadata metadata.fileNameView = encryptedFileAttributes.filename metadata.fileNameWithoutExt = (encryptedFileAttributes.filename as NSString).deletingPathExtension - + let results = NCCommunicationCommon.shared.getInternalType(fileName: encryptedFileAttributes.filename, mimeType: metadata.contentType, directory: metadata.directory) - + metadata.contentType = results.mimeType metadata.iconName = results.iconName metadata.classFile = results.classFile - + NCManageDatabase.shared.addMetadata(metadata) } - + } catch let error { print("Serious internal error in decoding metadata ("+error.localizedDescription+")") } } - + } catch let error { print("Serious internal error in decoding metadata ("+error.localizedDescription+")") return false } - + return true } } diff --git a/iOSClient/Security/NCViewCertificateDetails.swift b/iOSClient/Security/NCViewCertificateDetails.swift index 0040a8a3e..842b816f8 100644 --- a/iOSClient/Security/NCViewCertificateDetails.swift +++ b/iOSClient/Security/NCViewCertificateDetails.swift @@ -24,15 +24,15 @@ import UIKit public protocol NCViewCertificateDetailsDelegate { - func viewCertificateDetailsDismiss() + func viewCertificateDetailsDismiss(host: String) } // optional func public extension NCViewCertificateDetailsDelegate { - func viewCertificateDetailsDismiss() {} + func viewCertificateDetailsDismiss(host: String) {} } -class NCViewCertificateDetails: UIViewController { +class NCViewCertificateDetails: UIViewController { @IBOutlet weak var buttonCancel: UIBarButtonItem! @IBOutlet weak var scrollView: UIScrollView! @@ -49,13 +49,13 @@ class NCViewCertificateDetails: UIViewController { self.navigationItem.title = NSLocalizedString("_certificate_details_", comment: "") buttonCancel.title = NSLocalizedString("_close_", comment: "") - + let certNamePathTXT = directoryCertificate + "/" + host + ".txt" if FileManager.default.fileExists(atPath: certNamePathTXT) { do { let text = try String(contentsOfFile: certNamePathTXT, encoding: .utf8) let font = UIFont.systemFont(ofSize: 13) - let attributes = [NSAttributedString.Key.font: font] as [NSAttributedString.Key : Any] + let attributes = [NSAttributedString.Key.font: font] as [NSAttributedString.Key: Any] var contentRect = NSString(string: text).boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: 0), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: attributes, context: nil) contentRect = CGRect(x: contentRect.origin.x, y: contentRect.origin.y, width: ceil(contentRect.size.width), height: ceil(contentRect.size.height)) var contentWidth = contentRect.size.width @@ -66,14 +66,14 @@ class NCViewCertificateDetails: UIViewController { if contentHeight < view.frame.size.height { contentHeight = view.frame.size.width } - + textView.frame = CGRect(x: 0, y: 0, width: contentWidth, height: contentHeight) textView.font = font textView.text = text - + scrollView.contentSize = contentRect.size scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 50, right: 0) - + } catch { print("error") } @@ -83,15 +83,15 @@ class NCViewCertificateDetails: UIViewController { } } } - + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - self.delegate?.viewCertificateDetailsDismiss() + self.delegate?.viewCertificateDetailsDismiss(host: host) } - + // MARK: ACTION - + @IBAction func actionCancel(_ sender: UIBarButtonItem) { self.dismiss(animated: true, completion: nil) } diff --git a/iOSClient/Select/NCSelect.swift b/iOSClient/Select/NCSelect.swift index 65c47d501..7d083c6e2 100644 --- a/iOSClient/Select/NCSelect.swift +++ b/iOSClient/Select/NCSelect.swift @@ -29,12 +29,12 @@ import NCCommunication } class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresentationControllerDelegate, NCListCellDelegate, NCGridCellDelegate, NCSectionHeaderMenuDelegate, NCEmptyDataSetDelegate { - + @IBOutlet fileprivate weak var collectionView: UICollectionView! @IBOutlet fileprivate weak var buttonCancel: UIBarButtonItem! - + private var selectCommandViewSelect: NCSelectCommandView? - + @objc enum selectType: Int { case select case selectCreateFolder @@ -42,30 +42,30 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent } // ------ external settings ------------------------------------ - @objc var delegate: NCSelectDelegate? + @objc weak var delegate: NCSelectDelegate? @objc var typeOfCommandView: selectType = .select - + @objc var includeDirectoryE2EEncryption = false @objc var includeImages = false @objc var enableSelectFile = false @objc var type = "" @objc var items: [Any] = [] - + var titleCurrentFolder = NCBrandOptions.shared.brand var serverUrl = "" // ------------------------------------------------------------- - + private var emptyDataSet: NCEmptyDataSet? - + private let keyLayout = NCGlobal.shared.layoutViewMove private var serverUrlPush = "" private var metadataFolder = tableMetadata() - + private var isEditMode = false private var networkInProgress = false private var selectOcId: [String] = [] private var overwrite = true - + private var dataSource = NCDataSource() internal var richWorkspaceText: String? @@ -73,51 +73,51 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent private var autoUploadFileName = "" private var autoUploadDirectory = "" - + private var listLayout: NCListLayout! private var gridLayout: NCGridLayout! - + private let headerHeight: CGFloat = 50 private var headerRichWorkspaceHeight: CGFloat = 0 private let footerHeight: CGFloat = 100 - + private var shares: [tableShare]? - + private var backgroundImageView = UIImageView() - + private var activeAccount: tableAccount! - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + self.navigationController?.navigationBar.prefersLargeTitles = true self.navigationController?.presentationController?.delegate = self - + view.backgroundColor = NCBrandColor.shared.systemBackground activeAccount = NCManageDatabase.shared.getActiveAccount() - + // Cell - collectionView.register(UINib.init(nibName: "NCListCell", bundle: nil), forCellWithReuseIdentifier: "listCell") - collectionView.register(UINib.init(nibName: "NCGridCell", bundle: nil), forCellWithReuseIdentifier: "gridCell") - + collectionView.register(UINib(nibName: "NCListCell", bundle: nil), forCellWithReuseIdentifier: "listCell") + collectionView.register(UINib(nibName: "NCGridCell", bundle: nil), forCellWithReuseIdentifier: "gridCell") + // Header - collectionView.register(UINib.init(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu") - + collectionView.register(UINib(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu") + // Footer - collectionView.register(UINib.init(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter") + collectionView.register(UINib(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter") collectionView.alwaysBounceVertical = true collectionView.backgroundColor = NCBrandColor.shared.systemBackground - + listLayout = NCListLayout() gridLayout = NCGridLayout() - + buttonCancel.title = NSLocalizedString("_cancel_", comment: "") - + // Empty - emptyDataSet = NCEmptyDataSet.init(view: collectionView, offset: headerHeight, delegate: self) + emptyDataSet = NCEmptyDataSet(view: collectionView, offset: headerHeight, delegate: self) // Type of command view if typeOfCommandView == .select || typeOfCommandView == .selectCreateFolder { @@ -129,82 +129,82 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent self.view.addSubview(selectCommandViewSelect!) selectCommandViewSelect?.selectView = self selectCommandViewSelect?.translatesAutoresizingMaskIntoConstraints = false - + selectCommandViewSelect?.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true selectCommandViewSelect?.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true selectCommandViewSelect?.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true selectCommandViewSelect?.heightAnchor.constraint(equalToConstant: 80).isActive = true } - + if typeOfCommandView == .copyMove { selectCommandViewSelect = Bundle.main.loadNibNamed("NCSelectCommandViewCopyMove", owner: self, options: nil)?.first as? NCSelectCommandView self.view.addSubview(selectCommandViewSelect!) selectCommandViewSelect?.selectView = self selectCommandViewSelect?.translatesAutoresizingMaskIntoConstraints = false - + selectCommandViewSelect?.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true selectCommandViewSelect?.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true selectCommandViewSelect?.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true selectCommandViewSelect?.heightAnchor.constraint(equalToConstant: 150).isActive = true } - + NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSource), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSource), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(createFolder(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterCreateFolder), object: nil) changeTheming() } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + self.navigationItem.title = titleCurrentFolder - + // set the serverUrl if serverUrl == "" { serverUrl = NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account) } - + // get auto upload folder autoUploadFileName = NCManageDatabase.shared.getAccountAutoUploadFileName() autoUploadDirectory = NCManageDatabase.shared.getAccountAutoUploadDirectory(urlBase: activeAccount.urlBase, account: activeAccount.account) - - layoutForView = NCUtility.shared.getLayoutForView(key: keyLayout,serverUrl: serverUrl) + + layoutForView = NCUtility.shared.getLayoutForView(key: keyLayout, serverUrl: serverUrl) gridLayout.itemForLine = CGFloat(layoutForView?.itemForLine ?? 3) - + if layoutForView?.layout == NCGlobal.shared.layoutList { collectionView.collectionViewLayout = listLayout } else { collectionView.collectionViewLayout = gridLayout } - + loadDatasource(withLoadFolder: true) shares = NCManageDatabase.shared.getTableShares(account: activeAccount.account, serverUrl: serverUrl) } - + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) - + coordinator.animate(alongsideTransition: nil) { _ in self.collectionView?.collectionViewLayout.invalidateLayout() } } - + func presentationControllerDidDismiss( _ presentationController: UIPresentationController) { // Dismission } - + // MARK: - NotificationCenter @objc func changeTheming() { - + collectionView.reloadData() selectCommandViewSelect?.separatorView.backgroundColor = NCBrandColor.shared.separator } - + @objc func createFolder(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { if metadata.serverUrl == serverUrl { @@ -213,17 +213,17 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent } } } - + // MARK: - Empty - + func emptyDataSetView(_ view: NCEmptyView) { - + if networkInProgress { - view.emptyImage.image = UIImage.init(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width) + view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width) view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "") view.emptyDescription.text = "" } else { - view.emptyImage.image = UIImage.init(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width) + view.emptyImage.image = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width) if includeImages { view.emptyTitle.text = NSLocalizedString("_files_no_files_", comment: "") } else { @@ -232,65 +232,65 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent view.emptyDescription.text = "" } } - + // MARK: ACTION - + @IBAction func actionCancel(_ sender: UIBarButtonItem) { self.dismiss(animated: true, completion: nil) } - + func selectButtonPressed(_ sender: UIButton) { delegate?.dismissSelect(serverUrl: serverUrl, metadata: metadataFolder, type: type, items: items, overwrite: overwrite, copy: false, move: false) self.dismiss(animated: true, completion: nil) } - + func copyButtonPressed(_ sender: UIButton) { delegate?.dismissSelect(serverUrl: serverUrl, metadata: metadataFolder, type: type, items: items, overwrite: overwrite, copy: true, move: false) self.dismiss(animated: true, completion: nil) } - + func moveButtonPressed(_ sender: UIButton) { delegate?.dismissSelect(serverUrl: serverUrl, metadata: metadataFolder, type: type, items: items, overwrite: overwrite, copy: false, move: true) self.dismiss(animated: true, completion: nil) } - + func createFolderButtonPressed(_ sender: UIButton) { - - let alertController = UIAlertController(title: NSLocalizedString("_create_folder_", comment: ""), message:"", preferredStyle: .alert) - - alertController.addTextField { (textField) in + + let alertController = UIAlertController(title: NSLocalizedString("_create_folder_", comment: ""), message: "", preferredStyle: .alert) + + alertController.addTextField { textField in textField.autocapitalizationType = UITextAutocapitalizationType.words } - - let actionSave = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default) { (action:UIAlertAction) in - if let fileName = alertController.textFields?.first?.text { + + let actionSave = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default) { (_: UIAlertAction) in + if let fileName = alertController.textFields?.first?.text { self.createFolder(with: fileName) } } - - let actionCancel = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { (action:UIAlertAction) in + + let actionCancel = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { (_: UIAlertAction) in print("You've pressed cancel button") } - + alertController.addAction(actionSave) alertController.addAction(actionCancel) - - self.present(alertController, animated: true, completion:nil) + + self.present(alertController, animated: true, completion: nil) } - + @IBAction func valueChangedSwitchOverwrite(_ sender: UISwitch) { overwrite = sender.isOn } - + // MARK: TAP EVENT - + func tapSwitchHeader(sender: Any) { - + if collectionView.collectionViewLayout == gridLayout { // list layout UIView.animate(withDuration: 0.0, animations: { self.collectionView.collectionViewLayout.invalidateLayout() - self.collectionView.setCollectionViewLayout(self.listLayout, animated: false, completion: { (_) in + self.collectionView.setCollectionViewLayout(self.listLayout, animated: false, completion: { _ in self.collectionView.reloadData() }) }) @@ -299,29 +299,29 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent // grid layout UIView.animate(withDuration: 0.0, animations: { self.collectionView.collectionViewLayout.invalidateLayout() - self.collectionView.setCollectionViewLayout(self.gridLayout, animated: false, completion: { (_) in + self.collectionView.setCollectionViewLayout(self.gridLayout, animated: false, completion: { _ in self.collectionView.reloadData() }) }) layoutForView?.layout = NCGlobal.shared.layoutGrid } } - + func tapOrderHeader(sender: Any) { - + let sortMenu = NCSortMenu() sortMenu.toggleMenu(viewController: self, key: keyLayout, sortButton: sender as? UIButton, serverUrl: serverUrl) } - - // MARK: - Push metadata - + + // MARK: - Push metadata + func pushMetadata(_ metadata: tableMetadata) { - + guard let serverUrlPush = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName) else { return } guard let viewController = UIStoryboard(name: "NCSelect", bundle: nil).instantiateViewController(withIdentifier: "NCSelect.storyboard") as? NCSelect else { return } self.serverUrlPush = serverUrlPush - + viewController.delegate = delegate viewController.typeOfCommandView = typeOfCommandView viewController.includeDirectoryE2EEncryption = includeDirectoryE2EEncryption @@ -333,7 +333,7 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent viewController.titleCurrentFolder = metadata.fileNameView viewController.serverUrl = serverUrlPush - + self.navigationController?.pushViewController(viewController, animated: true) } } @@ -343,9 +343,9 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent extension NCSelect: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - + guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else { return } - + if isEditMode { if let index = selectOcId.firstIndex(of: metadata.ocId) { selectOcId.remove(at: index) @@ -355,13 +355,13 @@ extension NCSelect: UICollectionViewDelegate { collectionView.reloadItems(at: [indexPath]) return } - + if metadata.directory { - + pushMetadata(metadata) - + } else { - + delegate?.dismissSelect(serverUrl: serverUrl, metadata: metadata, type: type, items: items, overwrite: overwrite, copy: false, move: false) self.dismiss(animated: true, completion: nil) } @@ -371,40 +371,40 @@ extension NCSelect: UICollectionViewDelegate { extension NCSelect: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - + if kind == UICollectionView.elementKindSectionHeader { - + let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderMenu", for: indexPath) as! NCSectionHeaderMenu - + if collectionView.collectionViewLayout == gridLayout { - header.buttonSwitch.setImage(UIImage.init(named: "switchList")?.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) + header.buttonSwitch.setImage(UIImage(named: "switchList")?.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) } else { - header.buttonSwitch.setImage(UIImage.init(named: "switchGrid")?.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) + header.buttonSwitch.setImage(UIImage(named: "switchGrid")?.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) } - + header.delegate = self header.setStatusButton(count: dataSource.metadatas.count) header.setTitleSorted(datasourceTitleButton: layoutForView?.titleButtonHeader ?? "") header.viewRichWorkspaceHeightConstraint.constant = headerRichWorkspaceHeight header.setRichWorkspaceText(richWorkspaceText: richWorkspaceText) - + return header - + } else { - + let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as! NCSectionFooter - + let info = dataSource.getFilesInformation() footer.setTitleLabel(directories: info.directories, files: info.files, size: info.size) - + return footer } - + } - + func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else { return } - + // Thumbnail if !metadata.directory { if FileManager().fileExists(atPath: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) { @@ -413,7 +413,7 @@ extension NCSelect: UICollectionViewDataSource { NCOperationQueue.shared.downloadThumbnail(metadata: metadata, placeholder: true, cell: cell, view: collectionView) } } - + // Avatar if metadata.ownerId.count > 0, metadata.ownerId != activeAccount.userId, @@ -423,23 +423,23 @@ extension NCSelect: UICollectionViewDataSource { NCOperationQueue.shared.downloadAvatar(user: metadata.ownerId, dispalyName: metadata.ownerDisplayName, fileName: fileName, cell: cell, view: collectionView) } } - + func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { - + } - + func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } - + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { let numberOfItems = dataSource.numberOfItems() - emptyDataSet?.numberOfItemsInSection(numberOfItems, section:section) + emptyDataSet?.numberOfItemsInSection(numberOfItems, section: section) return numberOfItems } - + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - + guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else { if layoutForView?.layout == NCGlobal.shared.layoutList { return collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! NCListCell @@ -447,51 +447,51 @@ extension NCSelect: UICollectionViewDataSource { return collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as! NCGridCell } } - + var tableShare: tableShare? var isShare = false var isMounted = false - + isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !metadataFolder.permissions.contains(NCGlobal.shared.permissionShared) isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !metadataFolder.permissions.contains(NCGlobal.shared.permissionMounted) - + if dataSource.metadataShare[metadata.ocId] != nil { tableShare = dataSource.metadataShare[metadata.ocId] } - + // LAYOUT LIST - + if layoutForView?.layout == NCGlobal.shared.layoutList { - + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! NCListCell cell.delegate = self - + cell.fileObjectId = metadata.ocId cell.fileUser = metadata.ownerId cell.labelTitle.text = metadata.fileNameView cell.labelTitle.textColor = NCBrandColor.shared.label - + cell.imageSelect.image = nil cell.imageStatus.image = nil cell.imageLocal.image = nil cell.imageFavorite.image = nil cell.imageShared.image = nil cell.imageMore.image = nil - + cell.imageItem.image = nil cell.imageItem.backgroundColor = nil - + cell.progressView.progress = 0.0 - + if metadata.directory { - + if metadata.e2eEncrypted { cell.imageItem.image = NCBrandColor.cacheImages.folderEncrypted } else if isShare { cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe - } else if (tableShare != nil && tableShare?.shareType != 3) { + } else if tableShare != nil && tableShare?.shareType != 3 { cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe - } else if (tableShare != nil && tableShare?.shareType == 3) { + } else if tableShare != nil && tableShare?.shareType == 3 { cell.imageItem.image = NCBrandColor.cacheImages.folderPublic } else if metadata.mountType == "group" { cell.imageItem.image = NCBrandColor.cacheImages.folderGroup @@ -502,21 +502,21 @@ extension NCSelect: UICollectionViewDataSource { } else { cell.imageItem.image = NCBrandColor.cacheImages.folder } - + cell.labelInfo.text = CCUtility.dateDiff(metadata.date as Date) - + let lockServerUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName)! let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", activeAccount.account, lockServerUrl)) - + // Local image: offline if tableDirectory != nil && tableDirectory!.offline { cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag } - + } else { - + cell.labelInfo.text = CCUtility.dateDiff(metadata.date as Date) + " · " + CCUtility.transformedSize(metadata.size) - + // image local if dataSource.metadataOffLine.contains(metadata.ocId) { cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag @@ -524,75 +524,75 @@ extension NCSelect: UICollectionViewDataSource { cell.imageLocal.image = NCBrandColor.cacheImages.local } } - + // image Favorite if metadata.favorite { cell.imageFavorite.image = NCBrandColor.cacheImages.favorite } - + // Share image - if (isShare) { + if isShare { cell.imageShared.image = NCBrandColor.cacheImages.shared - } else if (tableShare != nil && tableShare?.shareType == 3) { + } else if tableShare != nil && tableShare?.shareType == 3 { cell.imageShared.image = NCBrandColor.cacheImages.shareByLink - } else if (tableShare != nil && tableShare?.shareType != 3) { + } else if tableShare != nil && tableShare?.shareType != 3 { cell.imageShared.image = NCBrandColor.cacheImages.shared } else { cell.imageShared.image = NCBrandColor.cacheImages.canShare } - + cell.imageSelect.isHidden = true cell.backgroundView = nil cell.hideButtonMore(true) cell.hideButtonShare(true) cell.selectMode(false) - + // Live Photo if metadata.livePhoto { cell.imageStatus.image = NCBrandColor.cacheImages.livePhoto } - + // Remove last separator if collectionView.numberOfItems(inSection: indexPath.section) == indexPath.row + 1 { cell.separator.isHidden = true } else { cell.separator.isHidden = false } - + return cell } - + // LAYOUT GRID - + if layoutForView?.layout == NCGlobal.shared.layoutGrid { - + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as! NCGridCell cell.delegate = self - + cell.fileObjectId = metadata.ocId cell.fileUser = metadata.ownerId cell.labelTitle.text = metadata.fileNameView cell.labelTitle.textColor = NCBrandColor.shared.label - + cell.imageSelect.image = nil cell.imageStatus.image = nil cell.imageLocal.image = nil cell.imageFavorite.image = nil - + cell.imageItem.image = nil cell.imageItem.backgroundColor = nil - + cell.progressView.progress = 0.0 if metadata.directory { - + if metadata.e2eEncrypted { cell.imageItem.image = NCBrandColor.cacheImages.folderEncrypted } else if isShare { cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe - } else if (tableShare != nil && tableShare!.shareType != 3) { + } else if tableShare != nil && tableShare!.shareType != 3 { cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe - } else if (tableShare != nil && tableShare!.shareType == 3) { + } else if tableShare != nil && tableShare!.shareType == 3 { cell.imageItem.image = NCBrandColor.cacheImages.folderPublic } else if metadata.mountType == "group" { cell.imageItem.image = NCBrandColor.cacheImages.folderGroup @@ -603,17 +603,17 @@ extension NCSelect: UICollectionViewDataSource { } else { cell.imageItem.image = NCBrandColor.cacheImages.folder } - + let lockServerUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName)! let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", activeAccount.account, lockServerUrl)) - + // Local image: offline if tableDirectory != nil && tableDirectory!.offline { cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag } - + } else { - + // image Local if dataSource.metadataOffLine.contains(metadata.ocId) { cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag @@ -621,12 +621,12 @@ extension NCSelect: UICollectionViewDataSource { cell.imageLocal.image = NCBrandColor.cacheImages.local } } - + // image Favorite if metadata.favorite { cell.imageFavorite.image = NCBrandColor.cacheImages.favorite } - + cell.imageSelect.isHidden = true cell.backgroundView = nil cell.hideButtonMore(true) @@ -635,10 +635,10 @@ extension NCSelect: UICollectionViewDataSource { if metadata.livePhoto { cell.imageStatus.image = NCBrandColor.cacheImages.livePhoto } - + return cell } - + return collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as! NCGridCell } } @@ -646,19 +646,19 @@ extension NCSelect: UICollectionViewDataSource { extension NCSelect: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { - + headerRichWorkspaceHeight = 0 - + if let richWorkspaceText = richWorkspaceText { let trimmed = richWorkspaceText.trimmingCharacters(in: .whitespaces) if trimmed.count > 0 { headerRichWorkspaceHeight = UIScreen.main.bounds.size.height / 4 } } - + return CGSize(width: collectionView.frame.width, height: headerHeight + headerRichWorkspaceHeight) } - + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.width, height: footerHeight) } @@ -671,61 +671,61 @@ extension NCSelect { @objc func reloadDataSource() { loadDatasource(withLoadFolder: false) } - + @objc func loadDatasource(withLoadFolder: Bool) { - + var predicate: NSPredicate? - + layoutForView = NCUtility.shared.getLayoutForView(key: keyLayout, serverUrl: serverUrl) - + if includeDirectoryE2EEncryption { - + if includeImages { predicate = NSPredicate(format: "account == %@ AND serverUrl == %@ AND (directory == true OR classFile == 'image')", activeAccount.account, serverUrl) } else { predicate = NSPredicate(format: "account == %@ AND serverUrl == %@ AND directory == true", activeAccount.account, serverUrl) } - + } else { - + if includeImages { predicate = NSPredicate(format: "account == %@ AND serverUrl == %@ AND e2eEncrypted == false AND (directory == true OR classFile == 'image')", activeAccount.account, serverUrl) } else { predicate = NSPredicate(format: "account == %@ AND serverUrl == %@ AND e2eEncrypted == false AND directory == true", activeAccount.account, serverUrl) } } - + let metadatasSource = NCManageDatabase.shared.getMetadatas(predicate: predicate!) - self.dataSource = NCDataSource.init(metadatasSource: metadatasSource, sort: layoutForView?.sort, ascending: layoutForView?.ascending, directoryOnTop: layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) - + self.dataSource = NCDataSource(metadatasSource: metadatasSource, sort: layoutForView?.sort, ascending: layoutForView?.ascending, directoryOnTop: layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) + if withLoadFolder { loadFolder() - } - - let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", activeAccount.account,serverUrl)) + } + + let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", activeAccount.account, serverUrl)) richWorkspaceText = directory?.richWorkspace - + DispatchQueue.main.async { self.collectionView.reloadData() } } - + func createFolder(with fileName: String) { - - NCNetworking.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: activeAccount.account, urlBase: activeAccount.urlBase) { (errorCode, errorDescription) in - + + NCNetworking.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: activeAccount.account, urlBase: activeAccount.urlBase) { errorCode, errorDescription in + if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } } } - + func loadFolder() { - + networkInProgress = true collectionView.reloadData() - - NCNetworking.shared.readFolder(serverUrl: serverUrl, account: activeAccount.account) { (_, _, _, _, _, _, errorCode, errorDescription) in + + NCNetworking.shared.readFolder(serverUrl: serverUrl, account: activeAccount.account) { _, _, _, _, _, _, errorCode, errorDescription in if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } @@ -750,47 +750,47 @@ class NCSelectCommandView: UIView { var selectView: NCSelect? private let gradient: CAGradientLayer = CAGradientLayer() - + override func awakeFromNib() { - + separatorHeightConstraint.constant = 0.5 separatorView.backgroundColor = NCBrandColor.shared.separator - + overwriteLabel?.text = NSLocalizedString("_overwrite_", comment: "") - + selectButton?.layer.cornerRadius = 15 selectButton?.layer.masksToBounds = true selectButton?.setTitle(NSLocalizedString("_select_", comment: ""), for: .normal) - + createFolderButton?.layer.cornerRadius = 15 createFolderButton?.layer.masksToBounds = true createFolderButton?.setTitle(NSLocalizedString("_create_folder_", comment: ""), for: .normal) - + copyButton?.layer.cornerRadius = 15 copyButton?.layer.masksToBounds = true copyButton?.setTitle(NSLocalizedString("_copy_", comment: ""), for: .normal) - + moveButton?.layer.cornerRadius = 15 moveButton?.layer.masksToBounds = true moveButton?.setTitle(NSLocalizedString("_move_", comment: ""), for: .normal) } - + @IBAction func createFolderButtonPressed(_ sender: UIButton) { selectView?.createFolderButtonPressed(sender) } - + @IBAction func selectButtonPressed(_ sender: UIButton) { selectView?.selectButtonPressed(sender) } - + @IBAction func copyButtonPressed(_ sender: UIButton) { selectView?.copyButtonPressed(sender) } - + @IBAction func moveButtonPressed(_ sender: UIButton) { selectView?.moveButtonPressed(sender) } - + @IBAction func valueChangedSwitchOverwrite(_ sender: UISwitch) { selectView?.valueChangedSwitchOverwrite(sender) } diff --git a/iOSClient/Settings/NCEndToEndInitialize.swift b/iOSClient/Settings/NCEndToEndInitialize.swift index 2b8e907ab..1337ad354 100644 --- a/iOSClient/Settings/NCEndToEndInitialize.swift +++ b/iOSClient/Settings/NCEndToEndInitialize.swift @@ -25,278 +25,277 @@ import UIKit import NCCommunication @objc protocol NCEndToEndInitializeDelegate { - + func endToEndInitializeSuccess() } -class NCEndToEndInitialize : NSObject { +class NCEndToEndInitialize: NSObject { @objc weak var delegate: NCEndToEndInitializeDelegate? let appDelegate = UIApplication.shared.delegate as! AppDelegate var extractedPublicKey: String? - + override init() { } - + // -------------------------------------------------------------------------------------------- // MARK: Initialize // -------------------------------------------------------------------------------------------- - + @objc func initEndToEndEncryption() { - + // Clear all keys CCUtility.clearAllKeysEnd(toEnd: appDelegate.account) - + self.getPublicKey() } - + func getPublicKey() { - - NCCommunication.shared.getE2EECertificate { (account, certificate, errorCode, errorDescription) in - - if (errorCode == 0 && account == self.appDelegate.account) { - + + NCCommunication.shared.getE2EECertificate { account, certificate, errorCode, errorDescription in + + if errorCode == 0 && account == self.appDelegate.account { + CCUtility.setEndToEndCertificate(account, certificate: certificate) - + self.extractedPublicKey = NCEndToEndEncryption.sharedManager().extractPublicKey(fromCertificate: certificate) - + // Request PrivateKey chiper to Server self.getPrivateKeyCipher() - + } else if errorCode != 0 { - + switch errorCode { - + case NCGlobal.shared.errorBadRequest: NCContentPresenter.shared.messageNotification("E2E get publicKey", description: "bad request: unpredictable internal error", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + case NCGlobal.shared.errorResourceNotFound: guard let csr = NCEndToEndEncryption.sharedManager().createCSR(self.appDelegate.userId, directory: CCUtility.getDirectoryUserData()) else { - + NCContentPresenter.shared.messageNotification("E2E Csr", description: "Error to create Csr", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + return } - - NCCommunication.shared.signE2EECertificate(certificate: csr) { (account, certificate, errorCode, errorDescription) in - - if (errorCode == 0 && account == self.appDelegate.account) { - + + NCCommunication.shared.signE2EECertificate(certificate: csr) { account, certificate, errorCode, errorDescription in + + if errorCode == 0 && account == self.appDelegate.account { + // TEST publicKey let extractedPublicKey = NCEndToEndEncryption.sharedManager().extractPublicKey(fromCertificate: certificate) if extractedPublicKey != NCEndToEndEncryption.sharedManager().generatedPublicKey { - + NCContentPresenter.shared.messageNotification("E2E sign publicKey", description: "error: the public key is incorrect", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + } else { - + CCUtility.setEndToEndCertificate(account, certificate: certificate) - + // Request PrivateKey chiper to Server self.getPrivateKeyCipher() } - + } else if errorCode != 0 { - + switch errorCode { - + case NCGlobal.shared.errorBadRequest: NCContentPresenter.shared.messageNotification("E2E sign publicKey", description: "bad request: unpredictable internal error", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + case NCGlobal.shared.errorConflict: NCContentPresenter.shared.messageNotification("E2E sign publicKey", description: "conflict: a public key for the user already exists", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + default: NCContentPresenter.shared.messageNotification("E2E sign publicKey", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) } } } - + case NCGlobal.shared.errorConflict: NCContentPresenter.shared.messageNotification("E2E get publicKey", description: "forbidden: the user can't access the public keys", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + default: NCContentPresenter.shared.messageNotification("E2E get publicKey", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) } } } } - + func getPrivateKeyCipher() { - + // Request PrivateKey chiper to Server - NCCommunication.shared.getE2EEPrivateKey { (account, privateKeyChiper, errorCode, errorDescription) in - - if (errorCode == 0 && account == self.appDelegate.account) { - + NCCommunication.shared.getE2EEPrivateKey { account, privateKeyChiper, errorCode, errorDescription in + + if errorCode == 0 && account == self.appDelegate.account { + // request Passphrase - + var passphraseTextField: UITextField? - + let alertController = UIAlertController(title: NSLocalizedString("_e2e_passphrase_request_title_", comment: ""), message: NSLocalizedString("_e2e_passphrase_request_message_", comment: ""), preferredStyle: .alert) - - let ok = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in - + + let ok = UIAlertAction(title: "OK", style: .default, handler: { _ -> Void in + let passphrase = passphraseTextField?.text - + let publicKey = CCUtility.getEndToEndCertificate(self.appDelegate.account) - + guard let privateKey = (NCEndToEndEncryption.sharedManager().decryptPrivateKey(privateKeyChiper, passphrase: passphrase, publicKey: publicKey)) else { - + NCContentPresenter.shared.messageNotification("E2E decrypt privateKey", description: "Serious internal error to decrypt Private Key", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError, priority: .max) - + return } - + // privateKey print(privateKey) - + // Save to keychain CCUtility.setEndToEndPrivateKey(self.appDelegate.account, privateKey: privateKey) - CCUtility.setEndToEndPassphrase(self.appDelegate.account, passphrase:passphrase) - + CCUtility.setEndToEndPassphrase(self.appDelegate.account, passphrase: passphrase) + // request server publicKey - NCCommunication.shared.getE2EEPublicKey { (account, publicKey, errorCode, errorDescription) in - - if (errorCode == 0 && account == self.appDelegate.account) { - + NCCommunication.shared.getE2EEPublicKey { account, publicKey, errorCode, errorDescription in + + if errorCode == 0 && account == self.appDelegate.account { + CCUtility.setEndToEndPublicKey(account, publicKey: publicKey) - + // Clear Table NCManageDatabase.shared.clearTable(tableDirectory.self, account: account) NCManageDatabase.shared.clearTable(tableE2eEncryption.self, account: account) - + self.delegate?.endToEndInitializeSuccess() - + } else if errorCode != 0 { - - switch (errorCode) { - + + switch errorCode { + case NCGlobal.shared.errorBadRequest: NCContentPresenter.shared.messageNotification("E2E Server publicKey", description: "bad request: unpredictable internal error", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + case NCGlobal.shared.errorResourceNotFound: NCContentPresenter.shared.messageNotification("E2E Server publicKey", description: "Server publickey doesn't exists", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + case NCGlobal.shared.errorConflict: NCContentPresenter.shared.messageNotification("E2E Server publicKey", description: "forbidden: the user can't access the Server publickey", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + default: NCContentPresenter.shared.messageNotification("E2E Server publicKey", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) } } } }) - - let cancel = UIAlertAction(title: "Cancel", style: .cancel) { (action) -> Void in + + let cancel = UIAlertAction(title: "Cancel", style: .cancel) { _ -> Void in } - + alertController.addAction(ok) alertController.addAction(cancel) - alertController.addTextField { (textField) -> Void in + alertController.addTextField { textField -> Void in passphraseTextField = textField passphraseTextField?.placeholder = "Enter passphrase (12 words)" } - + self.appDelegate.window?.rootViewController?.present(alertController, animated: true) - + } else if errorCode != 0 { - + switch errorCode { - + case NCGlobal.shared.errorBadRequest: NCContentPresenter.shared.messageNotification("E2E get privateKey", description: "bad request: unpredictable internal error", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + case NCGlobal.shared.errorResourceNotFound: // message let e2ePassphrase = NYMnemonic.generateString(128, language: "english") let message = "\n" + NSLocalizedString("_e2e_settings_view_passphrase_", comment: "") + "\n\n" + e2ePassphrase! - + let alertController = UIAlertController(title: NSLocalizedString("_e2e_settings_title_", comment: ""), message: NSLocalizedString(message, comment: ""), preferredStyle: .alert) - - let OKAction = UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default) { action in - + + let OKAction = UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default) { _ in + var privateKeyString: NSString? - + guard let privateKeyChiper = NCEndToEndEncryption.sharedManager().encryptPrivateKey(self.appDelegate.userId, directory: CCUtility.getDirectoryUserData(), passphrase: e2ePassphrase, privateKey: &privateKeyString) else { - + NCContentPresenter.shared.messageNotification("E2E privateKey", description: "Serious internal error to create PrivateKey chiper", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + return } - + // privateKeyChiper print(privateKeyChiper) - - NCCommunication.shared.storeE2EEPrivateKey(privateKey: privateKeyChiper) { (account, privateKey, errorCode, errorDescription) in - - if (errorCode == 0 && account == self.appDelegate.account) { - + + NCCommunication.shared.storeE2EEPrivateKey(privateKey: privateKeyChiper) { account, privateKey, errorCode, errorDescription in + + if errorCode == 0 && account == self.appDelegate.account { + CCUtility.setEndToEndPrivateKey(account, privateKey: privateKeyString! as String) CCUtility.setEndToEndPassphrase(account, passphrase: e2ePassphrase) - + // request server publicKey - NCCommunication.shared.getE2EEPublicKey { (account, publicKey, errorCode, errorDescription) in - - if (errorCode == 0 && account == self.appDelegate.account) { - + NCCommunication.shared.getE2EEPublicKey { account, publicKey, errorCode, errorDescription in + + if errorCode == 0 && account == self.appDelegate.account { + CCUtility.setEndToEndPublicKey(account, publicKey: publicKey) - + // Clear Table NCManageDatabase.shared.clearTable(tableDirectory.self, account: account) NCManageDatabase.shared.clearTable(tableE2eEncryption.self, account: account) - + self.delegate?.endToEndInitializeSuccess() - + } else if errorCode != 0 { - - switch (errorCode) { - + + switch errorCode { + case NCGlobal.shared.errorBadRequest: NCContentPresenter.shared.messageNotification("E2E Server publicKey", description: "bad request: unpredictable internal error", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + case NCGlobal.shared.errorResourceNotFound: NCContentPresenter.shared.messageNotification("E2E Server publicKey", description: "Server publickey doesn't exists", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + case NCGlobal.shared.errorConflict: NCContentPresenter.shared.messageNotification("E2E Server publicKey", description: "forbidden: the user can't access the Server publickey", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + default: NCContentPresenter.shared.messageNotification("E2E Server publicKey", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) } } } - + } else if errorCode != 0 { - + switch errorCode { - + case NCGlobal.shared.errorBadRequest: NCContentPresenter.shared.messageNotification("E2E store privateKey", description: "bad request: unpredictable internal error", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + case NCGlobal.shared.errorConflict: NCContentPresenter.shared.messageNotification("E2E store privateKey", description: "conflict: a private key for the user already exists", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + default: NCContentPresenter.shared.messageNotification("E2E store privateKey", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) } } } } - + alertController.addAction(OKAction) self.appDelegate.window?.rootViewController?.present(alertController, animated: true) - + case NCGlobal.shared.errorConflict: NCContentPresenter.shared.messageNotification("E2E get privateKey", description: "forbidden: the user can't access the private key", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) - + default: - NCContentPresenter.shared.messageNotification("E2E get privateKey", description: errorDescription,delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) + NCContentPresenter.shared.messageNotification("E2E get privateKey", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode, priority: .max) } } } } - -} +} diff --git a/iOSClient/Settings/NCManageAutoUploadFileName.swift b/iOSClient/Settings/NCManageAutoUploadFileName.swift index e88fb7384..b402f4739 100644 --- a/iOSClient/Settings/NCManageAutoUploadFileName.swift +++ b/iOSClient/Settings/NCManageAutoUploadFileName.swift @@ -24,36 +24,36 @@ import UIKit class NCManageAutoUploadFileName: XLFormViewController { - + let appDelegate = UIApplication.shared.delegate as! AppDelegate let dateExample = Date() - + func initializeForm() { - - let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + + let form: XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow - - var section : XLFormSectionDescriptor - var row : XLFormRowDescriptor + + var section: XLFormSectionDescriptor + var row: XLFormRowDescriptor // Section Mode filename section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_mode_filename_", comment: "")) form.addFormSection(section) - + // Maintain the original fileName - + row = XLFormRowDescriptor(tag: "maintainOriginalFileName", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_maintain_original_filename_", comment: "")) row.value = CCUtility.getOriginalFileName(NCGlobal.shared.keyFileNameOriginalAutoUpload) row.cellConfig["backgroundColor"] = NCBrandColor.shared.secondarySystemGroupedBackground - + row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label section.addFormRow(row) - + // Add File Name Type - + row = XLFormRowDescriptor(tag: "addFileNameType", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_add_filenametype_", comment: "")) row.value = CCUtility.getFileNameType(NCGlobal.shared.keyFileNameAutoUploadType) row.hidden = "$\("maintainOriginalFileName") == 1" @@ -63,20 +63,20 @@ class NCManageAutoUploadFileName: XLFormViewController { row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label section.addFormRow(row) - + // Section: Rename File Name - + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_filename_", comment: "")) form.addFormSection(section) - + row = XLFormRowDescriptor(tag: "maskFileName", rowType: XLFormRowDescriptorTypeText, title: (NSLocalizedString("_filename_", comment: ""))) - let fileNameMask : String = CCUtility.getFileNameMask(NCGlobal.shared.keyFileNameAutoUploadMask) + let fileNameMask: String = CCUtility.getFileNameMask(NCGlobal.shared.keyFileNameAutoUploadMask) if fileNameMask.count > 0 { row.value = fileNameMask } row.hidden = "$\("maintainOriginalFileName") == 1" row.cellConfig["backgroundColor"] = NCBrandColor.shared.secondarySystemGroupedBackground - + row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.label @@ -85,9 +85,9 @@ class NCManageAutoUploadFileName: XLFormViewController { row.cellConfig["textField.textColor"] = NCBrandColor.shared.label section.addFormRow(row) - + // Section: Preview File Name - + row = XLFormRowDescriptor(tag: "previewFileName", rowType: XLFormRowDescriptorTypeTextView, title: "") row.height = 180 row.disabled = true @@ -98,124 +98,122 @@ class NCManageAutoUploadFileName: XLFormViewController { row.cellConfig["textView.textColor"] = NCBrandColor.shared.label section.addFormRow(row) - + self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none self.form = form } - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + self.title = NSLocalizedString("_mode_filename_", comment: "") view.backgroundColor = NCBrandColor.shared.systemGroupedBackground - + tableView.backgroundColor = NCBrandColor.shared.systemGroupedBackground - + initializeForm() reloadForm() } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + appDelegate.activeViewController = self } - - //MARK: XLForm + + // MARK: XLForm func reloadForm() { - + self.form.delegate = nil - - let maskFileName : XLFormRowDescriptor = self.form.formRow(withTag: "maskFileName")! - let previewFileName : XLFormRowDescriptor = self.form.formRow(withTag: "previewFileName")! + + let maskFileName: XLFormRowDescriptor = self.form.formRow(withTag: "maskFileName")! + let previewFileName: XLFormRowDescriptor = self.form.formRow(withTag: "previewFileName")! previewFileName.value = self.previewFileName(valueRename: maskFileName.value as? String) - + self.tableView.reloadData() self.form.delegate = self } - + override func formRowDescriptorValueHasChanged(_ formRow: XLFormRowDescriptor!, oldValue: Any!, newValue: Any!) { - + super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue) - + if formRow.tag == "addFileNameType" { CCUtility.setFileNameType((formRow.value! as AnyObject).boolValue, key: NCGlobal.shared.keyFileNameAutoUploadType) self.reloadForm() - } - else if formRow.tag == "maintainOriginalFileName" { - CCUtility.setOriginalFileName((formRow.value! as AnyObject).boolValue, key:NCGlobal.shared.keyFileNameOriginalAutoUpload) + } else if formRow.tag == "maintainOriginalFileName" { + CCUtility.setOriginalFileName((formRow.value! as AnyObject).boolValue, key: NCGlobal.shared.keyFileNameOriginalAutoUpload) self.reloadForm() - } - else if formRow.tag == "maskFileName" { - + } else if formRow.tag == "maskFileName" { + let fileName = formRow.value as? String - + self.form.delegate = nil - + if let fileName = fileName { formRow.value = CCUtility.removeForbiddenCharactersServer(fileName) } - + self.form.delegate = self - - let previewFileName : XLFormRowDescriptor = self.form.formRow(withTag: "previewFileName")! + + let previewFileName: XLFormRowDescriptor = self.form.formRow(withTag: "previewFileName")! previewFileName.value = self.previewFileName(valueRename: formRow.value as? String) - + // reload cell if fileName != nil { - + if newValue as! String != formRow.value as! String { - + self.reloadFormRow(formRow) - + NCContentPresenter.shared.messageNotification("_info_", description: "_forbidden_characters_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorCharactersForbidden) } } - + self.reloadFormRow(previewFileName) } } - + // MARK: - Utility - - func previewFileName(valueRename : String?) -> String { - - var returnString : String = "" - + + func previewFileName(valueRename: String?) -> String { + + var returnString: String = "" + if CCUtility.getOriginalFileName(NCGlobal.shared.keyFileNameOriginalAutoUpload) { - + return (NSLocalizedString("_filename_", comment: "") + ": IMG_0001.JPG") - + } else if let valueRename = valueRename { - + let valueRenameTrimming = valueRename.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) - + if valueRenameTrimming.count > 0 { - + self.form.delegate = nil CCUtility.setFileNameMask(valueRename, key: NCGlobal.shared.keyFileNameAutoUploadMask) self.form.delegate = self - + returnString = CCUtility.createFileName("IMG_0001.JPG", fileDate: dateExample, fileType: PHAssetMediaType.image, keyFileName: NCGlobal.shared.keyFileNameAutoUploadMask, keyFileNameType: NCGlobal.shared.keyFileNameAutoUploadType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginalAutoUpload, forcedNewFileName: false) } else { - + CCUtility.setFileNameMask("", key: NCGlobal.shared.keyFileNameAutoUploadMask) returnString = CCUtility.createFileName("IMG_0001.JPG", fileDate: dateExample, fileType: PHAssetMediaType.image, keyFileName: nil, keyFileNameType: NCGlobal.shared.keyFileNameAutoUploadType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginalAutoUpload, forcedNewFileName: false) } - + } else { - + CCUtility.setFileNameMask("", key: NCGlobal.shared.keyFileNameAutoUploadMask) returnString = CCUtility.createFileName("IMG_0001.JPG", fileDate: dateExample, fileType: PHAssetMediaType.image, keyFileName: nil, keyFileNameType: NCGlobal.shared.keyFileNameAutoUploadType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginalAutoUpload, forcedNewFileName: false) } - + return String(format: NSLocalizedString("_preview_filename_", comment: ""), "MM,MMM,DD,YY,YYYY and HH,hh,mm,ss,ampm") + ":" + "\n\n" + returnString } - + // MARK: - override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { diff --git a/iOSClient/Settings/NCSettings.m b/iOSClient/Settings/NCSettings.m index 04dc16761..223241d21 100644 --- a/iOSClient/Settings/NCSettings.m +++ b/iOSClient/Settings/NCSettings.m @@ -66,9 +66,9 @@ row.action.viewControllerClass = [CCManageAutoUpload class]; [section addFormRow:row]; - // Section : LOCK -------------------------------------------------------------- + // Section : PRIVACY -------------------------------------------------------------- - section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_lock_", nil)]; + section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_privacy_", nil)]; [form addFormSection:section]; // Lock active YES/NO @@ -93,6 +93,12 @@ [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; [row.cellConfig setObject:NCBrandColor.shared.label forKey:@"textLabel.textColor"]; [section addFormRow:row]; + // Privacy screen + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"privacyScreen" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_privacy_screen_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = NCBrandColor.shared.secondarySystemGroupedBackground; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:NCBrandColor.shared.label forKey:@"textLabel.textColor"]; + [section addFormRow:row]; // Section : E2EEncryption -------------------------------------------------------------- @@ -144,8 +150,8 @@ if (!NCBrandOptions.shared.disable_crash_service) { - // Privacy - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"privacy" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_privacy_", nil)]; + // Privacy and Legal Policy + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"privacy" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_privacy_legal_", nil)]; row.cellConfigAtConfigure[@"backgroundColor"] = NCBrandColor.shared.secondarySystemGroupedBackground; [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; @@ -224,6 +230,7 @@ XLFormRowDescriptor *rowBloccoPasscode = [self.form formRowWithTag:@"bloccopasscode"]; XLFormRowDescriptor *rowNotPasscodeAtStart = [self.form formRowWithTag:@"notPasscodeAtStart"]; XLFormRowDescriptor *rowEnableTouchDaceID = [self.form formRowWithTag:@"enableTouchDaceID"]; + XLFormRowDescriptor *rowPrivacyScreen = [self.form formRowWithTag:@"privacyScreen"]; // ------------------------------------------------------------------ @@ -237,6 +244,8 @@ if ([CCUtility getEnableTouchFaceID]) [rowEnableTouchDaceID setValue:@1]; else [rowEnableTouchDaceID setValue:@0]; if ([CCUtility getNotPasscodeAtStart]) [rowNotPasscodeAtStart setValue:@1]; else [rowNotPasscodeAtStart setValue:@0]; + if ([CCUtility getPrivacyScreenEnabled]) [rowPrivacyScreen setValue:@1]; else [rowPrivacyScreen setValue:@0]; + // ----------------------------------------------------------------- @@ -266,6 +275,15 @@ [CCUtility setEnableTouchFaceID:false]; } } + + if ([rowDescriptor.tag isEqualToString:@"privacyScreen"]) { + + if ([[rowDescriptor.value valueData] boolValue] == YES) { + [CCUtility setPrivacyScreenEnabled:true]; + } else { + [CCUtility setPrivacyScreenEnabled:false]; + } + } } #pragma mark - diff --git a/iOSClient/Settings/NCSettingsBundleHelper.swift b/iOSClient/Settings/NCSettingsBundleHelper.swift index 055cda5f1..204288d7c 100644 --- a/iOSClient/Settings/NCSettingsBundleHelper.swift +++ b/iOSClient/Settings/NCSettingsBundleHelper.swift @@ -24,7 +24,7 @@ import Foundation class NCSettingsBundleHelper: NSObject { - + @objc class func setVersionAndBuildNumber() { let version = NCUtility.shared.getVersionApp() as String UserDefaults.standard.set(version, forKey: "version_preference") diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index 707727413..b43ce3e48 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -47,51 +47,51 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingD @IBOutlet weak var buttonCopy: UIButton! @IBOutlet weak var buttonMenu: UIButton! @IBOutlet weak var tableView: UITableView! - + private let appDelegate = UIApplication.shared.delegate as! AppDelegate public var metadata: tableMetadata? public var sharingEnabled = true public var height: CGFloat = 0 - + private var shareLinkMenuView: NCShareLinkMenuView? private var shareUserMenuView: NCShareUserMenuView? private var shareMenuViewWindow: UIView? private var dropDown = DropDown() private var networking: NCShareNetworking? - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + view.backgroundColor = NCBrandColor.shared.systemBackground viewContainerConstraint.constant = height searchFieldTopConstraint.constant = 10 - + searchField.placeholder = NSLocalizedString("_shareLinksearch_placeholder_", comment: "") - + shareLinkImage.image = NCShareCommon.shared.createLinkAvatar(imageName: "sharebylink", colorCircle: NCBrandColor.shared.brandElement) shareLinkLabel.text = NSLocalizedString("_share_link_", comment: "") shareLinkLabel.textColor = NCBrandColor.shared.label - buttonCopy.setImage(UIImage.init(named: "shareCopy")?.image(color: .gray, size: 50), for: .normal) + buttonCopy.setImage(UIImage(named: "shareCopy")?.image(color: .gray, size: 50), for: .normal) shareInternalLinkImage.image = NCShareCommon.shared.createLinkAvatar(imageName: "shareInternalLink", colorCircle: .gray) shareInternalLinkLabel.text = NSLocalizedString("_share_internal_link_", comment: "") shareInternalLinkDescription.text = NSLocalizedString("_share_internal_link_des_", comment: "") - buttonInternalCopy.setImage(UIImage.init(named: "shareCopy")?.image(color: .gray, size: 50), for: .normal) + buttonInternalCopy.setImage(UIImage(named: "shareCopy")?.image(color: .gray, size: 50), for: .normal) tableView.dataSource = self tableView.delegate = self tableView.allowsSelection = false tableView.backgroundColor = NCBrandColor.shared.systemBackground - tableView.register(UINib.init(nibName: "NCShareLinkCell", bundle: nil), forCellReuseIdentifier: "cellLink") - tableView.register(UINib.init(nibName: "NCShareUserCell", bundle: nil), forCellReuseIdentifier: "cellUser") - + tableView.register(UINib(nibName: "NCShareLinkCell", bundle: nil), forCellReuseIdentifier: "cellLink") + tableView.register(UINib(nibName: "NCShareUserCell", bundle: nil), forCellReuseIdentifier: "cellUser") + NotificationCenter.default.addObserver(self, selector: #selector(reloadData), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataNCShare), object: nil) - + // Shared with you by ... if let metadata = metadata, !metadata.ownerId.isEmpty, metadata.ownerId != self.appDelegate.userId { @@ -119,7 +119,6 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingD sharedWithYouByNoteImage.isHidden = true sharedWithYouByNote.isHidden = true } - let fileName = appDelegate.userBaseUrl + "-" + metadata.ownerId + ".png" @@ -127,49 +126,49 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingD let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName let etag = NCManageDatabase.shared.getTableAvatar(fileName: fileName)?.etag - NCCommunication.shared.downloadAvatar(user: metadata.ownerId, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: etag) { (account, imageAvatar, imageOriginal, etag, errorCode, errorMessage) in - + NCCommunication.shared.downloadAvatar(user: metadata.ownerId, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: etag) { _, imageAvatar, _, etag, errorCode, _ in + if errorCode == 0, let etag = etag, let imageAvatar = imageAvatar { - + NCManageDatabase.shared.addAvatar(fileName: fileName, etag: etag) self.sharedWithYouByImage.image = imageAvatar - + } else if errorCode == NCGlobal.shared.errorNotModified, let imageAvatar = NCManageDatabase.shared.setAvatarLoaded(fileName: fileName) { - + self.sharedWithYouByImage.image = imageAvatar } } } } - + reloadData() - + networking = NCShareNetworking(metadata: metadata!, urlBase: appDelegate.urlBase, view: self.view, delegate: self) if sharingEnabled { let isVisible = (self.navigationController?.topViewController as? NCSharePaging)?.indexPage == .sharing networking?.readShare(showLoadingIndicator: isVisible) } - + // changeTheming NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(changePermissions(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterShareChangePermissions), object: nil) - + changeTheming() } - + // MARK: - Notification Center - + @objc func openShareProfile() { guard let metadata = metadata else { return } self.showProfileMenu(userId: metadata.ownerId) } - + @objc func changeTheming() { tableView.reloadData() } - + @objc func changePermissions(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let idShare = userInfo["idShare"] as? Int, let permissions = userInfo["permissions"] as? Int, let hideDownload = userInfo["hideDownload"] as? Bool { networking?.updateShare(idShare: idShare, password: nil, permissions: permissions, note: nil, label: nil, expirationDate: nil, hideDownload: hideDownload) @@ -178,16 +177,16 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingD } // MARK: - - + @objc func reloadData() { let shares = NCManageDatabase.shared.getTableShares(metadata: metadata!) if shares.firstShareLink == nil { - buttonMenu.setImage(UIImage.init(named: "shareAdd")?.image(color: .gray, size: 50), for: .normal) + buttonMenu.setImage(UIImage(named: "shareAdd")?.image(color: .gray, size: 50), for: .normal) buttonCopy.isHidden = true } else { - buttonMenu.setImage(UIImage.init(named: "shareMenu")?.image(color: .gray, size: 50), for: .normal) + buttonMenu.setImage(UIImage(named: "shareMenu")?.image(color: .gray, size: 50), for: .normal) buttonCopy.isHidden = false - + shareLinkLabel.text = NSLocalizedString("_share_link_", comment: "") if shares.firstShareLink?.label.count ?? 0 > 0 { if let shareLinkLabel = shareLinkLabel { @@ -199,30 +198,30 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingD } tableView.reloadData() } - + // MARK: - IBAction @IBAction func searchFieldDidEndOnExit(textField: UITextField) { - + guard let searchString = textField.text else { return } networking?.getSharees(searchString: searchString) } - + @IBAction func touchUpInsideButtonCopy(_ sender: Any) { - + guard let metadata = self.metadata else { return } let shares = NCManageDatabase.shared.getTableShares(metadata: metadata) tapCopy(with: shares.firstShareLink, sender: sender) } - + @IBAction func touchUpInsideButtonCopyInernalLink(_ sender: Any) { - + guard let metadata = self.metadata else { return } - + let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName - NCNetworking.shared.readFile(serverUrlFileName: serverUrlFileName, account: metadata.account) { (account, metadata, errorCode, errorDescription) in + NCNetworking.shared.readFile(serverUrlFileName: serverUrlFileName, account: metadata.account, queue: .main) { _, metadata, errorCode, errorDescription in if errorCode == 0 && metadata != nil { let internalLink = self.appDelegate.urlBase + "/index.php/f/" + metadata!.fileId NCShareCommon.shared.copyLink(link: internalLink, viewController: self, sender: sender) @@ -231,34 +230,41 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingD } } } + + func checkEnforcedPassword(callback: @escaping (String?) -> Void) { + guard let metadata = self.metadata, + NCManageDatabase.shared.getCapabilitiesServerBool(account: metadata.account, elements: NCElementsJSON.shared.capabilitiesFileSharingPubPasswdEnforced, exists: false) + else { return callback(nil) } + + let alertController = UIAlertController(title: NSLocalizedString("_enforce_password_protection_", comment: ""), message: "", preferredStyle: .alert) + alertController.addTextField { textField in + textField.isSecureTextEntry = true + } + alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .default) { _ in }) + let okAction = UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default) { _ in + let password = alertController.textFields?.first?.text + callback(password) + } + + alertController.addAction(okAction) + + self.present(alertController, animated: true, completion:nil) + } @IBAction func touchUpInsideButtonMenu(_ sender: Any) { guard let metadata = self.metadata else { return } - let isFilesSharingPublicPasswordEnforced = NCManageDatabase.shared.getCapabilitiesServerBool(account: metadata.account, elements: NCElementsJSON.shared.capabilitiesFileSharingPubPasswdEnforced, exists: false) let shares = NCManageDatabase.shared.getTableShares(metadata: metadata) - if isFilesSharingPublicPasswordEnforced && shares.firstShareLink == nil { - let alertController = UIAlertController(title: NSLocalizedString("_enforce_password_protection_", comment: ""), message: "", preferredStyle: .alert) - alertController.addTextField { (textField) in - textField.isSecureTextEntry = true - } - alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .default) { (action:UIAlertAction) in }) - let okAction = UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default) { (action:UIAlertAction) in - let password = alertController.textFields?.first?.text - self.networking?.createShareLink(password: password ?? "") + if shares.firstShareLink == nil { + checkEnforcedPassword { password in + self.networking?.createShareLink(password: password) } - - alertController.addAction(okAction) - - self.present(alertController, animated: true, completion:nil) - } else if shares.firstShareLink == nil { - networking?.createShareLink(password: "") } else { tapMenu(with: shares.firstShareLink!, sender: sender) } } - + @objc func tapLinkMenuViewWindow(gesture: UITapGestureRecognizer) { shareLinkMenuView?.unLoad() shareLinkMenuView = nil @@ -271,28 +277,28 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingD } // MARK: - NCShareNetworkingDelegate - + func readShareCompleted() { NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare) } - + func shareCompleted() { NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare) } - + func unShareCompleted() { } - + func updateShareWithError(idShare: Int) { self.reloadData() } - + func getSharees(sharees: [NCCommunicationSharee]?) { - + guard let sharees = sharees else { return } dropDown = DropDown() let appearance = DropDown.appearance() - + appearance.backgroundColor = NCBrandColor.shared.systemBackground appearance.cornerRadius = 10 appearance.shadowColor = UIColor(white: 0.5, alpha: 1) @@ -301,22 +307,22 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingD appearance.animationduration = 0.25 appearance.textColor = .darkGray appearance.setupMaskedCorners([.layerMaxXMaxYCorner, .layerMinXMaxYCorner]) - + for sharee in sharees { var label = sharee.label if sharee.shareType == NCShareCommon.shared.SHARE_TYPE_CIRCLE { - label = label + " (" + sharee.circleInfo + ", " + sharee.circleOwner + ")" + label += " (" + sharee.circleInfo + ", " + sharee.circleOwner + ")" } dropDown.dataSource.append(label) } - + dropDown.anchorView = searchField dropDown.bottomOffset = CGPoint(x: 0, y: searchField.bounds.height) dropDown.width = searchField.bounds.width dropDown.direction = .bottom - + dropDown.cellNib = UINib(nibName: "NCShareUserDropDownCell", bundle: nil) - dropDown.customCellConfiguration = { (index: Index, item: String, cell: DropDownCell) -> Void in + dropDown.customCellConfiguration = { (index: Index, _: String, cell: DropDownCell) -> Void in guard let cell = cell as? NCShareUserDropDownCell else { return } let sharee = sharees[index] cell.imageItem.image = NCShareCommon.shared.getImageShareType(shareType: sharee.shareType) @@ -340,26 +346,28 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingD let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName let etag = NCManageDatabase.shared.getTableAvatar(fileName: fileName)?.etag - NCCommunication.shared.downloadAvatar(user: sharee.shareWith, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: etag) { (account, imageAvatar, imageOriginal, etag, errorCode, errorMessage) in - + NCCommunication.shared.downloadAvatar(user: sharee.shareWith, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: etag) { _, imageAvatar, _, etag, errorCode, _ in + if errorCode == 0, let etag = etag, let imageAvatar = imageAvatar { - + NCManageDatabase.shared.addAvatar(fileName: fileName, etag: etag) cell.imageItem.image = imageAvatar - + } else if errorCode == NCGlobal.shared.errorNotModified, let imageAvatar = NCManageDatabase.shared.setAvatarLoaded(fileName: fileName) { - + cell.imageItem.image = imageAvatar } } } } - - dropDown.selectionAction = { [weak self] (index, item) in + + dropDown.selectionAction = { (index, item) in let sharee = sharees[index] - self!.networking?.createShare(shareWith: sharee.shareWith, shareType: sharee.shareType, metadata: self!.metadata!) + self.checkEnforcedPassword { password in + self.networking?.createShare(shareWith: sharee.shareWith, shareType: sharee.shareType, password: password, metadata: self.metadata!) + } } - + dropDown.show() } } @@ -367,7 +375,7 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingD // MARK: - UITableViewDelegate extension NCShare: UITableViewDelegate { - + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 70 } @@ -376,28 +384,28 @@ extension NCShare: UITableViewDelegate { // MARK: - UITableViewDataSource extension NCShare: UITableViewDataSource { - + func numberOfSections(in tableView: UITableView) -> Int { return 1 } - + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - + var numOfRows = 0 let shares = NCManageDatabase.shared.getTableShares(metadata: metadata!) - + if shares.share != nil { numOfRows = shares.share!.count } - + return numOfRows } - + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - + let shares = NCManageDatabase.shared.getTableShares(metadata: metadata!) let tableShare = shares.share![indexPath.row] - + // LINK if tableShare.shareType == 3 { if let cell = tableView.dequeueReusableCell(withIdentifier: "cellLink", for: indexPath) as? NCShareLinkCell { @@ -413,7 +421,7 @@ extension NCShare: UITableViewDataSource { } else { // USER if let cell = tableView.dequeueReusableCell(withIdentifier: "cellUser", for: indexPath) as? NCShareUserCell { - + cell.tableShare = tableShare cell.delegate = self cell.labelTitle.text = tableShare.shareWithDisplayname @@ -423,15 +431,15 @@ extension NCShare: UITableViewDataSource { cell.imageDownArrow.isHidden = false cell.buttonMenu.isHidden = false cell.imageItem.image = NCShareCommon.shared.getImageShareType(shareType: tableShare.shareType) - + let status = NCUtility.shared.getUserStatus(userIcon: tableShare.userIcon, userStatus: tableShare.userStatus, userMessage: tableShare.userMessage) cell.imageStatus.image = status.onlineStatus cell.status.text = status.statusMessage - + let fileName = appDelegate.userBaseUrl + "-" + tableShare.shareWith + ".png" - + NCOperationQueue.shared.downloadAvatar(user: tableShare.shareWith, dispalyName: tableShare.shareWithDisplayname, fileName: fileName, cell: cell, view: tableView) - + // If the initiator or the recipient is not the current user, show the list of sharees without any options to edit it. if tableShare.uidOwner != self.appDelegate.userId && tableShare.uidFileOwner != self.appDelegate.userId { cell.isUserInteractionEnabled = false @@ -439,10 +447,10 @@ extension NCShare: UITableViewDataSource { cell.imageDownArrow.isHidden = true cell.buttonMenu.isHidden = true } - + cell.btnQuickStatus.setTitle("", for: .normal) cell.btnQuickStatus.contentHorizontalAlignment = .left - + if tableShare.permissions == NCGlobal.shared.permissionCreateShare { cell.labelQuickStatus.text = NSLocalizedString("_share_file_drop_", comment: "") } else { @@ -457,7 +465,7 @@ extension NCShare: UITableViewDataSource { return cell } } - + return UITableViewCell() } } @@ -466,21 +474,21 @@ extension NCShare: UITableViewDataSource { extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate { func tapCopy(with tableShare: tableShare?, sender: Any) { - + if let link = tableShare?.url { NCShareCommon.shared.copyLink(link: link, viewController: self, sender: sender) } } func tapMenu(with tableShare: tableShare?, sender: Any) { - + guard let tableShare = tableShare else { return } if tableShare.shareType == 3 { let views = NCShareCommon.shared.openViewMenuShareLink(shareViewController: self, tableShare: tableShare, metadata: metadata!) shareLinkMenuView = views.shareLinkMenuView shareMenuViewWindow = views.viewWindow - + let tap = UITapGestureRecognizer(target: self, action: #selector(tapLinkMenuViewWindow)) tap.delegate = self shareMenuViewWindow?.addGestureRecognizer(tap) @@ -488,7 +496,7 @@ extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate { let views = NCShareCommon.shared.openViewMenuUser(shareViewController: self, tableShare: tableShare, metadata: metadata!) shareUserMenuView = views.shareUserMenuView shareMenuViewWindow = views.viewWindow - + let tap = UITapGestureRecognizer(target: self, action: #selector(tapLinkMenuViewWindow)) tap.delegate = self shareMenuViewWindow?.addGestureRecognizer(tap) diff --git a/iOSClient/Share/NCShareCommentsCell.swift b/iOSClient/Share/NCShareCommentsCell.swift index 2c45c929e..36a31aae7 100644 --- a/iOSClient/Share/NCShareCommentsCell.swift +++ b/iOSClient/Share/NCShareCommentsCell.swift @@ -27,23 +27,23 @@ import NCCommunication // MARK: - NCShareCommentsCell class NCShareCommentsCell: UITableViewCell, NCCellProtocol { - + @IBOutlet weak var imageItem: UIImageView! @IBOutlet weak var labelUser: UILabel! @IBOutlet weak var buttonMenu: UIButton! @IBOutlet weak var labelDate: UILabel! @IBOutlet weak var labelMessage: UILabel! - + var tableComments: tableComments? - var delegate: NCShareCommentsCellDelegate? - - var filePreviewImageView : UIImageView? { - get{ + weak var delegate: NCShareCommentsCellDelegate? + + var filePreviewImageView: UIImageView? { + get { return nil } } var fileAvatarImageView: UIImageView? { - get{ + get { return imageItem } } @@ -53,19 +53,19 @@ class NCShareCommentsCell: UITableViewCell, NCCellProtocol { } } var fileUser: String? { - get{ + get { return tableComments?.actorId } } - + override func awakeFromNib() { super.awakeFromNib() - - buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: .lightGray, size: 50), for: .normal) + + buttonMenu.setImage(UIImage(named: "shareMenu")!.image(color: .lightGray, size: 50), for: .normal) let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAvatarImage)) imageItem?.addGestureRecognizer(tapGesture) } - + @objc func tapAvatarImage(_ sender: UITapGestureRecognizer) { self.delegate?.showProfile(with: tableComments, sender: sender) } @@ -75,7 +75,7 @@ class NCShareCommentsCell: UITableViewCell, NCCellProtocol { } } -protocol NCShareCommentsCellDelegate { +protocol NCShareCommentsCellDelegate: AnyObject { func tapMenu(with tableComments: tableComments?, sender: Any) func showProfile(with tableComment: tableComments?, sender: Any) } diff --git a/iOSClient/Share/NCShareCommon.swift b/iOSClient/Share/NCShareCommon.swift index fd05d0ff7..54ad9d29d 100644 --- a/iOSClient/Share/NCShareCommon.swift +++ b/iOSClient/Share/NCShareCommon.swift @@ -29,7 +29,7 @@ class NCShareCommon: NSObject { let instance = NCShareCommon() return instance }() - + let SHARE_TYPE_USER = 0 let SHARE_TYPE_GROUP = 1 let SHARE_TYPE_LINK = 3 @@ -40,24 +40,24 @@ class NCShareCommon: NSObject { let SHARE_TYPE_GUEST = 8 let SHARE_TYPE_REMOTE_GROUP = 9 let SHARE_TYPE_ROOM = 10 - + func createLinkAvatar(imageName: String, colorCircle: UIColor) -> UIImage? { - + let size: CGFloat = 200 - - let bottomImage = UIImage.init(named: "circle.fill")!.image(color: colorCircle, size: size/2) - let topImage = UIImage.init(named: imageName)!.image(color: .white, size: size/2) + + let bottomImage = UIImage(named: "circle.fill")!.image(color: colorCircle, size: size/2) + let topImage = UIImage(named: imageName)!.image(color: .white, size: size/2) UIGraphicsBeginImageContextWithOptions(CGSize(width: size, height: size), false, UIScreen.main.scale) bottomImage.draw(in: CGRect(origin: CGPoint.zero, size: CGSize(width: size, height: size))) - topImage.draw(in: CGRect(origin: CGPoint(x: size/4, y: size/4), size: CGSize(width: size/2, height: size/2))) + topImage.draw(in: CGRect(origin: CGPoint(x: size/4, y: size/4), size: CGSize(width: size/2, height: size/2))) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() - + return image } - + func openViewMenuShareLink(shareViewController: NCShare, tableShare: tableShare?, metadata: tableMetadata) -> (shareLinkMenuView: NCShareLinkMenuView, viewWindow: UIView) { - + var shareLinkMenuView: NCShareLinkMenuView let window = UIApplication.shared.keyWindow! let viewWindow = UIView(frame: window.bounds) @@ -70,14 +70,14 @@ class NCShareCommon: NSObject { } else { shareLinkMenuView = Bundle.main.loadNibNamed("NCShareLinkMenuView", owner: self, options: nil)?.first as! NCShareLinkMenuView } - + shareLinkMenuView.width = 250 if metadata.directory { shareLinkMenuView.height = 600 } else { shareLinkMenuView.height = 500 } - + shareLinkMenuView.backgroundColor = NCBrandColor.shared.systemBackground shareLinkMenuView.metadata = metadata shareLinkMenuView.viewWindow = viewWindow @@ -85,19 +85,19 @@ class NCShareCommon: NSObject { shareLinkMenuView.reloadData(idShare: tableShare?.idShare ?? 0) shareLinkMenuView.translatesAutoresizingMaskIntoConstraints = false viewWindow.addSubview(shareLinkMenuView) - + NSLayoutConstraint.activate([ shareLinkMenuView.widthAnchor.constraint(equalToConstant: shareLinkMenuView.width), shareLinkMenuView.heightAnchor.constraint(equalToConstant: shareLinkMenuView.height), shareLinkMenuView.centerXAnchor.constraint(equalTo: viewWindow.centerXAnchor), - shareLinkMenuView.centerYAnchor.constraint(equalTo: viewWindow.centerYAnchor), + shareLinkMenuView.centerYAnchor.constraint(equalTo: viewWindow.centerYAnchor) ]) - + return(shareLinkMenuView: shareLinkMenuView, viewWindow: viewWindow) } - + func openViewMenuUser(shareViewController: NCShare, tableShare: tableShare?, metadata: tableMetadata) -> (shareUserMenuView: NCShareUserMenuView, viewWindow: UIView) { - + var shareUserMenuView: NCShareUserMenuView let window = UIApplication.shared.keyWindow! let viewWindow = UIView(frame: window.bounds) @@ -110,14 +110,14 @@ class NCShareCommon: NSObject { } else { shareUserMenuView = Bundle.main.loadNibNamed("NCShareUserMenuView", owner: self, options: nil)?.first as! NCShareUserMenuView } - + shareUserMenuView.width = 250 if metadata.directory { shareUserMenuView.height = 420 } else { shareUserMenuView.height = 270 } - + shareUserMenuView.backgroundColor = NCBrandColor.shared.systemBackground shareUserMenuView.metadata = metadata shareUserMenuView.viewWindow = viewWindow @@ -130,22 +130,22 @@ class NCShareCommon: NSObject { shareUserMenuView.widthAnchor.constraint(equalToConstant: shareUserMenuView.width), shareUserMenuView.heightAnchor.constraint(equalToConstant: shareUserMenuView.height), shareUserMenuView.centerXAnchor.constraint(equalTo: viewWindow.centerXAnchor), - shareUserMenuView.centerYAnchor.constraint(equalTo: viewWindow.centerYAnchor), + shareUserMenuView.centerYAnchor.constraint(equalTo: viewWindow.centerYAnchor) ]) - + return(shareUserMenuView: shareUserMenuView, viewWindow: viewWindow) } - + func openCalendar(view: UIView, width: CGFloat, height: CGFloat) -> (calendarView: FSCalendar, viewWindow: UIView) { - + let globalPoint = view.superview?.convert(view.frame.origin, to: nil) - + let window = UIApplication.shared.keyWindow! let viewWindow = UIView(frame: window.bounds) window.addSubview(viewWindow) - + let calendar = FSCalendar(frame: CGRect(x: globalPoint!.x + 10, y: globalPoint!.y + 10, width: width - 20, height: 300)) - + if #available(iOS 13.0, *) { calendar.appearance.headerTitleColor = .label } else { @@ -154,7 +154,7 @@ class NCShareCommon: NSObject { calendar.backgroundColor = NCBrandColor.shared.systemBackground calendar.placeholderType = .none calendar.appearance.headerMinimumDissolvedAlpha = 0.0 - + calendar.layer.borderColor = UIColor.lightGray.cgColor calendar.layer.borderWidth = 0.5 calendar.layer.masksToBounds = false @@ -162,20 +162,20 @@ class NCShareCommon: NSObject { calendar.layer.masksToBounds = false calendar.layer.shadowOffset = CGSize(width: 2, height: 2) calendar.layer.shadowOpacity = 0.2 - + calendar.appearance.headerTitleFont = UIFont.systemFont(ofSize: 13) - + calendar.appearance.weekdayTextColor = NCBrandColor.shared.gray calendar.appearance.weekdayFont = UIFont.systemFont(ofSize: 13) - + calendar.appearance.todayColor = NCBrandColor.shared.brandElement calendar.appearance.titleFont = UIFont.systemFont(ofSize: 13) - + viewWindow.addSubview(calendar) - + return(calendarView: calendar, viewWindow: viewWindow) } - + func copyLink(link: String, viewController: UIViewController, sender: Any) { let objectsToShare = [link] @@ -190,9 +190,9 @@ class NCShareCommon: NSObject { viewController.present(activityViewController, animated: true, completion: nil) } - + func getImageShareType(shareType: Int) -> UIImage? { - + switch shareType { case SHARE_TYPE_USER: return UIImage(named: "shareTypeUser")?.imageColor(NCBrandColor.shared.label) diff --git a/iOSClient/Share/NCShareLinkCell.swift b/iOSClient/Share/NCShareLinkCell.swift index a5422b872..7468b78ba 100644 --- a/iOSClient/Share/NCShareLinkCell.swift +++ b/iOSClient/Share/NCShareLinkCell.swift @@ -20,40 +20,38 @@ // 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 - class NCShareLinkCell: UITableViewCell { - + @IBOutlet weak var imageItem: UIImageView! @IBOutlet weak var labelTitle: UILabel! @IBOutlet weak var buttonCopy: UIButton! @IBOutlet weak var buttonMenu: UIButton! - + private let iconShare: CGFloat = 200 - + var tableShare: tableShare? - var delegate: NCShareLinkCellDelegate? - + weak var delegate: NCShareLinkCellDelegate? + override func awakeFromNib() { super.awakeFromNib() - + imageItem.image = NCShareCommon.shared.createLinkAvatar(imageName: "sharebylink", colorCircle: NCBrandColor.shared.brandElement) - buttonCopy.setImage(UIImage.init(named: "shareCopy")!.image(color: .gray, size: 50), for: .normal) - buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: .gray, size: 50), for: .normal) + buttonCopy.setImage(UIImage(named: "shareCopy")!.image(color: .gray, size: 50), for: .normal) + buttonMenu.setImage(UIImage(named: "shareMenu")!.image(color: .gray, size: 50), for: .normal) } - + @IBAction func touchUpInsideCopy(_ sender: Any) { delegate?.tapCopy(with: tableShare, sender: sender) } - + @IBAction func touchUpInsideMenu(_ sender: Any) { delegate?.tapMenu(with: tableShare, sender: sender) } } -protocol NCShareLinkCellDelegate { +protocol NCShareLinkCellDelegate: AnyObject { func tapCopy(with tableShare: tableShare?, sender: Any) func tapMenu(with tableShare: tableShare?, sender: Any) } diff --git a/iOSClient/Share/NCShareLinkMenuView.swift b/iOSClient/Share/NCShareLinkMenuView.swift index 5a6093e69..19993dc42 100644 --- a/iOSClient/Share/NCShareLinkMenuView.swift +++ b/iOSClient/Share/NCShareLinkMenuView.swift @@ -25,54 +25,54 @@ import FSCalendar import NCCommunication class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDelegate, NCShareNetworkingDelegate, FSCalendarDelegate, FSCalendarDelegateAppearance { - + @IBOutlet weak var fieldLabel: UITextField! @IBOutlet weak var switchAllowEditing: UISwitch! @IBOutlet weak var labelAllowEditing: UILabel! - + @IBOutlet weak var switchReadOnly: UISwitch! @IBOutlet weak var labelReadOnly: UILabel! - + @IBOutlet weak var switchAllowUploadAndEditing: UISwitch! @IBOutlet weak var labelAllowUploadAndEditing: UILabel! - + @IBOutlet weak var switchFileDrop: UISwitch! @IBOutlet weak var labelFileDrop: UILabel! - + @IBOutlet weak var switchHideDownload: UISwitch! @IBOutlet weak var labelHideDownload: UILabel! - + @IBOutlet weak var switchPasswordProtect: UISwitch! @IBOutlet weak var labelPasswordProtect: UILabel! @IBOutlet weak var fieldPasswordProtect: UITextField! - + @IBOutlet weak var switchSetExpirationDate: UISwitch! @IBOutlet weak var labelSetExpirationDate: UILabel! @IBOutlet weak var fieldSetExpirationDate: UITextField! - + @IBOutlet weak var imageNoteToRecipient: UIImageView! @IBOutlet weak var labelNoteToRecipient: UILabel! @IBOutlet weak var fieldNoteToRecipient: UITextField! - + @IBOutlet weak var buttonDeleteShareLink: UIButton! @IBOutlet weak var labelDeleteShareLink: UILabel! @IBOutlet weak var imageDeleteShareLink: UIImageView! - + @IBOutlet weak var buttonAddAnotherLink: UIButton! @IBOutlet weak var labelAddAnotherLink: UILabel! @IBOutlet weak var imageAddAnotherLink: UIImageView! - + private let appDelegate = UIApplication.shared.delegate as! AppDelegate - + var width: CGFloat = 0 var height: CGFloat = 0 - + private var tableShare: tableShare? var metadata: tableMetadata? var shareViewController: NCShare? private var networking: NCShareNetworking? - + var viewWindow: UIView? var viewWindowCalendar: UIView? private var calendar: FSCalendar? @@ -80,14 +80,14 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg private var activeTextField = UITextField() override func awakeFromNib() { - + layer.borderColor = UIColor.lightGray.cgColor layer.borderWidth = 0.5 layer.cornerRadius = 5 layer.masksToBounds = false layer.shadowOffset = CGSize(width: 2, height: 2) layer.shadowOpacity = 0.2 - + fieldLabel?.placeholder = NSLocalizedString("_Link_name_", comment: "") switchAllowEditing?.transform = CGAffineTransform(scaleX: 0.75, y: 0.75) @@ -104,7 +104,7 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg switchPasswordProtect.onTintColor = NCBrandColor.shared.brandElement switchSetExpirationDate.transform = CGAffineTransform(scaleX: 0.75, y: 0.75) switchSetExpirationDate.onTintColor = NCBrandColor.shared.brandElement - + labelAllowEditing?.text = NSLocalizedString("_share_allow_editing_", comment: "") labelAllowEditing?.textColor = NCBrandColor.shared.label labelReadOnly?.text = NSLocalizedString("_share_read_only_", comment: "") @@ -125,43 +125,43 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg labelDeleteShareLink?.textColor = NCBrandColor.shared.label labelAddAnotherLink?.text = NSLocalizedString("_share_add_sharelink_", comment: "") labelAddAnotherLink?.textColor = NCBrandColor.shared.label - + fieldSetExpirationDate.inputView = UIView() - + fieldLabel.delegate = self fieldPasswordProtect.delegate = self fieldNoteToRecipient.delegate = self - - imageNoteToRecipient.image = UIImage.init(named: "file_txt")!.image(color: NCBrandColor.shared.gray, size: 50) + + imageNoteToRecipient.image = UIImage(named: "file_txt")!.image(color: NCBrandColor.shared.gray, size: 50) imageDeleteShareLink.image = NCUtility.shared.loadImage(named: "trash", color: NCBrandColor.shared.gray, size: 50) imageAddAnotherLink.image = NCUtility.shared.loadImage(named: "plus", color: NCBrandColor.shared.gray, size: 50) - + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) } - + override func willMove(toWindow newWindow: UIWindow?) { super.willMove(toWindow: newWindow) - + if newWindow == nil { // UIView disappear shareViewController?.reloadData() } else { // UIView appear - networking = NCShareNetworking.init(metadata: metadata!, urlBase: appDelegate.urlBase, view: self, delegate: self) + networking = NCShareNetworking(metadata: metadata!, urlBase: appDelegate.urlBase, view: self, delegate: self) } } - + func unLoad() { viewWindowCalendar?.removeFromSuperview() viewWindow?.removeFromSuperview() - + viewWindowCalendar = nil viewWindow = nil } - + func reloadData(idShare: Int) { - + guard let metadata = self.metadata else { return } tableShare = NCManageDatabase.shared.getTableShare(account: metadata.account, idShare: idShare) guard let tableShare = self.tableShare else { return } @@ -194,14 +194,14 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg switchAllowEditing.setOn(false, animated: false) } } - + // Hide download if tableShare.hideDownload { switchHideDownload.setOn(true, animated: false) } else { switchHideDownload.setOn(false, animated: false) } - + // Password protect if tableShare.shareWith.count > 0 { switchPasswordProtect.setOn(true, animated: false) @@ -212,12 +212,12 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg fieldPasswordProtect.isEnabled = false fieldPasswordProtect.text = "" } - + // Set expiration date if tableShare.expirationDate != nil { switchSetExpirationDate.setOn(true, animated: false) fieldSetExpirationDate.isEnabled = true - + let dateFormatter = DateFormatter() dateFormatter.formatterBehavior = .behavior10_4 dateFormatter.dateStyle = .medium @@ -227,22 +227,22 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg fieldSetExpirationDate.isEnabled = false fieldSetExpirationDate.text = "" } - + // Note to recipient fieldNoteToRecipient.text = tableShare.note } - + func textFieldDidBeginEditing(_ textField: UITextField) { - + self.activeTextField = textField } - + // MARK: - Keyboard notification - - @objc internal func keyboardWillShow(_ notification : Notification?) { - + + @objc internal func keyboardWillShow(_ notification: Notification?) { + activeTextfieldDiff = 0 - + if let info = notification?.userInfo, let centerObject = self.activeTextField.superview?.convert(self.activeTextField.center, to: nil) { let frameEndUserInfoKey = UIResponder.keyboardFrameEndUserInfoKey @@ -255,49 +255,49 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg } } } - + @objc func keyboardWillHide(_ notification: Notification) { self.frame.origin.y -= activeTextfieldDiff } - + // MARK: - Tap viewWindowCalendar - + @objc func tapViewWindowCalendar(gesture: UITapGestureRecognizer) { calendar?.removeFromSuperview() viewWindowCalendar?.removeFromSuperview() - + calendar = nil viewWindowCalendar = nil - + reloadData(idShare: tableShare?.idShare ?? 0) } - + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { return gestureRecognizer.view == touch.view } - + // MARK: - IBAction // Allow editing (file) @IBAction func switchAllowEditingChanged(sender: UISwitch) { - + guard let tableShare = self.tableShare else { return } guard let metadata = self.metadata else { return } var permissions: Int = 0 - + if sender.isOn { permissions = CCUtility.getPermissionsValue(byCanEdit: true, andCanCreate: true, andCanChange: true, andCanDelete: true, andCanShare: false, andIsFolder: metadata.directory) } else { permissions = CCUtility.getPermissionsValue(byCanEdit: false, andCanCreate: false, andCanChange: false, andCanDelete: false, andCanShare: false, andIsFolder: metadata.directory) } - + networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: permissions, note: nil, label: nil, expirationDate: nil, hideDownload: tableShare.hideDownload) } - + // Read Only (directory) @IBAction func switchReadOnly(sender: UISwitch) { - + guard let tableShare = self.tableShare else { return } guard let metadata = self.metadata else { return } let permissions = CCUtility.getPermissionsValue(byCanEdit: false, andCanCreate: false, andCanChange: false, andCanDelete: false, andCanShare: false, andIsFolder: metadata.directory) @@ -310,10 +310,10 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg sender.setOn(true, animated: false) } } - + // Allow Upload And Editing (directory) @IBAction func switchAllowUploadAndEditing(sender: UISwitch) { - + guard let tableShare = self.tableShare else { return } guard let metadata = self.metadata else { return } let permissions = CCUtility.getPermissionsValue(byCanEdit: true, andCanCreate: true, andCanChange: true, andCanDelete: true, andCanShare: false, andIsFolder: metadata.directory) @@ -326,10 +326,10 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg sender.setOn(true, animated: false) } } - + // File Drop (directory) @IBAction func switchFileDrop(sender: UISwitch) { - + guard let tableShare = self.tableShare else { return } let permissions = NCGlobal.shared.permissionCreateShare @@ -341,20 +341,20 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg sender.setOn(true, animated: false) } } - + // Hide download @IBAction func switchHideDownloadChanged(sender: UISwitch) { - + guard let tableShare = self.tableShare else { return } - + networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: tableShare.permissions, note: nil, label: nil, expirationDate: nil, hideDownload: sender.isOn) } - + // Password protect @IBAction func switchPasswordProtectChanged(sender: UISwitch) { - + guard let tableShare = self.tableShare else { return } - + if sender.isOn { fieldPasswordProtect.isEnabled = true fieldPasswordProtect.text = "" @@ -363,17 +363,17 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg networking?.updateShare(idShare: tableShare.idShare, password: "", permissions: tableShare.permissions, note: nil, label: nil, expirationDate: nil, hideDownload: tableShare.hideDownload) } } - + @IBAction func fieldPasswordProtectDidEndOnExit(textField: UITextField) { - + guard let tableShare = self.tableShare else { return } - + networking?.updateShare(idShare: tableShare.idShare, password: fieldPasswordProtect.text, permissions: tableShare.permissions, note: nil, label: nil, expirationDate: nil, hideDownload: tableShare.hideDownload) } - + // Set expiration date @IBAction func switchSetExpirationDate(sender: UISwitch) { - + guard let tableShare = self.tableShare else { return } if sender.isOn { @@ -383,101 +383,101 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: tableShare.permissions, note: nil, label: nil, expirationDate: "", hideDownload: tableShare.hideDownload) } } - + @IBAction func fieldSetExpirationDate(sender: UITextField) { - + let calendar = NCShareCommon.shared.openCalendar(view: self, width: width, height: height) calendar.calendarView.delegate = self self.calendar = calendar.calendarView viewWindowCalendar = calendar.viewWindow - + let tap = UITapGestureRecognizer(target: self, action: #selector(tapViewWindowCalendar)) tap.delegate = self viewWindowCalendar?.addGestureRecognizer(tap) } - + // Note to recipient @IBAction func fieldNoteToRecipientDidEndOnExit(textField: UITextField) { - + guard let tableShare = self.tableShare else { return } if fieldNoteToRecipient.text == nil { return } - + networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: tableShare.permissions, note: fieldNoteToRecipient.text, label: nil, expirationDate: nil, hideDownload: tableShare.hideDownload) } - + // Label @IBAction func fielLabelDidEndOnExit(textField: UITextField) { - + guard let tableShare = self.tableShare else { return } if fieldLabel.text == nil { return } - + networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: tableShare.permissions, note: nil, label: fieldLabel.text, expirationDate: nil, hideDownload: tableShare.hideDownload) } - + // Delete share link @IBAction func buttonDeleteShareLink(sender: UIButton) { - + guard let tableShare = self.tableShare else { return } - + networking?.unShare(idShare: tableShare.idShare) } - + // Add another link @IBAction func buttonAddAnotherLink(sender: UIButton) { - + networking?.createShareLink(password: "") } - + // MARK: - Delegate networking - + func readShareCompleted() { reloadData(idShare: tableShare?.idShare ?? 0) } - + func shareCompleted() { unLoad() NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare) } - + func unShareCompleted() { unLoad() NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare) } - + func updateShareWithError(idShare: Int) { reloadData(idShare: idShare) } - + func getSharees(sharees: [NCCommunicationSharee]?) { } - + // MARK: - Delegate calendar - + func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) { - + if monthPosition == .previous || monthPosition == .next { calendar.setCurrentPage(date, animated: true) } else { let dateFormatter = DateFormatter() dateFormatter.formatterBehavior = .behavior10_4 dateFormatter.dateStyle = .medium - fieldSetExpirationDate.text = dateFormatter.string(from:date) + fieldSetExpirationDate.text = dateFormatter.string(from: date) fieldSetExpirationDate.endEditing(true) - + viewWindowCalendar?.removeFromSuperview() - + guard let tableShare = self.tableShare else { return } dateFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss" let expirationDate = dateFormatter.string(from: date) - + networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: tableShare.permissions, note: nil, label: nil, expirationDate: expirationDate, hideDownload: tableShare.hideDownload) } } - + func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool { return date > Date() } - + func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, titleDefaultColorFor date: Date) -> UIColor? { return date > Date() ? NCBrandColor.shared.label : NCBrandColor.shared.systemGray3 } diff --git a/iOSClient/Share/NCShareNetworking.swift b/iOSClient/Share/NCShareNetworking.swift index eb04e429d..04052ec9b 100644 --- a/iOSClient/Share/NCShareNetworking.swift +++ b/iOSClient/Share/NCShareNetworking.swift @@ -24,31 +24,31 @@ import UIKit import NCCommunication class NCShareNetworking: NSObject { - + private let appDelegate = UIApplication.shared.delegate as! AppDelegate - + var urlBase: String - var delegate: NCShareNetworkingDelegate? + weak var delegate: NCShareNetworkingDelegate? var view: UIView var metadata: tableMetadata - + init(metadata: tableMetadata, urlBase: String, view: UIView, delegate: NCShareNetworkingDelegate?) { self.metadata = metadata self.urlBase = urlBase self.view = view self.delegate = delegate - + super.init() } - + func readShare(showLoadingIndicator: Bool) { if showLoadingIndicator { NCUtility.shared.startActivityIndicator(backgroundView: view, blurEffect: false) } - + let filenamePath = CCUtility.returnFileNamePath(fromFileName: metadata.fileName, serverUrl: metadata.serverUrl, urlBase: urlBase, account: metadata.account)! let parameter = NCCShareParameter(path: filenamePath) - NCCommunication.shared.readShares(parameters: parameter) { (account, shares, errorCode, errorDescription) in + NCCommunication.shared.readShares(parameters: parameter) { account, shares, errorCode, errorDescription in if showLoadingIndicator { NCUtility.shared.stopActivityIndicator() } @@ -62,11 +62,11 @@ class NCShareNetworking: NSObject { self.delegate?.readShareCompleted() } } - + func createShareLink(password: String?) { NCUtility.shared.startActivityIndicator(backgroundView: view, blurEffect: false) let filenamePath = CCUtility.returnFileNamePath(fromFileName: metadata.fileName, serverUrl: metadata.serverUrl, urlBase: urlBase, account: metadata.account)! - NCCommunication.shared.createShareLink(path: filenamePath, password: password) { (account, share, errorCode, errorDescription) in + NCCommunication.shared.createShareLink(path: filenamePath, password: password) { account, share, errorCode, errorDescription in NCUtility.shared.stopActivityIndicator() if errorCode == 0 && share != nil { NCManageDatabase.shared.addShare(urlBase: self.urlBase, account: self.metadata.account, shares: [share!]) @@ -78,15 +78,15 @@ class NCShareNetworking: NSObject { } } - func createShare(shareWith: String, shareType: Int, metadata: tableMetadata) { + func createShare(shareWith: String, shareType: Int, password: String?, metadata: tableMetadata) { NCUtility.shared.startActivityIndicator(backgroundView: view, blurEffect: false) let filenamePath = CCUtility.returnFileNamePath(fromFileName: metadata.fileName, serverUrl: metadata.serverUrl, urlBase: urlBase, account: metadata.account)! - var permission: Int = NCManageDatabase.shared.getCapabilitiesServerInt(account: metadata.account, elements: ["ocs","data","capabilities","files_sharing","default_permissions"]) + var permission: Int = NCManageDatabase.shared.getCapabilitiesServerInt(account: metadata.account, elements: ["ocs", "data", "capabilities", "files_sharing", "default_permissions"]) if permission <= 0 { permission = metadata.directory ? NCGlobal.shared.permissionMaxFolderShare : NCGlobal.shared.permissionMaxFileShare } - NCCommunication.shared.createShare(path: filenamePath, shareType: shareType, shareWith: shareWith, permissions: permission) { (account, share, errorCode, errorDescription) in + NCCommunication.shared.createShare(path: filenamePath, shareType: shareType, shareWith: shareWith, password: password, permissions: permission) { (account, share, errorCode, errorDescription) in NCUtility.shared.stopActivityIndicator() if errorCode == 0 && share != nil { NCManageDatabase.shared.addShare(urlBase: self.urlBase, account: self.metadata.account, shares: [share!]) @@ -97,10 +97,10 @@ class NCShareNetworking: NSObject { self.delegate?.shareCompleted() } } - + func unShare(idShare: Int) { NCUtility.shared.startActivityIndicator(backgroundView: view, blurEffect: false) - NCCommunication.shared.deleteShare(idShare: idShare) { (account, errorCode, errorDescription) in + NCCommunication.shared.deleteShare(idShare: idShare) { account, errorCode, errorDescription in NCUtility.shared.stopActivityIndicator() if errorCode == 0 { NCManageDatabase.shared.deleteTableShare(account: account, idShare: idShare) @@ -110,10 +110,10 @@ class NCShareNetworking: NSObject { } } } - + func updateShare(idShare: Int, password: String?, permissions: Int, note: String?, label: String?, expirationDate: String?, hideDownload: Bool) { NCUtility.shared.startActivityIndicator(backgroundView: view, blurEffect: false) - NCCommunication.shared.updateShare(idShare: idShare, password: password, expireDate: expirationDate, permissions: permissions, note: note, label: label, hideDownload: hideDownload) { (account, share, errorCode, errorDescription) in + NCCommunication.shared.updateShare(idShare: idShare, password: password, expireDate: expirationDate, permissions: permissions, note: note, label: label, hideDownload: hideDownload) { account, share, errorCode, errorDescription in NCUtility.shared.stopActivityIndicator() if errorCode == 0 && share != nil { NCManageDatabase.shared.addShare(urlBase: self.urlBase, account: self.metadata.account, shares: [share!]) @@ -125,10 +125,10 @@ class NCShareNetworking: NSObject { } } } - + func getSharees(searchString: String) { NCUtility.shared.startActivityIndicator(backgroundView: view, blurEffect: false) - NCCommunication.shared.searchSharees(search: searchString) { (account, sharees, errorCode, errorDescription) in + NCCommunication.shared.searchSharees(search: searchString) { _, sharees, errorCode, errorDescription in NCUtility.shared.stopActivityIndicator() if errorCode == 0 { self.delegate?.getSharees(sharees: sharees) @@ -140,7 +140,7 @@ class NCShareNetworking: NSObject { } } -protocol NCShareNetworkingDelegate { +protocol NCShareNetworkingDelegate: AnyObject { func readShareCompleted() func shareCompleted() func unShareCompleted() diff --git a/iOSClient/Share/NCSharePaging.swift b/iOSClient/Share/NCSharePaging.swift index d7a0bb451..fdf8d59d0 100644 --- a/iOSClient/Share/NCSharePaging.swift +++ b/iOSClient/Share/NCSharePaging.swift @@ -22,31 +22,30 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // - import UIKit import Parchment import NCCommunication import MarqueeLabel class NCSharePaging: UIViewController { - + private let pagingViewController = NCShareHeaderViewController() private let appDelegate = UIApplication.shared.delegate as! AppDelegate - + private var activityEnabled = true private var commentsEnabled = true private var sharingEnabled = true - + @objc var metadata = tableMetadata() var indexPage = NCGlobal.NCSharePagingIndex.activity - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + view.backgroundColor = NCBrandColor.shared.systemBackground - + navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_close_", comment: ""), style: .done, target: self, action: #selector(exitTapped)) // Verify Comments & Sharing enabled @@ -69,10 +68,10 @@ class NCSharePaging: UIViewController { if indexPage == .activity && !activityEnabled && sharingEnabled { indexPage = .sharing } - + // *** MUST BE THE FIRST ONE *** pagingViewController.metadata = metadata - + pagingViewController.activityEnabled = activityEnabled pagingViewController.commentsEnabled = commentsEnabled pagingViewController.sharingEnabled = sharingEnabled @@ -86,7 +85,7 @@ class NCSharePaging: UIViewController { addChild(pagingViewController) view.addSubview(pagingViewController.view) pagingViewController.didMove(toParent: self) - + // Customization pagingViewController.indicatorOptions = .visible( height: 1, @@ -94,50 +93,50 @@ class NCSharePaging: UIViewController { spacing: .zero, insets: UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5) ) - + // Contrain the paging view to all edges. pagingViewController.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ pagingViewController.view.topAnchor.constraint(equalTo: view.topAnchor), pagingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), pagingViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), - pagingViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + pagingViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor) ]) - + pagingViewController.dataSource = self pagingViewController.delegate = self pagingViewController.select(index: indexPage.rawValue) let pagingIndexItem = self.pagingViewController(pagingViewController, pagingItemAt: indexPage.rawValue) as! PagingIndexItem self.title = pagingIndexItem.title - + NotificationCenter.default.addObserver(self, selector: #selector(self.changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil) changeTheming() } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + if appDelegate.disableSharesView { self.dismiss(animated: false, completion: nil) } - + pagingViewController.menuItemSize = .fixed( width: self.view.bounds.width / CGFloat(NCGlobal.NCSharePagingIndex.allCases.count), height: 40) } - + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["ocId":metadata.ocId, "serverUrl":metadata.serverUrl]) + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl]) } - + @objc func exitTapped() { self.dismiss(animated: true, completion: nil) } - - //MARK: - NotificationCenter - + + // MARK: - NotificationCenter + @objc func changeTheming() { pagingViewController.indicatorColor = NCBrandColor.shared.brandElement (pagingViewController.view as! NCSharePagingView).setupConstraints() @@ -148,7 +147,7 @@ class NCSharePaging: UIViewController { // MARK: - PagingViewController Delegate extension NCSharePaging: PagingViewControllerDelegate { - + func pagingViewController(_ pagingViewController: PagingViewController, willScrollToItem pagingItem: PagingItem, startingViewController: UIViewController, destinationViewController: UIViewController) { guard @@ -169,9 +168,9 @@ extension NCSharePaging: PagingViewControllerDelegate { // MARK: - PagingViewController DataSource extension NCSharePaging: PagingViewControllerDataSource { - + func pagingViewController(_: PagingViewController, viewControllerAt index: Int) -> UIViewController { - + let height = pagingViewController.options.menuHeight + NCSharePagingView.HeaderHeight switch NCGlobal.NCSharePagingIndex(rawValue: index) { @@ -193,9 +192,9 @@ extension NCSharePaging: PagingViewControllerDataSource { return UIViewController() } } - + func pagingViewController(_: PagingViewController, pagingItemAt index: Int) -> PagingItem { - + switch NCGlobal.NCSharePagingIndex(rawValue: index) { case .activity: return PagingIndexItem(index: index, title: NSLocalizedString("_activity_", comment: "")) @@ -205,7 +204,7 @@ extension NCSharePaging: PagingViewControllerDataSource { return PagingIndexItem(index: index, title: "") } } - + func numberOfViewControllers(in pagingViewController: PagingViewController) -> Int { return 2 } @@ -214,10 +213,10 @@ extension NCSharePaging: PagingViewControllerDataSource { // MARK: - Header class NCShareHeaderViewController: PagingViewController { - + public var image: UIImage? public var metadata = tableMetadata() - + public var activityEnabled = true public var commentsEnabled = true public var sharingEnabled = true @@ -230,7 +229,7 @@ class NCShareHeaderViewController: PagingViewController { metadata: metadata ) } - + override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { if NCGlobal.NCSharePagingIndex(rawValue: indexPath.item) == .activity && !activityEnabled { return @@ -242,40 +241,40 @@ class NCShareHeaderViewController: PagingViewController { } class NCSharePagingView: PagingView { - + static let HeaderHeight: CGFloat = 250 var metadata = tableMetadata() - + var headerHeightConstraint: NSLayoutConstraint? - + // MARK: - View Life Cycle public init(options: Parchment.PagingOptions, collectionView: UICollectionView, pageView: UIView, metadata: tableMetadata) { super.init(options: options, collectionView: collectionView, pageView: pageView) - + self.metadata = metadata } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + override func setupConstraints() { - + let headerView = Bundle.main.loadNibNamed("NCShareHeaderView", owner: self, options: nil)?.first as! NCShareHeaderView headerView.backgroundColor = NCBrandColor.shared.systemBackground headerView.ocId = metadata.ocId - + if FileManager.default.fileExists(atPath: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) { - headerView.imageView.image = UIImage.init(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) + headerView.imageView.image = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) } else { if metadata.directory { - let image = UIImage.init(named: "folder")! + let image = UIImage(named: "folder")! headerView.imageView.image = image.image(color: NCBrandColor.shared.brandElement, size: image.size.width) } else if metadata.iconName.count > 0 { - headerView.imageView.image = UIImage.init(named: metadata.iconName) + headerView.imageView.image = UIImage(named: metadata.iconName) } else { - headerView.imageView.image = UIImage.init(named: "file") + headerView.imageView.image = UIImage(named: "file") } } headerView.path.text = NCUtilityFileSystem.shared.getPath(metadata: metadata) @@ -288,26 +287,26 @@ class NCSharePagingView: PagingView { } headerView.info.text = CCUtility.transformedSize(metadata.size) + ", " + CCUtility.dateDiff(metadata.date as Date) addSubview(headerView) - + pageView.translatesAutoresizingMaskIntoConstraints = false collectionView.translatesAutoresizingMaskIntoConstraints = false headerView.translatesAutoresizingMaskIntoConstraints = false - + headerHeightConstraint = headerView.heightAnchor.constraint( equalToConstant: NCSharePagingView.HeaderHeight ) headerHeightConstraint?.isActive = true - + NSLayoutConstraint.activate([ collectionView.leadingAnchor.constraint(equalTo: leadingAnchor), collectionView.trailingAnchor.constraint(equalTo: trailingAnchor), collectionView.heightAnchor.constraint(equalToConstant: options.menuHeight), collectionView.topAnchor.constraint(equalTo: headerView.bottomAnchor), - + headerView.topAnchor.constraint(equalTo: topAnchor), headerView.leadingAnchor.constraint(equalTo: leadingAnchor), headerView.trailingAnchor.constraint(equalTo: trailingAnchor), - + pageView.leadingAnchor.constraint(equalTo: leadingAnchor), pageView.trailingAnchor.constraint(equalTo: trailingAnchor), pageView.bottomAnchor.constraint(equalTo: bottomAnchor), @@ -317,25 +316,23 @@ class NCSharePagingView: PagingView { } class NCShareHeaderView: UIView { - + @IBOutlet weak var imageView: UIImageView! @IBOutlet weak var path: MarqueeLabel! @IBOutlet weak var info: UILabel! @IBOutlet weak var favorite: UIButton! - - private let appDelegate = UIApplication.shared.delegate as! AppDelegate var ocId = "" override func awakeFromNib() { super.awakeFromNib() - + let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.longTap)) path.addGestureRecognizer(longGesture) } - + @IBAction func touchUpInsideFavorite(_ sender: UIButton) { if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - NCNetworking.shared.favoriteMetadata(metadata) { (errorCode, errorDescription) in + NCNetworking.shared.favoriteMetadata(metadata) { errorCode, errorDescription in if errorCode == 0 { if !metadata.favorite { self.favorite.setImage(NCUtility.shared.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite, size: 20), for: .normal) @@ -348,12 +345,12 @@ class NCShareHeaderView: UIView { } } } - - @objc func longTap(sender : UIGestureRecognizer) { - + + @objc func longTap(sender: UIGestureRecognizer) { + let board = UIPasteboard.general board.string = path.text - + NCContentPresenter.shared.messageNotification("", description: "_copied_path_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorNoError) } } diff --git a/iOSClient/Share/NCShareQuickStatusMenu.swift b/iOSClient/Share/NCShareQuickStatusMenu.swift index d165bb091..71d4a4be6 100644 --- a/iOSClient/Share/NCShareQuickStatusMenu.swift +++ b/iOSClient/Share/NCShareQuickStatusMenu.swift @@ -9,11 +9,11 @@ import UIKit class NCShareQuickStatusMenu: NSObject { - + func toggleMenu(viewController: UIViewController, directory: Bool, tableShare: tableShare) { - + print(tableShare.permissions) - let menuViewController = UIStoryboard.init(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu + let menuViewController = UIStoryboard(name: "NCMenu", bundle: nil).instantiateInitialViewController() as! NCMenu var actions = [NCMenuAction]() actions.append( @@ -22,7 +22,7 @@ class NCShareQuickStatusMenu: NSObject { icon: UIImage(), selected: tableShare.permissions == (NCGlobal.shared.permissionReadShare + NCGlobal.shared.permissionShareShare) || tableShare.permissions == NCGlobal.shared.permissionReadShare, on: false, - action: { menuAction in + action: { _ in let canShare = CCUtility.isPermission(toCanShare: tableShare.permissions) let permissions = CCUtility.getPermissionsValue(byCanEdit: false, andCanCreate: false, andCanChange: false, andCanDelete: false, andCanShare: canShare, andIsFolder: directory) NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShareChangePermissions, userInfo: ["idShare": tableShare.idShare, "permissions": permissions, "hideDownload": tableShare.hideDownload]) @@ -36,7 +36,7 @@ class NCShareQuickStatusMenu: NSObject { icon: UIImage(), selected: hasUploadPermission(tableShare: tableShare), on: false, - action: { menuAction in + action: { _ in let canShare = CCUtility.isPermission(toCanShare: tableShare.permissions) let permissions = CCUtility.getPermissionsValue(byCanEdit: true, andCanCreate: true, andCanChange: true, andCanDelete: true, andCanShare: canShare, andIsFolder: directory) NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShareChangePermissions, userInfo: ["idShare": tableShare.idShare, "permissions": permissions, "hideDownload": tableShare.hideDownload]) @@ -64,4 +64,3 @@ class NCShareQuickStatusMenu: NSObject { return uploadPermissions.contains(tableShare.permissions) } } - diff --git a/iOSClient/Share/NCShareUserCell.swift b/iOSClient/Share/NCShareUserCell.swift index 95e9210f6..c20fe3dc0 100644 --- a/iOSClient/Share/NCShareUserCell.swift +++ b/iOSClient/Share/NCShareUserCell.swift @@ -24,7 +24,7 @@ import UIKit import DropDown class NCShareUserCell: UITableViewCell, NCCellProtocol { - + @IBOutlet weak var imageItem: UIImageView! @IBOutlet weak var labelTitle: UILabel! @IBOutlet weak var buttonMenu: UIButton! @@ -33,12 +33,12 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { @IBOutlet weak var btnQuickStatus: UIButton! @IBOutlet weak var labelQuickStatus: UILabel! @IBOutlet weak var imageDownArrow: UIImageView! - + var tableShare: tableShare? - var delegate: NCShareUserCellDelegate? - + weak var delegate: NCShareUserCellDelegate? + var fileAvatarImageView: UIImageView? { - get{ + get { return imageItem } } @@ -47,41 +47,41 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { return nil } } - var filePreviewImageView : UIImageView? { - get{ + var filePreviewImageView: UIImageView? { + get { return nil } } var fileUser: String? { - get{ + get { return tableShare?.shareWith } } - + override func awakeFromNib() { super.awakeFromNib() let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAvatarImage)) imageItem?.addGestureRecognizer(tapGesture) - buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: .gray, size: 50), for: .normal) + buttonMenu.setImage(UIImage(named: "shareMenu")!.image(color: .gray, size: 50), for: .normal) labelQuickStatus.textColor = NCBrandColor.shared.customer imageDownArrow.image = NCUtility.shared.loadImage(named: "arrowtriangle.down.fill", color: NCBrandColor.shared.customer) } - + @objc func tapAvatarImage(_ sender: UITapGestureRecognizer) { delegate?.showProfile(with: tableShare, sender: sender) } - + @IBAction func touchUpInsideMenu(_ sender: Any) { delegate?.tapMenu(with: tableShare, sender: sender) } - + @IBAction func quickStatusClicked(_ sender: Any) { delegate?.quickStatus(with: tableShare, sender: sender) } } -protocol NCShareUserCellDelegate { +protocol NCShareUserCellDelegate: AnyObject { func tapMenu(with tableShare: tableShare?, sender: Any) func showProfile(with tableComment: tableShare?, sender: Any) func quickStatus(with tableShare: tableShare?, sender: Any) @@ -90,15 +90,15 @@ protocol NCShareUserCellDelegate { // MARK: - NCShareUserDropDownCell class NCShareUserDropDownCell: DropDownCell, NCCellProtocol { - + @IBOutlet weak var imageItem: UIImageView! @IBOutlet weak var imageStatus: UIImageView! @IBOutlet weak var status: UILabel! @IBOutlet weak var imageShareeType: UIImageView! @IBOutlet weak var centerTitle: NSLayoutConstraint! - + private var user: String = "" - + var fileAvatarImageView: UIImageView? { get { return imageItem diff --git a/iOSClient/Share/NCShareUserMenuView.swift b/iOSClient/Share/NCShareUserMenuView.swift index 38d1c6ff6..9dd2c2be2 100644 --- a/iOSClient/Share/NCShareUserMenuView.swift +++ b/iOSClient/Share/NCShareUserMenuView.swift @@ -25,36 +25,36 @@ import FSCalendar import NCCommunication class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDelegate, NCShareNetworkingDelegate, FSCalendarDelegate, FSCalendarDelegateAppearance { - + @IBOutlet weak var switchCanReshare: UISwitch! @IBOutlet weak var labelCanReshare: UILabel! - + @IBOutlet weak var switchCanCreate: UISwitch! @IBOutlet weak var labelCanCreate: UILabel! - + @IBOutlet weak var switchCanChange: UISwitch! @IBOutlet weak var labelCanChange: UILabel! - + @IBOutlet weak var switchCanDelete: UISwitch! @IBOutlet weak var labelCanDelete: UILabel! - + @IBOutlet weak var switchSetExpirationDate: UISwitch! @IBOutlet weak var labelSetExpirationDate: UILabel! @IBOutlet weak var fieldSetExpirationDate: UITextField! - + @IBOutlet weak var imageNoteToRecipient: UIImageView! @IBOutlet weak var labelNoteToRecipient: UILabel! @IBOutlet weak var fieldNoteToRecipient: UITextField! - + @IBOutlet weak var buttonUnshare: UIButton! @IBOutlet weak var labelUnshare: UILabel! @IBOutlet weak var imageUnshare: UIImageView! - + private let appDelegate = UIApplication.shared.delegate as! AppDelegate - + var width: CGFloat = 0 var height: CGFloat = 0 - + private var tableShare: tableShare? var metadata: tableMetadata? var shareViewController: NCShare? @@ -63,18 +63,18 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg var viewWindow: UIView? var viewWindowCalendar: UIView? private var calendar: FSCalendar? - private var activeTextfieldDiff : CGFloat = 0 + private var activeTextfieldDiff: CGFloat = 0 private var activeTextField = UITextField() override func awakeFromNib() { - + layer.borderColor = UIColor.lightGray.cgColor layer.borderWidth = 0.5 layer.cornerRadius = 5 layer.masksToBounds = false layer.shadowOffset = CGSize(width: 2, height: 2) layer.shadowOpacity = 0.2 - + switchCanReshare.transform = CGAffineTransform(scaleX: 0.75, y: 0.75) switchCanReshare.onTintColor = NCBrandColor.shared.brandElement switchCanCreate?.transform = CGAffineTransform(scaleX: 0.75, y: 0.75) @@ -85,7 +85,7 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg switchCanDelete?.onTintColor = NCBrandColor.shared.brandElement switchSetExpirationDate.transform = CGAffineTransform(scaleX: 0.75, y: 0.75) switchSetExpirationDate.onTintColor = NCBrandColor.shared.brandElement - + labelCanReshare?.text = NSLocalizedString("_share_can_reshare_", comment: "") labelCanReshare?.textColor = NCBrandColor.shared.label labelCanCreate?.text = NSLocalizedString("_share_can_create_", comment: "") @@ -100,40 +100,40 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg labelNoteToRecipient?.textColor = NCBrandColor.shared.label labelUnshare?.text = NSLocalizedString("_share_unshare_", comment: "") labelUnshare?.textColor = NCBrandColor.shared.label - + fieldSetExpirationDate.inputView = UIView() - + fieldNoteToRecipient.delegate = self - - imageNoteToRecipient.image = UIImage.init(named: "file_txt")!.image(color: NCBrandColor.shared.gray, size: 50) + + imageNoteToRecipient.image = UIImage(named: "file_txt")!.image(color: NCBrandColor.shared.gray, size: 50) imageUnshare.image = NCUtility.shared.loadImage(named: "trash", color: NCBrandColor.shared.gray, size: 50) - + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) } - + override func willMove(toWindow newWindow: UIWindow?) { super.willMove(toWindow: newWindow) - + if newWindow == nil { // UIView disappear shareViewController?.reloadData() } else { // UIView appear - networking = NCShareNetworking.init(metadata: metadata!, urlBase: appDelegate.urlBase, view: self, delegate: self) + networking = NCShareNetworking(metadata: metadata!, urlBase: appDelegate.urlBase, view: self, delegate: self) } } - + func unLoad() { viewWindowCalendar?.removeFromSuperview() viewWindow?.removeFromSuperview() - + viewWindowCalendar = nil viewWindow = nil } - + func reloadData(idShare: Int) { - + guard let metadata = self.metadata else { return } tableShare = NCManageDatabase.shared.getTableShare(account: metadata.account, idShare: idShare) guard let tableShare = self.tableShare else { return } @@ -141,26 +141,26 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg // Can reshare (file) let canReshare = CCUtility.isPermission(toCanShare: tableShare.permissions) switchCanReshare.setOn(canReshare, animated: false) - + if metadata.directory { // Can create (folder) let canCreate = CCUtility.isPermission(toCanCreate: tableShare.permissions) switchCanCreate.setOn(canCreate, animated: false) - + // Can change (folder) let canChange = CCUtility.isPermission(toCanChange: tableShare.permissions) switchCanChange.setOn(canChange, animated: false) - + // Can delete (folder) let canDelete = CCUtility.isPermission(toCanDelete: tableShare.permissions) switchCanDelete.setOn(canDelete, animated: false) } - + // Set expiration date if tableShare.expirationDate != nil { switchSetExpirationDate.setOn(true, animated: false) fieldSetExpirationDate.isEnabled = true - + let dateFormatter = DateFormatter() dateFormatter.formatterBehavior = .behavior10_4 dateFormatter.dateStyle = .medium @@ -170,22 +170,22 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg fieldSetExpirationDate.isEnabled = false fieldSetExpirationDate.text = "" } - + // Note to recipient fieldNoteToRecipient.text = tableShare.note } - + func textFieldDidBeginEditing(_ textField: UITextField) { - + self.activeTextField = textField } - + // MARK: - Keyboard notification - - @objc internal func keyboardWillShow(_ notification : Notification?) { - + + @objc internal func keyboardWillShow(_ notification: Notification?) { + activeTextfieldDiff = 0 - + if let info = notification?.userInfo, let centerObject = self.activeTextField.superview?.convert(self.activeTextField.center, to: nil) { let frameEndUserInfoKey = UIResponder.keyboardFrameEndUserInfoKey @@ -198,32 +198,32 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg } } } - + @objc func keyboardWillHide(_ notification: Notification) { self.frame.origin.y -= activeTextfieldDiff } - + // MARK: - Tap viewWindowCalendar - + @objc func tapViewWindowCalendar(gesture: UITapGestureRecognizer) { calendar?.removeFromSuperview() viewWindowCalendar?.removeFromSuperview() - + calendar = nil viewWindowCalendar = nil - + reloadData(idShare: tableShare?.idShare ?? 0) } - + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { return gestureRecognizer.view == touch.view } - + // MARK: - IBAction // Can reshare @IBAction func switchCanReshareChanged(sender: UISwitch) { - + guard let tableShare = self.tableShare else { return } guard let metadata = self.metadata else { return } @@ -231,9 +231,9 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg let canCreate = CCUtility.isPermission(toCanCreate: tableShare.permissions) let canChange = CCUtility.isPermission(toCanChange: tableShare.permissions) let canDelete = CCUtility.isPermission(toCanDelete: tableShare.permissions) - + var permissions: Int = 0 - + if metadata.directory { permissions = CCUtility.getPermissionsValue(byCanEdit: canEdit, andCanCreate: canCreate, andCanChange: canChange, andCanDelete: canDelete, andCanShare: sender.isOn, andIsFolder: metadata.directory) } else { @@ -251,12 +251,12 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg } } } - + networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: permissions, note: nil, label: nil, expirationDate: nil, hideDownload: tableShare.hideDownload) } - + @IBAction func switchCanCreate(sender: UISwitch) { - + guard let tableShare = self.tableShare else { return } guard let metadata = self.metadata else { return } @@ -269,42 +269,42 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: permissions, note: nil, label: nil, expirationDate: nil, hideDownload: tableShare.hideDownload) } - + @IBAction func switchCanChange(sender: UISwitch) { - + guard let tableShare = self.tableShare else { return } guard let metadata = self.metadata else { return } - + let canEdit = CCUtility.isAnyPermission(toEdit: tableShare.permissions) let canCreate = CCUtility.isPermission(toCanCreate: tableShare.permissions) let canDelete = CCUtility.isPermission(toCanDelete: tableShare.permissions) let canShare = CCUtility.isPermission(toCanShare: tableShare.permissions) - + let permissions = CCUtility.getPermissionsValue(byCanEdit: canEdit, andCanCreate: canCreate, andCanChange: sender.isOn, andCanDelete: canDelete, andCanShare: canShare, andIsFolder: metadata.directory) networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: permissions, note: nil, label: nil, expirationDate: nil, hideDownload: tableShare.hideDownload) } - + @IBAction func switchCanDelete(sender: UISwitch) { - + guard let tableShare = self.tableShare else { return } guard let metadata = self.metadata else { return } - + let canEdit = CCUtility.isAnyPermission(toEdit: tableShare.permissions) let canCreate = CCUtility.isPermission(toCanCreate: tableShare.permissions) let canChange = CCUtility.isPermission(toCanChange: tableShare.permissions) let canShare = CCUtility.isPermission(toCanShare: tableShare.permissions) - + let permissions = CCUtility.getPermissionsValue(byCanEdit: canEdit, andCanCreate: canCreate, andCanChange: canChange, andCanDelete: sender.isOn, andCanShare: canShare, andIsFolder: metadata.directory) networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: permissions, note: nil, label: nil, expirationDate: nil, hideDownload: tableShare.hideDownload) } - + // Set expiration date @IBAction func switchSetExpirationDate(sender: UISwitch) { - + guard let tableShare = self.tableShare else { return } - + if sender.isOn { fieldSetExpirationDate.isEnabled = true fieldSetExpirationDate(sender: fieldSetExpirationDate) @@ -312,86 +312,86 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDeleg networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: tableShare.permissions, note: nil, label: nil, expirationDate: "", hideDownload: tableShare.hideDownload) } } - + @IBAction func fieldSetExpirationDate(sender: UITextField) { - + let calendar = NCShareCommon.shared.openCalendar(view: self, width: width, height: height) calendar.calendarView.delegate = self self.calendar = calendar.calendarView viewWindowCalendar = calendar.viewWindow - + let tap = UITapGestureRecognizer(target: self, action: #selector(tapViewWindowCalendar)) tap.delegate = self viewWindowCalendar?.addGestureRecognizer(tap) } - + // Note to recipient @IBAction func fieldNoteToRecipientDidEndOnExit(textField: UITextField) { - + guard let tableShare = self.tableShare else { return } if fieldNoteToRecipient.text == nil { return } - + networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: tableShare.permissions, note: fieldNoteToRecipient.text, label: nil, expirationDate: nil, hideDownload: tableShare.hideDownload) } - + // Unshare @IBAction func buttonUnshare(sender: UIButton) { - + guard let tableShare = self.tableShare else { return } - + networking?.unShare(idShare: tableShare.idShare) } - + // MARK: - Delegate networking - + func readShareCompleted() { reloadData(idShare: tableShare?.idShare ?? 0) } - + func shareCompleted() { unLoad() NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare) } - + func unShareCompleted() { unLoad() NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare) } - + func updateShareWithError(idShare: Int) { reloadData(idShare: idShare) } - + func getSharees(sharees: [NCCommunicationSharee]?) { } - + // MARK: - Delegate calendar func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) { - + if monthPosition == .previous || monthPosition == .next { calendar.setCurrentPage(date, animated: true) } else { let dateFormatter = DateFormatter() dateFormatter.formatterBehavior = .behavior10_4 dateFormatter.dateStyle = .medium - fieldSetExpirationDate.text = dateFormatter.string(from:date) + fieldSetExpirationDate.text = dateFormatter.string(from: date) fieldSetExpirationDate.endEditing(true) - + viewWindowCalendar?.removeFromSuperview() - + guard let tableShare = self.tableShare else { return } - + dateFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss" let expirationDate = dateFormatter.string(from: date) - + networking?.updateShare(idShare: tableShare.idShare, password: nil, permissions: tableShare.permissions, note: nil, label: nil, expirationDate: expirationDate, hideDownload: tableShare.hideDownload) } } - + func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool { return date > Date() } - + func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, titleDefaultColorFor date: Date) -> UIColor? { return date > Date() ? NCBrandColor.shared.label : NCBrandColor.shared.systemGray3 } diff --git a/iOSClient/Shares/NCShares.swift b/iOSClient/Shares/NCShares.swift index 98faa61c7..c6a2d2ac9 100644 --- a/iOSClient/Shares/NCShares.swift +++ b/iOSClient/Shares/NCShares.swift @@ -24,26 +24,26 @@ import UIKit import NCCommunication -class NCShares: NCCollectionViewCommon { - +class NCShares: NCCollectionViewCommon { + // MARK: - View Life Cycle required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - + titleCurrentFolder = NSLocalizedString("_list_shares_", comment: "") - layoutKey = NCGlobal.shared.layoutViewShares + layoutKey = NCGlobal.shared.layoutViewShares enableSearchBar = false - emptyImage = UIImage.init(named: "share")?.image(color: .gray, size: UIScreen.main.bounds.width) + emptyImage = UIImage(named: "share")?.image(color: .gray, size: UIScreen.main.bounds.width) emptyTitle = "_list_shares_no_files_" emptyDescription = "_tutorial_list_shares_view_" } - + // MARK: - DataSource + NC Endpoint - + override func reloadDataSource() { super.reloadDataSource() - + DispatchQueue.global().async { self.metadatasSource.removeAll() let sharess = NCManageDatabase.shared.getTableShares(account: self.appDelegate.account) @@ -54,52 +54,51 @@ class NCShares: NCCollectionViewCommon { } } } - - self.dataSource = NCDataSource.init(metadatasSource: self.metadatasSource, sort: self.layoutForView?.sort, ascending: self.layoutForView?.ascending, directoryOnTop: self.layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) - + + self.dataSource = NCDataSource(metadatasSource: self.metadatasSource, sort: self.layoutForView?.sort, ascending: self.layoutForView?.ascending, directoryOnTop: self.layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true) + DispatchQueue.main.async { self.refreshControl.endRefreshing() self.collectionView.reloadData() } } } - + override func reloadDataSourceNetwork(forced: Bool = false) { super.reloadDataSourceNetwork(forced: forced) - + if isSearching { networkSearch() return } - + isReloadDataSourceNetworkInProgress = true collectionView?.reloadData() - + // Shares network - NCCommunication.shared.readShares(parameters: NCCShareParameter(), queue: NCCommunicationCommon.shared.backgroundQueue) { (account, shares, errorCode, ErrorDescription) in - + NCCommunication.shared.readShares(parameters: NCCShareParameter(), queue: NCCommunicationCommon.shared.backgroundQueue) { account, shares, errorCode, errorDescription in + DispatchQueue.main.async { self.refreshControl.endRefreshing() self.isReloadDataSourceNetworkInProgress = false } - + if errorCode == 0 { - + NCManageDatabase.shared.deleteTableShare(account: account) if shares != nil { NCManageDatabase.shared.addShare(urlBase: self.appDelegate.urlBase, account: account, shares: shares!) } self.appDelegate.shares = NCManageDatabase.shared.getTableShares(account: account) self.reloadDataSource() - + } else { - + DispatchQueue.main.async { self.collectionView?.reloadData() - NCContentPresenter.shared.messageNotification("_share_", description: ErrorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) + NCContentPresenter.shared.messageNotification("_share_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } } } } } - diff --git a/iOSClient/Supporting Files/af.lproj/Localizable.strings b/iOSClient/Supporting Files/af.lproj/Localizable.strings Binary files differindex 0f35e9358..3efb91c30 100644 --- a/iOSClient/Supporting Files/af.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/af.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/ar.lproj/Localizable.strings b/iOSClient/Supporting Files/ar.lproj/Localizable.strings Binary files differindex 206816400..47d88f81e 100644 --- a/iOSClient/Supporting Files/ar.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/ar.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/ast.lproj/Localizable.strings b/iOSClient/Supporting Files/ast.lproj/Localizable.strings Binary files differindex 1f951a894..976711c3f 100644 --- a/iOSClient/Supporting Files/ast.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/ast.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/az.lproj/Localizable.strings b/iOSClient/Supporting Files/az.lproj/Localizable.strings Binary files differindex a9b3eed07..49c6f8050 100644 --- a/iOSClient/Supporting Files/az.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/az.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings b/iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings Binary files differindex 8ed5d8502..bc062b616 100644 --- a/iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings b/iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings Binary files differindex e64a32138..c3a5ad2d8 100644 --- a/iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/br.lproj/Localizable.strings b/iOSClient/Supporting Files/br.lproj/Localizable.strings Binary files differindex d9c234cb5..516956454 100644 --- a/iOSClient/Supporting Files/br.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/br.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/bs.lproj/Localizable.strings b/iOSClient/Supporting Files/bs.lproj/Localizable.strings Binary files differindex 8696c06a8..b2d172074 100644 --- a/iOSClient/Supporting Files/bs.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/bs.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/ca.lproj/Localizable.strings b/iOSClient/Supporting Files/ca.lproj/Localizable.strings Binary files differindex f0744f0e1..1f2cdd384 100644 --- a/iOSClient/Supporting Files/ca.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/ca.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings b/iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings Binary files differindex 6cd34d129..42ae9e102 100644 --- a/iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings b/iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings Binary files differindex 691d7bbb6..66fc24ba2 100644 --- a/iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/da.lproj/Localizable.strings b/iOSClient/Supporting Files/da.lproj/Localizable.strings Binary files differindex 34f50aba0..6b20c7433 100644 --- a/iOSClient/Supporting Files/da.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/da.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/de.lproj/Localizable.strings b/iOSClient/Supporting Files/de.lproj/Localizable.strings Binary files differindex e74232024..0eb8af558 100644 --- a/iOSClient/Supporting Files/de.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/de.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/el.lproj/Localizable.strings b/iOSClient/Supporting Files/el.lproj/Localizable.strings Binary files differindex 85b479cb6..1e7228d0e 100644 --- a/iOSClient/Supporting Files/el.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/el.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/en-GB.lproj/Localizable.strings b/iOSClient/Supporting Files/en-GB.lproj/Localizable.strings Binary files differindex c7190a6db..2a35fa58e 100644 --- a/iOSClient/Supporting Files/en-GB.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en-GB.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index c63f9d828..43a3941f8 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -168,7 +168,7 @@ "_upload_e2ee_" = "The file you are uploading is encrypted, keep the app in the foreground until complete"; "_chunk_size_mb_" = "Chunk size in MB"; "_chunk_footer_title_" = "Chunked file upload (0 is disabled)\nImportant: the chunked upload works only when the app is \"active\"."; -"_privacy_" = "Privacy"; +"_privacy_legal_" = "Privacy and Legal Policy"; "_source_code_" = "Get source code"; "_account_select_" = "Select the account"; "_host_insert_" = "Insert the host name, for example:"; @@ -821,4 +821,5 @@ "_copied_path_" = "Copied path"; "_copy_path_" = "Copy path"; "_certificates_" = "Certificates"; +"_privacy_screen_" = "Splash screen when app inactive"; diff --git a/iOSClient/Supporting Files/eo.lproj/Localizable.strings b/iOSClient/Supporting Files/eo.lproj/Localizable.strings Binary files differindex cd0899730..6ef9c3dcd 100644 --- a/iOSClient/Supporting Files/eo.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/eo.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-419.lproj/Localizable.strings b/iOSClient/Supporting Files/es-419.lproj/Localizable.strings Binary files differindex 2cefb5560..292250b74 100644 --- a/iOSClient/Supporting Files/es-419.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-419.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-AR.lproj/Localizable.strings b/iOSClient/Supporting Files/es-AR.lproj/Localizable.strings Binary files differindex e46f02447..bd6992ffc 100644 --- a/iOSClient/Supporting Files/es-AR.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-AR.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-CL.lproj/Localizable.strings b/iOSClient/Supporting Files/es-CL.lproj/Localizable.strings Binary files differindex c74e0cd91..9755b0a9f 100644 --- a/iOSClient/Supporting Files/es-CL.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-CL.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-CO.lproj/Localizable.strings b/iOSClient/Supporting Files/es-CO.lproj/Localizable.strings Binary files differindex c74e0cd91..9755b0a9f 100644 --- a/iOSClient/Supporting Files/es-CO.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-CO.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-CR.lproj/Localizable.strings b/iOSClient/Supporting Files/es-CR.lproj/Localizable.strings Binary files differindex c74e0cd91..9755b0a9f 100644 --- a/iOSClient/Supporting Files/es-CR.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-CR.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-DO.lproj/Localizable.strings b/iOSClient/Supporting Files/es-DO.lproj/Localizable.strings Binary files differindex c74e0cd91..9755b0a9f 100644 --- a/iOSClient/Supporting Files/es-DO.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-DO.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-EC.lproj/Localizable.strings b/iOSClient/Supporting Files/es-EC.lproj/Localizable.strings Binary files differindex 8c450121e..e7f49175f 100644 --- a/iOSClient/Supporting Files/es-EC.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-EC.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-GT.lproj/Localizable.strings b/iOSClient/Supporting Files/es-GT.lproj/Localizable.strings Binary files differindex c74e0cd91..9755b0a9f 100644 --- a/iOSClient/Supporting Files/es-GT.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-GT.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-HN.lproj/Localizable.strings b/iOSClient/Supporting Files/es-HN.lproj/Localizable.strings Binary files differindex 6489de796..96ae36764 100644 --- a/iOSClient/Supporting Files/es-HN.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-HN.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-MX.lproj/Localizable.strings b/iOSClient/Supporting Files/es-MX.lproj/Localizable.strings Binary files differindex e9d067780..e59a07f1a 100644 --- a/iOSClient/Supporting Files/es-MX.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-MX.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-NI.lproj/Localizable.strings b/iOSClient/Supporting Files/es-NI.lproj/Localizable.strings Binary files differindex 6489de796..96ae36764 100644 --- a/iOSClient/Supporting Files/es-NI.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-NI.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-PA.lproj/Localizable.strings b/iOSClient/Supporting Files/es-PA.lproj/Localizable.strings Binary files differindex 6489de796..96ae36764 100644 --- a/iOSClient/Supporting Files/es-PA.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-PA.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-PE.lproj/Localizable.strings b/iOSClient/Supporting Files/es-PE.lproj/Localizable.strings Binary files differindex 6489de796..96ae36764 100644 --- a/iOSClient/Supporting Files/es-PE.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-PE.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-PR.lproj/Localizable.strings b/iOSClient/Supporting Files/es-PR.lproj/Localizable.strings Binary files differindex 6489de796..96ae36764 100644 --- a/iOSClient/Supporting Files/es-PR.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-PR.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-PY.lproj/Localizable.strings b/iOSClient/Supporting Files/es-PY.lproj/Localizable.strings Binary files differindex 28a55cec9..b0d7b02ea 100644 --- a/iOSClient/Supporting Files/es-PY.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-PY.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-SV.lproj/Localizable.strings b/iOSClient/Supporting Files/es-SV.lproj/Localizable.strings Binary files differindex c74e0cd91..9755b0a9f 100644 --- a/iOSClient/Supporting Files/es-SV.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-SV.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es-UY.lproj/Localizable.strings b/iOSClient/Supporting Files/es-UY.lproj/Localizable.strings Binary files differindex 6489de796..96ae36764 100644 --- a/iOSClient/Supporting Files/es-UY.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es-UY.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/es.lproj/Localizable.strings b/iOSClient/Supporting Files/es.lproj/Localizable.strings Binary files differindex 11221ab03..067cf5a49 100644 --- a/iOSClient/Supporting Files/es.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/es.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/et_EE.lproj/Localizable.strings b/iOSClient/Supporting Files/et_EE.lproj/Localizable.strings Binary files differindex 144f0c633..3c5ca9b97 100644 --- a/iOSClient/Supporting Files/et_EE.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/et_EE.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/eu.lproj/Localizable.strings b/iOSClient/Supporting Files/eu.lproj/Localizable.strings Binary files differindex b62225672..0ad96afa1 100644 --- a/iOSClient/Supporting Files/eu.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/eu.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/fa.lproj/Localizable.strings b/iOSClient/Supporting Files/fa.lproj/Localizable.strings Binary files differindex 3361c9bba..cf44b0c48 100644 --- a/iOSClient/Supporting Files/fa.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/fa.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/fi-FI.lproj/Localizable.strings b/iOSClient/Supporting Files/fi-FI.lproj/Localizable.strings Binary files differindex 6ebb70204..5fe4efd52 100644 --- a/iOSClient/Supporting Files/fi-FI.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/fi-FI.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/fr.lproj/Localizable.strings b/iOSClient/Supporting Files/fr.lproj/Localizable.strings Binary files differindex f3904e5ff..474800104 100644 --- a/iOSClient/Supporting Files/fr.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/fr.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/gl.lproj/Localizable.strings b/iOSClient/Supporting Files/gl.lproj/Localizable.strings Binary files differindex 8e0bff546..bb9f2958e 100644 --- a/iOSClient/Supporting Files/gl.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/gl.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/he.lproj/Localizable.strings b/iOSClient/Supporting Files/he.lproj/Localizable.strings Binary files differindex b427493d4..c018f0daf 100644 --- a/iOSClient/Supporting Files/he.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/he.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/hr.lproj/Localizable.strings b/iOSClient/Supporting Files/hr.lproj/Localizable.strings Binary files differindex 49ee3670d..f0e5e87ed 100644 --- a/iOSClient/Supporting Files/hr.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/hr.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/hu.lproj/Localizable.strings b/iOSClient/Supporting Files/hu.lproj/Localizable.strings Binary files differindex b4785587d..f5c74bad9 100644 --- a/iOSClient/Supporting Files/hu.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/hu.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/ia.lproj/Localizable.strings b/iOSClient/Supporting Files/ia.lproj/Localizable.strings Binary files differindex 37098bbaa..90f8beb84 100644 --- a/iOSClient/Supporting Files/ia.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/ia.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/id.lproj/Localizable.strings b/iOSClient/Supporting Files/id.lproj/Localizable.strings Binary files differindex 6107a926f..df99eb24c 100644 --- a/iOSClient/Supporting Files/id.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/id.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/is.lproj/Localizable.strings b/iOSClient/Supporting Files/is.lproj/Localizable.strings Binary files differindex 50927126b..37a72f17d 100644 --- a/iOSClient/Supporting Files/is.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/is.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/it.lproj/Localizable.strings b/iOSClient/Supporting Files/it.lproj/Localizable.strings Binary files differindex 4ef22322f..55186b2f7 100644 --- a/iOSClient/Supporting Files/it.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/it.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/ja-JP.lproj/Localizable.strings b/iOSClient/Supporting Files/ja-JP.lproj/Localizable.strings Binary files differindex 571c6d459..fa64bf6cb 100644 --- a/iOSClient/Supporting Files/ja-JP.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/ja-JP.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/ka-GE.lproj/Localizable.strings b/iOSClient/Supporting Files/ka-GE.lproj/Localizable.strings Binary files differindex 24875fba5..a51cbe7f2 100644 --- a/iOSClient/Supporting Files/ka-GE.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/ka-GE.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/ko.lproj/Localizable.strings b/iOSClient/Supporting Files/ko.lproj/Localizable.strings Binary files differindex 2814501f1..a92f4615d 100644 --- a/iOSClient/Supporting Files/ko.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/ko.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/lb.lproj/Localizable.strings b/iOSClient/Supporting Files/lb.lproj/Localizable.strings Binary files differindex 584c1f931..ed5772bd7 100644 --- a/iOSClient/Supporting Files/lb.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/lb.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/lo.lproj/Localizable.strings b/iOSClient/Supporting Files/lo.lproj/Localizable.strings Binary files differindex 56f01cbab..dab2b2b9f 100644 --- a/iOSClient/Supporting Files/lo.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/lo.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/lt_LT.lproj/Localizable.strings b/iOSClient/Supporting Files/lt_LT.lproj/Localizable.strings Binary files differindex e74133cc5..1f31b8079 100644 --- a/iOSClient/Supporting Files/lt_LT.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/lt_LT.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/lv.lproj/Localizable.strings b/iOSClient/Supporting Files/lv.lproj/Localizable.strings Binary files differindex d6c6ee3fb..26f2e7cf5 100644 --- a/iOSClient/Supporting Files/lv.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/lv.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/mk.lproj/Localizable.strings b/iOSClient/Supporting Files/mk.lproj/Localizable.strings Binary files differindex e05b00b06..f61ad8027 100644 --- a/iOSClient/Supporting Files/mk.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/mk.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/mn.lproj/Localizable.strings b/iOSClient/Supporting Files/mn.lproj/Localizable.strings Binary files differindex 443624733..65807c359 100644 --- a/iOSClient/Supporting Files/mn.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/mn.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/nb-NO.lproj/Localizable.strings b/iOSClient/Supporting Files/nb-NO.lproj/Localizable.strings Binary files differindex 9cb28fe3e..2b11487af 100644 --- a/iOSClient/Supporting Files/nb-NO.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/nb-NO.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/nl.lproj/Localizable.strings b/iOSClient/Supporting Files/nl.lproj/Localizable.strings Binary files differindex 93d1a5958..fdfb0f35a 100644 --- a/iOSClient/Supporting Files/nl.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/nl.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/nn_NO.lproj/Localizable.strings b/iOSClient/Supporting Files/nn_NO.lproj/Localizable.strings Binary files differindex c4622dbac..da2a2b1a0 100644 --- a/iOSClient/Supporting Files/nn_NO.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/nn_NO.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/oc.lproj/Localizable.strings b/iOSClient/Supporting Files/oc.lproj/Localizable.strings Binary files differindex eec304ecb..8090f99c0 100644 --- a/iOSClient/Supporting Files/oc.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/oc.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/pl.lproj/Localizable.strings b/iOSClient/Supporting Files/pl.lproj/Localizable.strings Binary files differindex 1611218b5..c49bda67c 100644 --- a/iOSClient/Supporting Files/pl.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/pl.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/pt-BR.lproj/Localizable.strings b/iOSClient/Supporting Files/pt-BR.lproj/Localizable.strings Binary files differindex e180668b1..6054f4672 100644 --- a/iOSClient/Supporting Files/pt-BR.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/pt-BR.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/pt-PT.lproj/Localizable.strings b/iOSClient/Supporting Files/pt-PT.lproj/Localizable.strings Binary files differindex 574845498..3a0b0a2fc 100644 --- a/iOSClient/Supporting Files/pt-PT.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/pt-PT.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/ro.lproj/Localizable.strings b/iOSClient/Supporting Files/ro.lproj/Localizable.strings Binary files differindex 53abe2a4f..386fad178 100644 --- a/iOSClient/Supporting Files/ro.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/ro.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/ru.lproj/Localizable.strings b/iOSClient/Supporting Files/ru.lproj/Localizable.strings Binary files differindex 5bea5c25b..85698c41b 100644 --- a/iOSClient/Supporting Files/ru.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/ru.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/sc.lproj/Localizable.strings b/iOSClient/Supporting Files/sc.lproj/Localizable.strings Binary files differindex 7d91ca211..e3c7eda7b 100644 --- a/iOSClient/Supporting Files/sc.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/sc.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/si.lproj/Localizable.strings b/iOSClient/Supporting Files/si.lproj/Localizable.strings Binary files differindex f28e40ee7..27e552922 100644 --- a/iOSClient/Supporting Files/si.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/si.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/sk-SK.lproj/Localizable.strings b/iOSClient/Supporting Files/sk-SK.lproj/Localizable.strings Binary files differindex 9eaeb7d23..e06764a5c 100644 --- a/iOSClient/Supporting Files/sk-SK.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/sk-SK.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/sl.lproj/Localizable.strings b/iOSClient/Supporting Files/sl.lproj/Localizable.strings Binary files differindex 9532ac9bd..d20393a1e 100644 --- a/iOSClient/Supporting Files/sl.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/sl.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/sq.lproj/Localizable.strings b/iOSClient/Supporting Files/sq.lproj/Localizable.strings Binary files differindex 1232f5d2f..37225fe73 100644 --- a/iOSClient/Supporting Files/sq.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/sq.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/sr.lproj/Localizable.strings b/iOSClient/Supporting Files/sr.lproj/Localizable.strings Binary files differindex c842ff75f..f16069e25 100644 --- a/iOSClient/Supporting Files/sr.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/sr.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/sr@latin.lproj/Localizable.strings b/iOSClient/Supporting Files/sr@latin.lproj/Localizable.strings Binary files differindex cec026b46..c0a4bc668 100644 --- a/iOSClient/Supporting Files/sr@latin.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/sr@latin.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/sv.lproj/Localizable.strings b/iOSClient/Supporting Files/sv.lproj/Localizable.strings Binary files differindex 2b1674a54..eba3a29dd 100644 --- a/iOSClient/Supporting Files/sv.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/sv.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/th_TH.lproj/Localizable.strings b/iOSClient/Supporting Files/th_TH.lproj/Localizable.strings Binary files differindex 063b18774..7b654608a 100644 --- a/iOSClient/Supporting Files/th_TH.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/th_TH.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/tr.lproj/Localizable.strings b/iOSClient/Supporting Files/tr.lproj/Localizable.strings Binary files differindex cf76ef9ac..58f6c0895 100644 --- a/iOSClient/Supporting Files/tr.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/tr.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/uk.lproj/Localizable.strings b/iOSClient/Supporting Files/uk.lproj/Localizable.strings Binary files differindex 01110b2f7..69af5cc02 100644 --- a/iOSClient/Supporting Files/uk.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/uk.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/vi.lproj/Localizable.strings b/iOSClient/Supporting Files/vi.lproj/Localizable.strings Binary files differindex 00103a6e1..1ddc5eca7 100644 --- a/iOSClient/Supporting Files/vi.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/vi.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/zh-Hans.lproj/Localizable.strings b/iOSClient/Supporting Files/zh-Hans.lproj/Localizable.strings Binary files differindex 806b698cb..5185e2eb5 100644 --- a/iOSClient/Supporting Files/zh-Hans.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/zh-Hans.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/zh-Hant-TW.lproj/Localizable.strings b/iOSClient/Supporting Files/zh-Hant-TW.lproj/Localizable.strings Binary files differindex 9e4c7c045..49fed5d3b 100644 --- a/iOSClient/Supporting Files/zh-Hant-TW.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/zh-Hant-TW.lproj/Localizable.strings diff --git a/iOSClient/Supporting Files/zh_HK.lproj/Localizable.strings b/iOSClient/Supporting Files/zh_HK.lproj/Localizable.strings Binary files differindex 1a5ec2d14..e38510ffb 100644 --- a/iOSClient/Supporting Files/zh_HK.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/zh_HK.lproj/Localizable.strings diff --git a/iOSClient/Transfers/NCTransferCell.swift b/iOSClient/Transfers/NCTransferCell.swift index 770cbdeef..614e4f002 100755 --- a/iOSClient/Transfers/NCTransferCell.swift +++ b/iOSClient/Transfers/NCTransferCell.swift @@ -24,7 +24,7 @@ import UIKit class NCTransferCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProtocol { - + @IBOutlet weak var imageItem: UIImageView! @IBOutlet weak var labelTitle: UILabel! @IBOutlet weak var labelPath: UILabel! @@ -35,14 +35,14 @@ class NCTransferCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellP @IBOutlet weak var progressView: UIProgressView! @IBOutlet weak var separator: UIView! @IBOutlet weak var separatorHeightConstraint: NSLayoutConstraint! - + private var objectId = "" private var user = "" - - var delegate: NCTransferCellDelegate? + + weak var delegate: NCTransferCellDelegate? var indexPath = IndexPath() var namedButtonMore = "" - + var fileAvatarImageView: UIImageView? { get { return nil @@ -56,7 +56,7 @@ class NCTransferCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellP objectId = newValue ?? "" } } - var filePreviewImageView : UIImageView? { + var filePreviewImageView: UIImageView? { get { return imageItem } @@ -69,13 +69,13 @@ class NCTransferCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellP user = newValue ?? "" } } - + override func awakeFromNib() { super.awakeFromNib() - + imageItem.layer.cornerRadius = 6 imageItem.layer.masksToBounds = true - + progressView.tintColor = NCBrandColor.shared.brandElement progressView.transform = CGAffineTransform(scaleX: 1.0, y: 0.5) progressView.trackTintColor = .clear @@ -85,45 +85,45 @@ class NCTransferCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellP longPressedGesture.delegate = self longPressedGesture.delaysTouchesBegan = true self.addGestureRecognizer(longPressedGesture) - + let longPressedGestureMore = UILongPressGestureRecognizer(target: self, action: #selector(longPressInsideMore(gestureRecognizer:))) longPressedGestureMore.minimumPressDuration = 0.5 longPressedGestureMore.delegate = self longPressedGestureMore.delaysTouchesBegan = true buttonMore.addGestureRecognizer(longPressedGestureMore) - + separator.backgroundColor = NCBrandColor.shared.separator separatorHeightConstraint.constant = 0.5 } - + override func prepareForReuse() { super.prepareForReuse() imageItem.backgroundColor = nil } - + @IBAction func touchUpInsideShare(_ sender: Any) { delegate?.tapShareListItem(with: objectId, sender: sender) } - + @IBAction func touchUpInsideMore(_ sender: Any) { delegate?.tapMoreListItem(with: objectId, namedButtonMore: namedButtonMore, image: imageItem.image, sender: sender) } - + @objc func longPressInsideMore(gestureRecognizer: UILongPressGestureRecognizer) { delegate?.longPressMoreListItem(with: objectId, namedButtonMore: namedButtonMore, gestureRecognizer: gestureRecognizer) } - + @objc func longPress(gestureRecognizer: UILongPressGestureRecognizer) { delegate?.longPressListItem(with: objectId, gestureRecognizer: gestureRecognizer) } - + func setButtonMore(named: String, image: UIImage) { namedButtonMore = named imageMore.image = image } } -protocol NCTransferCellDelegate { +protocol NCTransferCellDelegate: AnyObject { func tapShareListItem(with objectId: String, sender: Any) func tapMoreListItem(with objectId: String, namedButtonMore: String, image: UIImage?, sender: Any) func longPressMoreListItem(with objectId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) diff --git a/iOSClient/Transfers/NCTransfers.swift b/iOSClient/Transfers/NCTransfers.swift index 0abc00023..bc5d022b0 100644 --- a/iOSClient/Transfers/NCTransfers.swift +++ b/iOSClient/Transfers/NCTransfers.swift @@ -24,184 +24,184 @@ import UIKit import NCCommunication -class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate { - +class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate { + var metadataTemp: tableMetadata? - + // MARK: - View Life Cycle required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - + titleCurrentFolder = NSLocalizedString("_transfers_", comment: "") layoutKey = NCGlobal.shared.layoutViewTransfers enableSearchBar = false - emptyImage = UIImage.init(named: "arrow.left.arrow.right")?.image(color: .gray, size: UIScreen.main.bounds.width) + emptyImage = UIImage(named: "arrow.left.arrow.right")?.image(color: .gray, size: UIScreen.main.bounds.width) emptyTitle = "_no_transfer_" emptyDescription = "_no_transfer_sub_" } - + override func viewDidLoad() { super.viewDidLoad() - + listLayout.itemHeight = 105 collectionView?.collectionViewLayout = listLayout self.navigationItem.title = titleCurrentFolder serverUrl = appDelegate.activeServerUrl } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + collectionView?.collectionViewLayout = listLayout } - + override func setNavigationItem() { self.navigationItem.rightBarButtonItem = nil self.navigationItem.leftBarButtonItem = nil } - + // MARK: - NotificationCenter - + override func downloadStartFile(_ notification: NSNotification) { - + reloadDataSource() } - + override func downloadedFile(_ notification: NSNotification) { - + reloadDataSource() } - + override func downloadCancelFile(_ notification: NSNotification) { - + reloadDataSource() } - + override func uploadStartFile(_ notification: NSNotification) { - + reloadDataSource() } - + override func uploadedFile(_ notification: NSNotification) { - + reloadDataSource() } - + override func uploadCancelFile(_ notification: NSNotification) { - + reloadDataSource() } - + // MARK: TAP EVENT - + override func longPressMoreListItem(with objectId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) { - + if gestureRecognizer.state != .began { return } - + let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .alert) - + alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil)) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_all_task_", comment: ""), style: .default, handler: { action in + alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_all_task_", comment: ""), style: .default, handler: { _ in NCNetworking.shared.cancelAllTransfer(account: self.appDelegate.account) { self.reloadDataSource() } })) - + self.present(alertController, animated: true, completion: nil) } - + override func longPressListItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer) { - + if gestureRecognizer.state != .began { return } - + if let metadata = NCManageDatabase.shared.getMetadataFromOcId(objectId) { metadataTemp = metadata let touchPoint = gestureRecognizer.location(in: collectionView) becomeFirstResponder() - let startTaskItem = UIMenuItem.init(title: NSLocalizedString("_force_start_", comment: ""), action: #selector(startTask(_:))) + let startTaskItem = UIMenuItem(title: NSLocalizedString("_force_start_", comment: ""), action: #selector(startTask(_:))) UIMenuController.shared.menuItems = [startTaskItem] UIMenuController.shared.setTargetRect(CGRect(x: touchPoint.x, y: touchPoint.y, width: 0, height: 0), in: collectionView) UIMenuController.shared.setMenuVisible(true, animated: true) } } - + override func longPressCollecationView(_ gestureRecognizer: UILongPressGestureRecognizer) { } - + @objc func startTask(_ notification: Any) { - + guard let metadata = metadataTemp else { return } - + metadata.status = NCGlobal.shared.metadataStatusInUpload metadata.session = NCCommunicationCommon.shared.sessionIdentifierUpload - + NCManageDatabase.shared.addMetadata(metadata) - NCNetworking.shared.upload(metadata: metadata) { } completion: { (_, _) in } + NCNetworking.shared.upload(metadata: metadata) { } completion: { _, _ in } } - + override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { - + if action != #selector(startTask(_:)) { return false } guard let metadata = metadataTemp else { return false } if metadata.e2eEncrypted { return false } - + if metadata.status == NCGlobal.shared.metadataStatusWaitUpload || metadata.status == NCGlobal.shared.metadataStatusInUpload || metadata.status == NCGlobal.shared.metadataStatusUploading { return true } - + return false } - + // MARK: - Collection View - + override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // nothing } - + override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.width, height: 0) } - + override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - + guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else { return collectionView.dequeueReusableCell(withReuseIdentifier: "transferCell", for: indexPath) as! NCTransferCell } - + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "transferCell", for: indexPath) as! NCTransferCell cell.delegate = self - + cell.fileObjectId = metadata.ocId cell.fileUser = metadata.ownerId cell.indexPath = indexPath - + cell.imageItem.image = nil cell.imageItem.backgroundColor = nil - + cell.labelTitle.text = metadata.fileNameView cell.labelTitle.textColor = NCBrandColor.shared.label - + let serverUrlHome = NCUtilityFileSystem.shared.getHomeServer(account: metadata.account) var pathText = metadata.serverUrl.replacingOccurrences(of: serverUrlHome, with: "") if pathText == "" { pathText = "/" } cell.labelPath.text = pathText - + cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop) cell.progressView.progress = 0.0 - + if FileManager().fileExists(atPath: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) { cell.imageItem.image = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) } else if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue && FileManager().fileExists(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)) { cell.imageItem.image = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)) } - + if cell.imageItem.image == nil { cell.imageItem.image = NCBrandColor.cacheImages.file } - + cell.labelInfo.text = CCUtility.dateDiff(metadata.date as Date) + " · " + CCUtility.transformedSize(metadata.size) - + // Transfer var progress: Float = 0.0 var totalBytes: Int64 = 0 @@ -209,14 +209,14 @@ class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate { progress = progressType.progress totalBytes = progressType.totalBytes } - + if metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusUploading { cell.progressView.isHidden = false cell.progressView.progress = progress } else { cell.progressView.isHidden = true } - + // Write status on Label Info switch metadata.status { case NCGlobal.shared.metadataStatusWaitDownload: @@ -252,32 +252,32 @@ class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate { cell.labelInfo.text = "" break } - + // Remove last separator if collectionView.numberOfItems(inSection: indexPath.section) == indexPath.row + 1 { cell.separator.isHidden = true } else { cell.separator.isHidden = false } - + return cell } - + // MARK: - DataSource + NC Endpoint override func reloadDataSource() { super.reloadDataSource() - + metadatasSource = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "status != %i", NCGlobal.shared.metadataStatusNormal), page: 1, limit: 100, sorted: "sessionTaskIdentifier", ascending: false) - self.dataSource = NCDataSource.init(metadatasSource: metadatasSource) - + self.dataSource = NCDataSource(metadatasSource: metadatasSource) + refreshControl.endRefreshing() collectionView.reloadData() } - + override func reloadDataSourceNetwork(forced: Bool = false) { super.reloadDataSourceNetwork(forced: forced) - + reloadDataSource() } } diff --git a/iOSClient/Trash/Cell/NCTrashListCell.swift b/iOSClient/Trash/Cell/NCTrashListCell.swift index 7f12785d4..13f83c183 100644 --- a/iOSClient/Trash/Cell/NCTrashListCell.swift +++ b/iOSClient/Trash/Cell/NCTrashListCell.swift @@ -24,49 +24,49 @@ import UIKit class NCTrashListCell: UICollectionViewCell { - + @IBOutlet weak var imageItem: UIImageView! @IBOutlet weak var imageItemLeftConstraint: NSLayoutConstraint! @IBOutlet weak var imageSelect: UIImageView! @IBOutlet weak var labelTitle: UILabel! @IBOutlet weak var labelInfo: UILabel! - + @IBOutlet weak var imageRestore: UIImageView! @IBOutlet weak var imageMore: UIImageView! @IBOutlet weak var buttonMore: UIButton! @IBOutlet weak var buttonRestore: UIButton! - + @IBOutlet weak var separator: UIView! @IBOutlet weak var separatorHeightConstraint: NSLayoutConstraint! - var delegate: NCTrashListCellDelegate? - + weak var delegate: NCTrashListCellDelegate? + var objectId = "" var indexPath = IndexPath() override func awakeFromNib() { super.awakeFromNib() - + imageRestore.image = NCBrandColor.cacheImages.buttonRestore imageMore.image = NCBrandColor.cacheImages.buttonMore - + imageItem.layer.cornerRadius = 6 imageItem.layer.masksToBounds = true - + separator.backgroundColor = NCBrandColor.shared.separator separatorHeightConstraint.constant = 0.5 } - + @IBAction func touchUpInsideMore(_ sender: Any) { delegate?.tapMoreListItem(with: objectId, image: imageItem.image, sender: sender) } - + @IBAction func touchUpInsideRestore(_ sender: Any) { delegate?.tapRestoreListItem(with: objectId, image: imageItem.image, sender: sender) } - + func selectMode(_ status: Bool) { if status { imageItemLeftConstraint.constant = 45 @@ -77,18 +77,18 @@ class NCTrashListCell: UICollectionViewCell { backgroundView = nil } } - + func selected(_ status: Bool) { if status { imageSelect.image = NCBrandColor.cacheImages.checkedYes - + let blurEffect = UIBlurEffect(style: .extraLight) let blurEffectView = UIVisualEffectView(effect: blurEffect) blurEffectView.frame = self.bounds blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight] blurEffectView.backgroundColor = NCBrandColor.shared.brandElement.withAlphaComponent(0.2) backgroundView = blurEffectView - + } else { imageSelect.image = NCBrandColor.cacheImages.checkedNo backgroundView = nil @@ -96,7 +96,7 @@ class NCTrashListCell: UICollectionViewCell { } } -protocol NCTrashListCellDelegate { +protocol NCTrashListCellDelegate: AnyObject { func tapRestoreListItem(with objectId: String, image: UIImage?, sender: Any) func tapMoreListItem(with objectId: String, image: UIImage?, sender: Any) } diff --git a/iOSClient/Trash/NCTrash.swift b/iOSClient/Trash/NCTrash.swift index 30dfe90d3..9647dfff9 100644 --- a/iOSClient/Trash/NCTrash.swift +++ b/iOSClient/Trash/NCTrash.swift @@ -24,8 +24,8 @@ import UIKit import NCCommunication -class NCTrash: UIViewController, UIGestureRecognizerDelegate, NCTrashListCellDelegate, NCGridCellDelegate, NCTrashSectionHeaderMenuDelegate, NCEmptyDataSetDelegate { - +class NCTrash: UIViewController, UIGestureRecognizerDelegate, NCTrashListCellDelegate, NCGridCellDelegate, NCTrashSectionHeaderMenuDelegate, NCEmptyDataSetDelegate { + @IBOutlet weak var collectionView: UICollectionView! var trashPath = "" @@ -34,10 +34,10 @@ class NCTrash: UIViewController, UIGestureRecognizerDelegate, NCTrashListCellDel var emptyDataSet: NCEmptyDataSet? internal let appDelegate = UIApplication.shared.delegate as! AppDelegate - + internal var isEditMode = false internal var selectOcId: [String] = [] - + private var datasource: [tableTrash] = [] private var layoutForView: NCGlobal.layoutForViewType? private var listLayout: NCListLayout! @@ -49,97 +49,97 @@ class NCTrash: UIViewController, UIGestureRecognizerDelegate, NCTrashListCellDel override func viewDidLoad() { super.viewDidLoad() - + view.backgroundColor = NCBrandColor.shared.systemBackground self.navigationController?.navigationBar.prefersLargeTitles = true // Cell - collectionView.register(UINib.init(nibName: "NCTrashListCell", bundle: nil), forCellWithReuseIdentifier: "listCell") - collectionView.register(UINib.init(nibName: "NCGridCell", bundle: nil), forCellWithReuseIdentifier: "gridCell") - + collectionView.register(UINib(nibName: "NCTrashListCell", bundle: nil), forCellWithReuseIdentifier: "listCell") + collectionView.register(UINib(nibName: "NCGridCell", bundle: nil), forCellWithReuseIdentifier: "gridCell") + // Header - Footer - collectionView.register(UINib.init(nibName: "NCTrashSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu") - collectionView.register(UINib.init(nibName: "NCTrashSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter") + collectionView.register(UINib(nibName: "NCTrashSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu") + collectionView.register(UINib(nibName: "NCTrashSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter") collectionView.alwaysBounceVertical = true collectionView.backgroundColor = NCBrandColor.shared.systemBackground listLayout = NCListLayout() gridLayout = NCGridLayout() - + // Add Refresh Control collectionView.addSubview(refreshControl) refreshControl.tintColor = .gray refreshControl.addTarget(self, action: #selector(loadListingTrash), for: .valueChanged) - + // Empty - emptyDataSet = NCEmptyDataSet.init(view: collectionView, offset: highHeader, delegate: self) - + emptyDataSet = NCEmptyDataSet(view: collectionView, offset: highHeader, delegate: self) + NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSource), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSource), object: nil) - + changeTheming() } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + appDelegate.activeViewController = self - + self.navigationItem.title = titleCurrentFolder layoutForView = NCUtility.shared.getLayoutForView(key: NCGlobal.shared.layoutViewTrash, serverUrl: "", sort: "date", ascending: false, titleButtonHeader: "_sorted_by_date_more_recent_") gridLayout.itemForLine = CGFloat(layoutForView?.itemForLine ?? 3) - + if layoutForView?.layout == NCGlobal.shared.layoutList { collectionView.collectionViewLayout = listLayout } else { collectionView.collectionViewLayout = gridLayout } - + if trashPath == "" { guard let userId = (appDelegate.userId as NSString).addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlFragmentAllowed) else { return } trashPath = appDelegate.urlBase + "/" + NCUtilityFileSystem.shared.getWebDAV(account: appDelegate.account) + "/trashbin/" + userId + "/trash/" } reloadDataSource() } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + loadListingTrash() } - + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) - + coordinator.animate(alongsideTransition: nil) { _ in self.collectionView?.collectionViewLayout.invalidateLayout() } } - + @objc func changeTheming() { collectionView.reloadData() } - + // MARK: - Empty - + func emptyDataSetView(_ view: NCEmptyView) { - - view.emptyImage.image = UIImage.init(named: "trash")?.image(color: .gray, size: UIScreen.main.bounds.width) + + view.emptyImage.image = UIImage(named: "trash")?.image(color: .gray, size: UIScreen.main.bounds.width) view.emptyTitle.text = NSLocalizedString("_trash_no_trash_", comment: "") view.emptyDescription.text = NSLocalizedString("_trash_no_trash_description_", comment: "") } - + // MARK: TAP EVENT - + func tapSwitchHeaderMenu(sender: Any) { - + if collectionView.collectionViewLayout == gridLayout { // list layout UIView.animate(withDuration: 0.0, animations: { self.collectionView.collectionViewLayout.invalidateLayout() - self.collectionView.setCollectionViewLayout(self.listLayout, animated: false, completion: { (_) in + self.collectionView.setCollectionViewLayout(self.listLayout, animated: false, completion: { _ in self.collectionView.reloadData() }) }) @@ -149,7 +149,7 @@ class NCTrash: UIViewController, UIGestureRecognizerDelegate, NCTrashListCellDel // grid layout UIView.animate(withDuration: 0.0, animations: { self.collectionView.collectionViewLayout.invalidateLayout() - self.collectionView.setCollectionViewLayout(self.gridLayout, animated: false, completion: { (_) in + self.collectionView.setCollectionViewLayout(self.gridLayout, animated: false, completion: { _ in self.collectionView.reloadData() }) }) @@ -157,31 +157,31 @@ class NCTrash: UIViewController, UIGestureRecognizerDelegate, NCTrashListCellDel NCUtility.shared.setLayoutForView(key: NCGlobal.shared.layoutViewTrash, serverUrl: "", layout: layoutForView?.layout) } } - + func tapOrderHeaderMenu(sender: Any) { - + let sortMenu = NCSortMenu() sortMenu.toggleMenu(viewController: self, key: NCGlobal.shared.layoutViewTrash, sortButton: sender as? UIButton, serverUrl: "", hideDirectoryOnTop: true) } - + func tapMoreHeaderMenu(sender: Any) { - + toggleMenuMoreHeader() } - + func tapRestoreListItem(with ocId: String, image: UIImage?, sender: Any) { - + if !isEditMode { restoreItem(with: ocId) } else { - let buttonPosition:CGPoint = (sender as! UIButton).convert(CGPoint.zero, to:collectionView) + let buttonPosition: CGPoint = (sender as! UIButton).convert(CGPoint.zero, to: collectionView) let indexPath = collectionView.indexPathForItem(at: buttonPosition) collectionView(self.collectionView, didSelectItemAt: indexPath!) } } - + func tapMoreListItem(with objectId: String, image: UIImage?, sender: Any) { - + if !isEditMode { toggleMenuMoreList(with: objectId, image: image) } else { @@ -190,9 +190,9 @@ class NCTrash: UIViewController, UIGestureRecognizerDelegate, NCTrashListCellDel collectionView(self.collectionView, didSelectItemAt: indexPath!) } } - + func tapMoreGridItem(with objectId: String, namedButtonMore: String, image: UIImage?, sender: Any) { - + if !isEditMode { toggleMenuMoreGrid(with: objectId, namedButtonMore: namedButtonMore, image: image) } else { @@ -204,7 +204,7 @@ class NCTrash: UIViewController, UIGestureRecognizerDelegate, NCTrashListCellDel func longPressGridItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer) { } - + func longPressMoreGridItem(with objectId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) { } } @@ -214,9 +214,9 @@ class NCTrash: UIViewController, UIGestureRecognizerDelegate, NCTrashListCellDel extension NCTrash: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - + let tableTrash = datasource[indexPath.item] - + if isEditMode { if let index = selectOcId.firstIndex(of: tableTrash.fileId) { selectOcId.remove(at: index) @@ -226,14 +226,14 @@ extension NCTrash: UICollectionViewDelegate { collectionView.reloadItems(at: [indexPath]) return } - + if tableTrash.directory { - - let ncTrash:NCTrash = UIStoryboard(name: "NCTrash", bundle: nil).instantiateInitialViewController() as! NCTrash - + + let ncTrash: NCTrash = UIStoryboard(name: "NCTrash", bundle: nil).instantiateInitialViewController() as! NCTrash + ncTrash.trashPath = tableTrash.filePath + tableTrash.fileName ncTrash.titleCurrentFolder = tableTrash.trashbinFileName - + self.navigationController?.pushViewController(ncTrash, animated: true) } } @@ -242,69 +242,69 @@ extension NCTrash: UICollectionViewDelegate { extension NCTrash: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - + if kind == UICollectionView.elementKindSectionHeader { - + let trashHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderMenu", for: indexPath) as! NCTrashSectionHeaderMenu - + if collectionView.collectionViewLayout == gridLayout { - trashHeader.buttonSwitch.setImage(UIImage.init(named: "switchList")?.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) + trashHeader.buttonSwitch.setImage(UIImage(named: "switchList")?.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) } else { - trashHeader.buttonSwitch.setImage(UIImage.init(named: "switchGrid")?.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) + trashHeader.buttonSwitch.setImage(UIImage(named: "switchGrid")?.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) } - + trashHeader.delegate = self trashHeader.backgroundColor = NCBrandColor.shared.systemBackground trashHeader.separator.backgroundColor = NCBrandColor.shared.separator trashHeader.setStatusButton(datasource: datasource) trashHeader.setTitleSorted(datasourceTitleButton: layoutForView?.titleButtonHeader ?? "") - + return trashHeader - + } else { - + let trashFooter = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as! NCTrashSectionFooter - + trashFooter.setTitleLabelFooter(datasource: datasource) - + return trashFooter } } - + func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } - + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { emptyDataSet?.numberOfItemsInSection(datasource.count, section: section) return datasource.count } - + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - + let tableTrash = datasource[indexPath.item] var image: UIImage? - + if tableTrash.iconName.count > 0 { - image = UIImage.init(named: tableTrash.iconName) + image = UIImage(named: tableTrash.iconName) } else { - image = UIImage.init(named: "file") + image = UIImage(named: "file") } - + if FileManager().fileExists(atPath: CCUtility.getDirectoryProviderStorageIconOcId(tableTrash.fileId, etag: tableTrash.fileName)) { - image = UIImage.init(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(tableTrash.fileId, etag: tableTrash.fileName)) + image = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(tableTrash.fileId, etag: tableTrash.fileName)) } else { if tableTrash.hasPreview && !CCUtility.fileProviderStoragePreviewIconExists(tableTrash.fileId, etag: tableTrash.fileName) { downloadThumbnail(with: tableTrash, indexPath: indexPath) } } - + if collectionView.collectionViewLayout == listLayout { - + // LIST let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! NCTrashListCell cell.delegate = self - + cell.objectId = tableTrash.fileId cell.indexPath = indexPath cell.labelTitle.text = tableTrash.trashbinFileName @@ -317,7 +317,7 @@ extension NCTrash: UICollectionViewDataSource { cell.imageItem.image = image cell.labelInfo.text = CCUtility.dateDiff(tableTrash.date as Date) + ", " + CCUtility.transformedSize(tableTrash.size) } - + if isEditMode { cell.selectMode(true) if selectOcId.contains(tableTrash.fileId) { @@ -328,26 +328,26 @@ extension NCTrash: UICollectionViewDataSource { } else { cell.selectMode(false) } - + return cell - + } else { - + // GRID let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as! NCGridCell cell.delegate = self - + cell.fileObjectId = tableTrash.fileId cell.labelTitle.text = tableTrash.trashbinFileName cell.labelTitle.textColor = NCBrandColor.shared.label cell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCBrandColor.cacheImages.buttonMore) - + if tableTrash.directory { cell.imageItem.image = NCBrandColor.cacheImages.folder } else { cell.imageItem.image = image } - + if isEditMode { cell.imageSelect.isHidden = false if selectOcId.contains(tableTrash.fileId) { @@ -369,7 +369,7 @@ extension NCTrash: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.width, height: highHeader) } - + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.width, height: highHeader) } @@ -380,26 +380,26 @@ extension NCTrash: UICollectionViewDelegateFlowLayout { extension NCTrash { @objc func reloadDataSource() { - + layoutForView = NCUtility.shared.getLayoutForView(key: NCGlobal.shared.layoutViewTrash, serverUrl: "") - + datasource.removeAll() - + guard let tashItems = NCManageDatabase.shared.getTrash(filePath: trashPath, sort: layoutForView?.sort, ascending: layoutForView?.ascending, account: appDelegate.account) else { return } - + datasource = tashItems collectionView.reloadData() - + if self.blinkFileId != nil { for item in 0...self.datasource.count-1 { if self.datasource[item].fileId.contains(self.blinkFileId!) { let indexPath = IndexPath(item: item, section: 0) DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { UIView.animate(withDuration: 0.3) { - self.collectionView.scrollToItem(at:indexPath, at: .centeredVertically, animated: false) - } completion: { (_) in + self.collectionView.scrollToItem(at: indexPath, at: .centeredVertically, animated: false) + } completion: { _ in if let cell = self.collectionView.cellForItem(at: indexPath) { cell.backgroundColor = .darkGray UIView.animate(withDuration: 2) { @@ -413,11 +413,11 @@ extension NCTrash { } } } - + @objc func loadListingTrash() { - - NCCommunication.shared.listingTrash(showHiddenFiles: false, queue: NCCommunicationCommon.shared.backgroundQueue) { (account, items, errorCode, errorDescription) in - + + NCCommunication.shared.listingTrash(showHiddenFiles: false, queue: NCCommunicationCommon.shared.backgroundQueue) { account, items, errorCode, errorDescription in + if errorCode == 0 && account == self.appDelegate.account { NCManageDatabase.shared.deleteTrash(filePath: self.trashPath, account: self.appDelegate.account) NCManageDatabase.shared.addTrash(account: account, items: items) @@ -426,40 +426,40 @@ extension NCTrash { } else { print("[LOG] It has been changed user during networking process, error.") } - + DispatchQueue.main.async { self.refreshControl.endRefreshing() self.reloadDataSource() } } } - + func restoreItem(with fileId: String) { - + guard let tableTrash = NCManageDatabase.shared.getTrashItem(fileId: fileId, account: appDelegate.account) else { return } - + let fileNameFrom = tableTrash.filePath + tableTrash.fileName let fileNameTo = appDelegate.urlBase + "/" + NCUtilityFileSystem.shared.getWebDAV(account: appDelegate.account) + "/trashbin/" + appDelegate.userId + "/restore/" + tableTrash.fileName - - NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: fileNameFrom, serverUrlFileNameDestination: fileNameTo, overwrite: true) { (account, errorCode, errorDescription) in + + NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: fileNameFrom, serverUrlFileNameDestination: fileNameTo, overwrite: true) { account, errorCode, errorDescription in if errorCode == 0 && account == self.appDelegate.account { NCManageDatabase.shared.deleteTrash(fileId: fileId, account: account) self.reloadDataSource() - } else if errorCode != 0 { + } else if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } else { print("[LOG] It has been changed user during networking process, error.") } } } - + func emptyTrash() { - + let serverUrlFileName = appDelegate.urlBase + "/" + NCUtilityFileSystem.shared.getWebDAV(account: appDelegate.account) + "/trashbin/" + appDelegate.userId + "/trash" - NCCommunication.shared.deleteFileOrFolder(serverUrlFileName) { (account, errorCode, errorDescription) in + NCCommunication.shared.deleteFileOrFolder(serverUrlFileName) { account, errorCode, errorDescription in if errorCode == 0 && account == self.appDelegate.account { NCManageDatabase.shared.deleteTrash(fileId: nil, account: self.appDelegate.account) } else if errorCode != 0 { @@ -470,16 +470,16 @@ extension NCTrash { self.reloadDataSource() } } - + func deleteItem(with fileId: String) { - + guard let tableTrash = NCManageDatabase.shared.getTrashItem(fileId: fileId, account: appDelegate.account) else { return } - + let serverUrlFileName = tableTrash.filePath + tableTrash.fileName - - NCCommunication.shared.deleteFileOrFolder(serverUrlFileName) { (account, errorCode, errorDescription) in + + NCCommunication.shared.deleteFileOrFolder(serverUrlFileName) { account, errorCode, errorDescription in if errorCode == 0 && account == self.appDelegate.account { NCManageDatabase.shared.deleteTrash(fileId: fileId, account: account) self.reloadDataSource() @@ -490,14 +490,14 @@ extension NCTrash { } } } - + func downloadThumbnail(with tableTrash: tableTrash, indexPath: IndexPath) { - + let fileNamePreviewLocalPath = CCUtility.getDirectoryProviderStoragePreviewOcId(tableTrash.fileId, etag: tableTrash.fileName)! let fileNameIconLocalPath = CCUtility.getDirectoryProviderStorageIconOcId(tableTrash.fileId, etag: tableTrash.fileName)! - - NCCommunication.shared.downloadPreview(fileNamePathOrFileId: tableTrash.fileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, widthPreview: NCGlobal.shared.sizePreview, heightPreview: NCGlobal.shared.sizePreview, fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon, etag: nil, endpointTrashbin: true) { (account, imagePreview, imageIcon, imageOriginal, etag, errorCode, errorDescription) in - + + NCCommunication.shared.downloadPreview(fileNamePathOrFileId: tableTrash.fileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, widthPreview: NCGlobal.shared.sizePreview, heightPreview: NCGlobal.shared.sizePreview, fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon, etag: nil, endpointTrashbin: true) { account, _, imageIcon, _, _, errorCode, _ in + if errorCode == 0 && imageIcon != nil && account == self.appDelegate.account { if let cell = self.collectionView.cellForItem(at: indexPath) { if cell is NCTrashListCell { diff --git a/iOSClient/Trash/Section/NCTrashSectionHeaderFooter.swift b/iOSClient/Trash/Section/NCTrashSectionHeaderFooter.swift index d861cd31d..c919e41f5 100644 --- a/iOSClient/Trash/Section/NCTrashSectionHeaderFooter.swift +++ b/iOSClient/Trash/Section/NCTrashSectionHeaderFooter.swift @@ -24,7 +24,7 @@ import UIKit class NCTrashSectionHeaderMenu: UICollectionReusableView { - + @IBOutlet weak var buttonMore: UIButton! @IBOutlet weak var buttonSwitch: UIButton! @IBOutlet weak var buttonOrder: UIButton! @@ -32,35 +32,35 @@ class NCTrashSectionHeaderMenu: UICollectionReusableView { @IBOutlet weak var separator: UIView! @IBOutlet weak var separatorHeightConstraint: NSLayoutConstraint! - var delegate: NCTrashSectionHeaderMenuDelegate? + weak var delegate: NCTrashSectionHeaderMenuDelegate? override func awakeFromNib() { super.awakeFromNib() - - buttonSwitch.setImage(UIImage.init(named: "switchList")!.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) - + + buttonSwitch.setImage(UIImage(named: "switchList")!.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) + buttonOrder.setTitle("", for: .normal) buttonOrder.setTitleColor(NCBrandColor.shared.brandElement, for: .normal) - - buttonMore.setImage(UIImage.init(named: "more")!.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) - + + buttonMore.setImage(UIImage(named: "more")!.image(color: NCBrandColor.shared.gray, size: 25), for: .normal) + separator.backgroundColor = NCBrandColor.shared.separator separatorHeightConstraint.constant = 0.5 backgroundColor = NCBrandColor.shared.systemBackground } - + func setTitleSorted(datasourceTitleButton: String) { - + let title = NSLocalizedString(datasourceTitleButton, comment: "") - let size = title.size(withAttributes:[.font: buttonOrder.titleLabel?.font as Any]) - + let size = title.size(withAttributes: [.font: buttonOrder.titleLabel?.font as Any]) + buttonOrder.setTitle(title, for: .normal) buttonOrderWidthConstraint.constant = size.width + 5 } - + func setStatusButton(datasource: [tableTrash]) { - + if datasource.count == 0 { buttonSwitch.isEnabled = false buttonOrder.isEnabled = false @@ -71,63 +71,63 @@ class NCTrashSectionHeaderMenu: UICollectionReusableView { buttonMore.isEnabled = true } } - + @IBAction func touchUpInsideMore(_ sender: Any) { delegate?.tapMoreHeaderMenu(sender: sender) } - + @IBAction func touchUpInsideSwitch(_ sender: Any) { delegate?.tapSwitchHeaderMenu(sender: sender) } - + @IBAction func touchUpInsideOrder(_ sender: Any) { delegate?.tapOrderHeaderMenu(sender: sender) } } -protocol NCTrashSectionHeaderMenuDelegate { +protocol NCTrashSectionHeaderMenuDelegate: AnyObject { func tapSwitchHeaderMenu(sender: Any) func tapMoreHeaderMenu(sender: Any) func tapOrderHeaderMenu(sender: Any) } class NCTrashSectionFooter: UICollectionReusableView { - + @IBOutlet weak var labelFooter: UILabel! override func awakeFromNib() { super.awakeFromNib() - + labelFooter.textColor = NCBrandColor.shared.gray } - + func setTitleLabelFooter(datasource: [tableTrash]) { - + var folders: Int = 0, foldersText = "" var files: Int = 0, filesText = "" var size: Int64 = 0 - + for record: tableTrash in datasource { if record.directory { folders += 1 } else { files += 1 - size = size + record.size + size += record.size } } - + if folders > 1 { foldersText = "\(folders) " + NSLocalizedString("_folders_", comment: "") } else if folders == 1 { foldersText = "1 " + NSLocalizedString("_folder_", comment: "") } - + if files > 1 { filesText = "\(files) " + NSLocalizedString("_files_", comment: "") + " " + CCUtility.transformedSize(size) } else if files == 1 { filesText = "1 " + NSLocalizedString("_file_", comment: "") + " " + CCUtility.transformedSize(size) } - + if foldersText == "" { labelFooter.text = filesText } else if filesText == "" { diff --git a/iOSClient/UserStatus/NCUserStatus.swift b/iOSClient/UserStatus/NCUserStatus.swift index 0f71c364b..bd0cda98d 100644 --- a/iOSClient/UserStatus/NCUserStatus.swift +++ b/iOSClient/UserStatus/NCUserStatus.swift @@ -29,17 +29,17 @@ import DropDown @available(iOS 13.0, *) class NCUserStatus: UIViewController { - + @IBOutlet weak var buttonCancel: UIBarButtonItem! @IBOutlet weak var onlineButton: UIButton! @IBOutlet weak var onlineImage: UIImageView! @IBOutlet weak var onlineLabel: UILabel! - + @IBOutlet weak var awayButton: UIButton! @IBOutlet weak var awayImage: UIImageView! @IBOutlet weak var awayLabel: UILabel! - + @IBOutlet weak var dndButton: UIButton! @IBOutlet weak var dndImage: UIImageView! @IBOutlet weak var dndLabel: UILabel! @@ -49,34 +49,32 @@ class NCUserStatus: UIViewController { @IBOutlet weak var invisibleImage: UIImageView! @IBOutlet weak var invisibleLabel: UILabel! @IBOutlet weak var invisibleDescrLabel: UILabel! - + @IBOutlet weak var statusMessageLabel: UILabel! @IBOutlet weak var statusMessageEmojiTextField: emojiTextField! @IBOutlet weak var statusMessageTextField: UITextField! - + @IBOutlet weak var tableView: UITableView! - + @IBOutlet weak var clearStatusMessageAfterLabel: UILabel! @IBOutlet weak var clearStatusMessageAfterText: UILabel! @IBOutlet weak var clearStatusMessageButton: UIButton! @IBOutlet weak var setStatusMessageButton: UIButton! - private let appDelegate = UIApplication.shared.delegate as! AppDelegate - private var statusPredefinedStatuses: [NCCommunicationUserStatus] = [] - + private var clearAtTimestamp: Double = 0 // Unix Timestamp representing the time to clear the status - + private let borderWidthButton: CGFloat = 1.5 private let borderColorButton: CGColor = NCBrandColor.shared.brand.cgColor - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + self.navigationItem.title = NSLocalizedString("_online_status_", comment: "") buttonCancel.title = NSLocalizedString("_close_", comment: "") @@ -88,7 +86,7 @@ class NCUserStatus: UIViewController { onlineImage.image = onLine.onlineStatus onlineLabel.text = onLine.statusMessage onlineLabel.textColor = NCBrandColor.shared.label - + awayButton.layer.cornerRadius = 10 awayButton.layer.masksToBounds = true awayButton.backgroundColor = NCBrandColor.shared.systemGray5 @@ -96,7 +94,7 @@ class NCUserStatus: UIViewController { awayImage.image = away.onlineStatus awayLabel.text = away.statusMessage awayLabel.textColor = NCBrandColor.shared.label - + dndButton.layer.cornerRadius = 10 dndButton.layer.masksToBounds = true dndButton.backgroundColor = NCBrandColor.shared.systemGray5 @@ -106,7 +104,7 @@ class NCUserStatus: UIViewController { dndLabel.textColor = NCBrandColor.shared.label dndDescrLabel.text = dnd.descriptionMessage dndDescrLabel.textColor = .darkGray - + invisibleButton.layer.cornerRadius = 10 invisibleButton.layer.masksToBounds = true invisibleButton.backgroundColor = NCBrandColor.shared.systemGray5 @@ -116,23 +114,23 @@ class NCUserStatus: UIViewController { invisibleLabel.textColor = NCBrandColor.shared.label invisibleDescrLabel.text = invisible.descriptionMessage invisibleDescrLabel.textColor = .darkGray - + statusMessageLabel.text = NSLocalizedString("_status_message_", comment: "") statusMessageLabel.textColor = NCBrandColor.shared.label statusMessageEmojiTextField.delegate = self statusMessageEmojiTextField.backgroundColor = NCBrandColor.shared.systemGray5 - + statusMessageTextField.delegate = self statusMessageTextField.placeholder = NSLocalizedString("_status_message_placehorder_", comment: "") statusMessageTextField.textColor = NCBrandColor.shared.label - + tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 1)) tableView.separatorStyle = UITableViewCell.SeparatorStyle.none - + clearStatusMessageAfterLabel.text = NSLocalizedString("_clear_status_message_after_", comment: "") clearStatusMessageAfterLabel.textColor = NCBrandColor.shared.label - + clearStatusMessageAfterText.layer.cornerRadius = 5 clearStatusMessageAfterText.layer.masksToBounds = true clearStatusMessageAfterText.layer.borderWidth = 0.2 @@ -149,7 +147,7 @@ class NCUserStatus: UIViewController { clearStatusMessageAfterText.isUserInteractionEnabled = true clearStatusMessageAfterText.addGestureRecognizer(tap) clearStatusMessageAfterText.text = " " + NSLocalizedString("_dont_clear_", comment: "") - + clearStatusMessageButton.layer.cornerRadius = 15 clearStatusMessageButton.layer.masksToBounds = true clearStatusMessageButton.layer.borderWidth = 0.5 @@ -157,7 +155,7 @@ class NCUserStatus: UIViewController { clearStatusMessageButton.backgroundColor = NCBrandColor.shared.systemGray5 clearStatusMessageButton.setTitle(NSLocalizedString("_clear_status_message_", comment: ""), for: .normal) clearStatusMessageButton.setTitleColor(NCBrandColor.shared.label, for: .normal) - + setStatusMessageButton.layer.cornerRadius = 15 setStatusMessageButton.layer.masksToBounds = true setStatusMessageButton.backgroundColor = NCBrandColor.shared.brand @@ -166,25 +164,25 @@ class NCUserStatus: UIViewController { getStatus() } - + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - + changeTheming() } - + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - - NCCommunication.shared.getUserStatus { (account, clearAt, icon, message, messageId, messageIsPredefined, status, statusIsUserDefined, userId, errorCode, errorDescription) in - + + NCCommunication.shared.getUserStatus { account, clearAt, icon, message, messageId, messageIsPredefined, status, statusIsUserDefined, _, errorCode, _ in + if errorCode == 0 { - + NCManageDatabase.shared.setAccountUserStatus(userStatusClearAt: clearAt, userStatusIcon: icon, userStatusMessage: message, userStatusMessageId: messageId, userStatusMessageIsPredefined: messageIsPredefined, userStatusStatus: status, userStatusStatusIsUserDefined: statusIsUserDefined, account: account) } } } - + func dismissIfError(_ errorCode: Int, errorDescription: String) { if errorCode != 0 && errorCode != NCGlobal.shared.errorResourceNotFound { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { @@ -194,25 +192,25 @@ class NCUserStatus: UIViewController { } } } - + // MARK: - Theming - + @objc func changeTheming() { - + view.backgroundColor = NCBrandColor.shared.systemBackground tableView.backgroundColor = NCBrandColor.shared.systemBackground - + tableView.reloadData() } - + // MARK: ACTION - + @IBAction func actionCancel(_ sender: UIBarButtonItem) { self.dismiss(animated: true, completion: nil) } - + @IBAction func actionOnline(_ sender: UIButton) { - + self.onlineButton.layer.borderWidth = self.borderWidthButton self.onlineButton.layer.borderColor = self.borderColorButton self.awayButton.layer.borderWidth = 0 @@ -221,14 +219,14 @@ class NCUserStatus: UIViewController { self.dndButton.layer.borderColor = nil self.invisibleButton.layer.borderWidth = 0 self.invisibleButton.layer.borderColor = nil - - NCCommunication.shared.setUserStatus(status: "online") { account, errorCode, errorDescription in + + NCCommunication.shared.setUserStatus(status: "online") { _, errorCode, errorDescription in self.dismissIfError(errorCode, errorDescription: errorDescription) } } - + @IBAction func actionAway(_ sender: UIButton) { - + self.onlineButton.layer.borderWidth = 0 self.onlineButton.layer.borderColor = nil self.awayButton.layer.borderWidth = self.borderWidthButton @@ -237,14 +235,14 @@ class NCUserStatus: UIViewController { self.dndButton.layer.borderColor = nil self.invisibleButton.layer.borderWidth = 0 self.invisibleButton.layer.borderColor = nil - - NCCommunication.shared.setUserStatus(status: "away") { account, errorCode, errorDescription in + + NCCommunication.shared.setUserStatus(status: "away") { _, errorCode, errorDescription in self.dismissIfError(errorCode, errorDescription: errorDescription) } } - + @IBAction func actionDnd(_ sender: UIButton) { - + self.onlineButton.layer.borderWidth = 0 self.onlineButton.layer.borderColor = nil self.awayButton.layer.borderWidth = 0 @@ -253,14 +251,14 @@ class NCUserStatus: UIViewController { self.dndButton.layer.borderColor = self.borderColorButton self.invisibleButton.layer.borderWidth = 0 self.invisibleButton.layer.borderColor = nil - - NCCommunication.shared.setUserStatus(status: "dnd") { account, errorCode, errorDescription in + + NCCommunication.shared.setUserStatus(status: "dnd") { _, errorCode, errorDescription in self.dismissIfError(errorCode, errorDescription: errorDescription) } } - + @IBAction func actionInvisible(_ sender: UIButton) { - + self.onlineButton.layer.borderWidth = 0 self.onlineButton.layer.borderColor = nil self.awayButton.layer.borderWidth = 0 @@ -269,18 +267,18 @@ class NCUserStatus: UIViewController { self.dndButton.layer.borderColor = nil self.invisibleButton.layer.borderWidth = self.borderWidthButton self.invisibleButton.layer.borderColor = self.borderColorButton - - NCCommunication.shared.setUserStatus(status: "invisible") { account, errorCode, errorDescription in + + NCCommunication.shared.setUserStatus(status: "invisible") { _, errorCode, errorDescription in self.dismissIfError(errorCode, errorDescription: errorDescription) } } - - @objc func actionClearStatusMessageAfterText(sender:UITapGestureRecognizer) { + + @objc func actionClearStatusMessageAfterText(sender: UITapGestureRecognizer) { let dropDown = DropDown() let appearance = DropDown.appearance() let clearStatusMessageAfterTextBackup = clearStatusMessageAfterText.text - + if traitCollection.userInterfaceStyle == .dark { appearance.backgroundColor = .black appearance.textColor = .white @@ -293,7 +291,7 @@ class NCUserStatus: UIViewController { appearance.animationEntranceOptions = .transitionCurlUp appearance.animationduration = 0.25 appearance.setupMaskedCorners([.layerMaxXMaxYCorner, .layerMinXMaxYCorner]) - + dropDown.dataSource.append(NSLocalizedString("_dont_clear_", comment: "")) dropDown.dataSource.append(NSLocalizedString("_30_minutes_", comment: "")) dropDown.dataSource.append(NSLocalizedString("_1_hour_", comment: "")) @@ -305,68 +303,68 @@ class NCUserStatus: UIViewController { dropDown.topOffset = CGPoint(x: 0, y: -clearStatusMessageAfterText.bounds.height) dropDown.width = clearStatusMessageAfterText.bounds.width dropDown.direction = .top - - dropDown.selectionAction = { (index, item) in - + + dropDown.selectionAction = { _, item in + self.clearAtTimestamp = self.getClearAt(item) self.clearStatusMessageAfterText.text = " " + item } - + dropDown.cancelAction = { [unowned self] in clearStatusMessageAfterText.text = clearStatusMessageAfterTextBackup } - + clearStatusMessageAfterText.text = " " + NSLocalizedString("_select_option_", comment: "") - + dropDown.show() } - + @IBAction func actionClearStatusMessage(_ sender: UIButton) { - - NCCommunication.shared.clearMessage { account, errorCode, errorDescription in - + + NCCommunication.shared.clearMessage { _, errorCode, errorDescription in + if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } - + self.dismiss(animated: true) } } - + @IBAction func actionSetStatusMessage(_ sender: UIButton) { - + guard let message = statusMessageTextField.text else { return } - - NCCommunication.shared.setCustomMessageUserDefined(statusIcon: statusMessageEmojiTextField.text, message: message, clearAt: clearAtTimestamp) { account, errorCode, errorDescription in - + + NCCommunication.shared.setCustomMessageUserDefined(statusIcon: statusMessageEmojiTextField.text, message: message, clearAt: clearAtTimestamp) { _, errorCode, errorDescription in + if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } - + self.dismiss(animated: true) } } - + // MARK: - Networking - + func getStatus() { - - NCCommunication.shared.getUserStatus { account, clearAt, icon, message, messageId, messageIsPredefined, status, statusIsUserDefined, userId, errorCode, errorDescription in - + + NCCommunication.shared.getUserStatus { _, clearAt, icon, message, _, _, status, _, _, errorCode, errorDescription in + if errorCode == 0 || errorCode == NCGlobal.shared.errorResourceNotFound { - + if icon != nil { self.statusMessageEmojiTextField.text = icon } - + if message != nil { self.statusMessageTextField.text = message } - + if clearAt != nil { self.clearStatusMessageAfterText.text = " " + self.getPredefinedClearStatusText(clearAt: clearAt, clearAtTime: nil, clearAtType: nil) } - + switch status { case "online": self.onlineButton.layer.borderWidth = self.borderWidthButton @@ -383,40 +381,40 @@ class NCUserStatus: UIViewController { default: print("No status") } - - NCCommunication.shared.getUserStatusPredefinedStatuses { account, userStatuses, errorCode, errorDescription in - + + NCCommunication.shared.getUserStatusPredefinedStatuses { _, userStatuses, errorCode, errorDescription in + if errorCode == 0 { - + if let userStatuses = userStatuses { self.statusPredefinedStatuses = userStatuses } - + self.tableView.reloadData() } - + self.dismissIfError(errorCode, errorDescription: errorDescription) } - + } - + self.dismissIfError(errorCode, errorDescription: errorDescription) } } - + // MARK: - Algorithms func getClearAt(_ clearAtString: String) -> Double { - + let now = Date() let calendar = Calendar.current let gregorian = Calendar(identifier: .gregorian) let midnight = calendar.startOfDay(for: now) - + guard let tomorrow = calendar.date(byAdding: .day, value: 1, to: midnight) else { return 0 } guard let startweek = gregorian.date(from: gregorian.dateComponents([.yearForWeekOfYear, .weekOfYear], from: now)) else { return 0 } guard let endweek = gregorian.date(byAdding: .day, value: 6, to: startweek) else { return 0 } - + switch clearAtString { case NSLocalizedString("_dont_clear_", comment: ""): return 0 @@ -437,40 +435,40 @@ class NCUserStatus: UIViewController { return 0 } } - + func getPredefinedClearStatusText(clearAt: NSDate?, clearAtTime: String?, clearAtType: String?) -> String { - + // Date if clearAt != nil { - + let from = Date() let to = clearAt! as Date - + let day = Calendar.current.dateComponents([.day], from: from, to: to).day ?? 0 let hour = Calendar.current.dateComponents([.hour], from: from, to: to).hour ?? 0 let minute = Calendar.current.dateComponents([.minute], from: from, to: to).minute ?? 0 - + if day > 0 { if day == 1 { return NSLocalizedString("day", comment: "") } return "\(day) " + NSLocalizedString("_days_", comment: "") } - + if hour > 0 { if hour == 1 { return NSLocalizedString("_an_hour_", comment: "") } if hour == 4 { return NSLocalizedString("_4_hour_", comment: "") } return "\(hour) " + NSLocalizedString("_hours_", comment: "") } - + if minute > 0 { if minute >= 25 && minute <= 30 { return NSLocalizedString("_30_minutes_", comment: "") } if minute > 30 { return NSLocalizedString("_an_hour_", comment: "") } return "\(minute) " + NSLocalizedString("_minutes_", comment: "") } } - + // Period if clearAtTime != nil && clearAtType == "period" { - + switch clearAtTime { case "3600": return NSLocalizedString("_an_hour_", comment: "") @@ -480,36 +478,36 @@ class NCUserStatus: UIViewController { return NSLocalizedString("_dont_clear_", comment: "") } } - + // End of if clearAtTime != nil && clearAtType == "end-of" { - + return NSLocalizedString(clearAtTime!, comment: "") } - + return NSLocalizedString("_dont_clear_", comment: "") } } @available(iOS 13.0, *) extension NCUserStatus: UITextFieldDelegate { - + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - + if textField is emojiTextField { - + if string.count == 0 { textField.text = "😀" return false } - + textField.text = string textField.endEditing(true) } - + return true } - + func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() return false @@ -560,32 +558,32 @@ class emojiTextField: UITextField { @available(iOS 13.0, *) extension NCUserStatus: UITableViewDelegate { - + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 45 } - + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - + guard let cell = tableView.cellForRow(at: indexPath) else { return } let status = statusPredefinedStatuses[indexPath.row] - + if let messageId = status.id { - - NCCommunication.shared.setCustomMessagePredefined(messageId: messageId, clearAt: 0) { account, errorCode, errorDescription in - + + NCCommunication.shared.setCustomMessagePredefined(messageId: messageId, clearAt: 0) { _, errorCode, errorDescription in + cell.isSelected = false - + if errorCode == 0 { - + let clearAtTimestampString = self.getPredefinedClearStatusText(clearAt: status.clearAt, clearAtTime: status.clearAtTime, clearAtType: status.clearAtType) - + self.statusMessageEmojiTextField.text = status.icon self.statusMessageTextField.text = status.message self.clearStatusMessageAfterText.text = " " + clearAtTimestampString self.clearAtTimestamp = self.getClearAt(clearAtTimestampString) } - + self.dismissIfError(errorCode, errorDescription: errorDescription) } } @@ -594,18 +592,18 @@ extension NCUserStatus: UITableViewDelegate { @available(iOS 13.0, *) extension NCUserStatus: UITableViewDataSource { - + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return statusPredefinedStatuses.count } - + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.backgroundColor = tableView.backgroundColor - + let status = statusPredefinedStatuses[indexPath.row] - + let icon = cell.viewWithTag(10) as! UILabel let message = cell.viewWithTag(20) as! UILabel @@ -613,7 +611,7 @@ extension NCUserStatus: UITableViewDataSource { var timeString = getPredefinedClearStatusText(clearAt: status.clearAt, clearAtTime: status.clearAtTime, clearAtType: status.clearAtType) if let messageText = status.message { - + message.text = messageText timeString = " - " + timeString @@ -621,7 +619,7 @@ extension NCUserStatus: UITableViewDataSource { attributedString.setColor(color: .lightGray, font: UIFont.systemFont(ofSize: 15), forText: timeString) message.attributedText = attributedString } - + return cell } } diff --git a/iOSClient/Utility/CCUtility.h b/iOSClient/Utility/CCUtility.h index 19cac2e01..db9593127 100644 --- a/iOSClient/Utility/CCUtility.h +++ b/iOSClient/Utility/CCUtility.h @@ -51,6 +51,8 @@ + (BOOL)getEnableTouchFaceID; + (void)setEnableTouchFaceID:(BOOL)set; ++ (BOOL)isPasscodeAtStartEnabled; + + (NSString *)getGroupBySettings; + (void)setGroupBySettings:(NSString *)groupby; @@ -181,6 +183,9 @@ + (PDFDisplayDirection)getPDFDisplayDirection; + (void)setPDFDisplayDirection:(PDFDisplayDirection)direction; ++ (BOOL)getPrivacyScreenEnabled; ++ (void)setPrivacyScreenEnabled:(BOOL)set; + // ===== Varius ===== + (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL; diff --git a/iOSClient/Utility/CCUtility.m b/iOSClient/Utility/CCUtility.m index 0d262455f..bc77b3c6b 100644 --- a/iOSClient/Utility/CCUtility.m +++ b/iOSClient/Utility/CCUtility.m @@ -103,6 +103,12 @@ [UICKeyChainStore setString:sSet forKey:@"enableTouchFaceID" service:NCGlobal.shared.serviceShareKeyChain]; } ++ (BOOL)isPasscodeAtStartEnabled +{ + if ([self getPasscode].length > 0 && ![self getNotPasscodeAtStart]) return true; + else return false; +} + + (NSString *)getGroupBySettings { NSString *groupby = [UICKeyChainStore stringForKey:@"groupby" service:NCGlobal.shared.serviceShareKeyChain]; @@ -726,6 +732,25 @@ [UICKeyChainStore setString:directionString forKey:@"PDFDisplayDirection" service:NCGlobal.shared.serviceShareKeyChain]; } ++ (BOOL)getPrivacyScreenEnabled +{ + NSString *valueString = [UICKeyChainStore stringForKey:@"privacyScreen" service:NCGlobal.shared.serviceShareKeyChain]; + + // Default TRUE + if (valueString == nil) { + [self setPrivacyScreenEnabled:YES]; + return true; + } + + return [valueString boolValue]; +} + ++ (void)setPrivacyScreenEnabled:(BOOL)set +{ + NSString *sSet = (set) ? @"true" : @"false"; + [UICKeyChainStore setString:sSet forKey:@"privacyScreen" service:NCGlobal.shared.serviceShareKeyChain]; +} + #pragma -------------------------------------------------------------------------------------------- #pragma mark ===== Various ===== #pragma -------------------------------------------------------------------------------------------- diff --git a/iOSClient/Utility/NCAskAuthorization.swift b/iOSClient/Utility/NCAskAuthorization.swift index ef49d09b4..28ce6e902 100644 --- a/iOSClient/Utility/NCAskAuthorization.swift +++ b/iOSClient/Utility/NCAskAuthorization.swift @@ -28,20 +28,20 @@ class NCAskAuthorization: NSObject { let instance = NCAskAuthorization() return instance }() - - func askAuthorizationAudioRecord(viewController: UIViewController?, completion: @escaping (_ hasPermission: Bool)->()) { - + + func askAuthorizationAudioRecord(viewController: UIViewController?, completion: @escaping (_ hasPermission: Bool) -> Void) { + switch AVAudioSession.sharedInstance().recordPermission { case AVAudioSession.RecordPermission.granted: completion(true) break case AVAudioSession.RecordPermission.denied: let alert = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_err_permission_microphone_", comment: ""), preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("_open_settings_", comment: ""), style: .default, handler: { action in + alert.addAction(UIAlertAction(title: NSLocalizedString("_open_settings_", comment: ""), style: .default, handler: { _ in UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!) completion(false) })) - alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: { action in + alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: { _ in completion(false) })) DispatchQueue.main.async { @@ -49,7 +49,7 @@ class NCAskAuthorization: NSObject { } break case AVAudioSession.RecordPermission.undetermined: - AVAudioSession.sharedInstance().requestRecordPermission { (allowed) in + AVAudioSession.sharedInstance().requestRecordPermission { allowed in DispatchQueue.main.async { if allowed { completion(true) @@ -64,20 +64,20 @@ class NCAskAuthorization: NSObject { break } } - - func askAuthorizationPhotoLibrary(viewController: UIViewController?, completion: @escaping (_ hasPermission: Bool)->()) { - + + func askAuthorizationPhotoLibrary(viewController: UIViewController?, completion: @escaping (_ hasPermission: Bool) -> Void) { + switch PHPhotoLibrary.authorizationStatus() { case PHAuthorizationStatus.authorized: completion(true) break case PHAuthorizationStatus.denied, PHAuthorizationStatus.limited, PHAuthorizationStatus.restricted: let alert = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_err_permission_photolibrary_", comment: ""), preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("_open_settings_", comment: ""), style: .default, handler: { action in + alert.addAction(UIAlertAction(title: NSLocalizedString("_open_settings_", comment: ""), style: .default, handler: { _ in UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!) completion(false) })) - alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: { action in + alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: { _ in completion(false) })) DispatchQueue.main.async { @@ -85,7 +85,7 @@ class NCAskAuthorization: NSObject { } break case PHAuthorizationStatus.notDetermined: - PHPhotoLibrary.requestAuthorization { (allowed) in + PHPhotoLibrary.requestAuthorization { allowed in DispatchQueue.main.async { if allowed == PHAuthorizationStatus.authorized { completion(true) @@ -100,9 +100,9 @@ class NCAskAuthorization: NSObject { break } } - - @objc func askAuthorizationLocationManager(completion: @escaping (_ hasFullPermissions: Bool)->()) { - + + @objc func askAuthorizationLocationManager(completion: @escaping (_ hasFullPermissions: Bool) -> Void) { + switch CLLocationManager.authorizationStatus() { case CLAuthorizationStatus.authorizedAlways: completion(true) diff --git a/iOSClient/Utility/NCContentPresenter.swift b/iOSClient/Utility/NCContentPresenter.swift index d35213e1d..2607d39f6 100644 --- a/iOSClient/Utility/NCContentPresenter.swift +++ b/iOSClient/Utility/NCContentPresenter.swift @@ -30,7 +30,7 @@ class NCContentPresenter: NSObject { let instance = NCContentPresenter() return instance }() - + typealias MainFont = Font.HelveticaNeue enum Font { enum HelveticaNeue: String { @@ -47,20 +47,20 @@ class NCContentPresenter: NSObject { case condensedBlack = "CondensedBlack" case condensedBold = "CondensedBold" case boldItalic = "BoldItalic" - + func with(size: CGFloat) -> UIFont { return UIFont(name: "HelveticaNeue-\(rawValue)", size: size)! } } } - + @objc enum messageType: Int { case error case success case info } - - //MARK: - Message + + // MARK: - Message @objc func showGenericError(description: String) { messageNotification( @@ -95,16 +95,16 @@ class NCContentPresenter: NSObject { } } } - - //MARK: - Flat message - + + // MARK: - Flat message + private func flatTop(title: String, description: String, delay: TimeInterval, imageName: String?, type: messageType, priority: EKAttributes.Precedence.Priority = .normal, dropEnqueuedEntries: Bool = false) { - + if SwiftEntryKit.isCurrentlyDisplaying(entryNamed: title + description) { return } - + var attributes = EKAttributes.topFloat var image: UIImage? - + attributes.windowLevel = .normal attributes.displayDuration = delay attributes.name = title + description @@ -114,9 +114,9 @@ class NCContentPresenter: NSObject { attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt) attributes.precedence = .override(priority: priority, dropEnqueuedEntries: dropEnqueuedEntries) - let title = EKProperty.LabelContent(text: title, style: .init(font: MainFont.bold.with(size: 16), color: .white)) - let description = EKProperty.LabelContent(text: description, style: .init(font: MainFont.medium.with(size: 13), color: .white)) - + let title = EKProperty.LabelContent(text: title, style: .init(font: MainFont.bold.with(size: 16), color: .white)) + let description = EKProperty.LabelContent(text: description, style: .init(font: MainFont.medium.with(size: 13), color: .white)) + if imageName == nil { image = getImageFromType(type) } else { @@ -126,19 +126,19 @@ class NCContentPresenter: NSObject { let simpleMessage = EKSimpleMessage(image: imageMessage, title: title, description: description) let notificationMessage = EKNotificationMessage(simpleMessage: simpleMessage) - + let contentView = EKNotificationMessageView(with: notificationMessage) DispatchQueue.main.async { SwiftEntryKit.display(entry: contentView, using: attributes) } } - - //MARK: - Note Message - + + // MARK: - Note Message + func noteTop(text: String, image: UIImage?, color: UIColor? = nil, type: messageType? = nil, delay: TimeInterval, priority: EKAttributes.Precedence.Priority = .normal, dropEnqueuedEntries: Bool = false) { - + if SwiftEntryKit.isCurrentlyDisplaying(entryNamed: text) { return } var attributes = EKAttributes.topNote - + attributes.windowLevel = .normal attributes.displayDuration = delay attributes.name = text @@ -152,7 +152,7 @@ class NCContentPresenter: NSObject { let style = EKProperty.LabelStyle(font: MainFont.light.with(size: 14), color: .white, alignment: .center) let labelContent = EKProperty.LabelContent(text: text, style: style) - + if let image = image { let imageContent = EKProperty.ImageContent(image: image, size: CGSize(width: 17, height: 17)) let contentView = EKImageNoteMessageView(with: labelContent, imageContent: imageContent) @@ -162,8 +162,8 @@ class NCContentPresenter: NSObject { DispatchQueue.main.async { SwiftEntryKit.display(entry: contentView, using: attributes) } } } - - //MARK: - Private + + // MARK: - Private private func getBackgroundColorFromType(_ type: messageType) -> UIColor { switch type { @@ -177,7 +177,7 @@ class NCContentPresenter: NSObject { return .white } } - + private func getImageFromType(_ type: messageType) -> UIImage? { switch type { case .info: @@ -190,5 +190,5 @@ class NCContentPresenter: NSObject { return nil } } - + } diff --git a/iOSClient/Utility/NCLivePhoto.swift b/iOSClient/Utility/NCLivePhoto.swift index 820749963..949f2a471 100644 --- a/iOSClient/Utility/NCLivePhoto.swift +++ b/iOSClient/Utility/NCLivePhoto.swift @@ -12,7 +12,7 @@ import MobileCoreServices import Photos class NCLivePhoto { - + // MARK: PUBLIC typealias LivePhotoResources = (pairedImage: URL, pairedVideo: URL) /// Returns the paired image and video for the given PHLivePhoto @@ -34,14 +34,14 @@ class NCLivePhoto { let options = PHAssetResourceCreationOptions() creationRequest.addResource(with: PHAssetResourceType.pairedVideo, fileURL: resources.pairedVideo, options: options) creationRequest.addResource(with: PHAssetResourceType.photo, fileURL: resources.pairedImage, options: options) - }, completionHandler: { (success, error) in + }, completionHandler: { success, error in if error != nil { print(error as Any) } completion(success) }) } - + // MARK: PRIVATE private static let shared = NCLivePhoto() private static let queue = DispatchQueue(label: "com.limit-point.LivePhotoQueue", attributes: .concurrent) @@ -55,13 +55,13 @@ class NCLivePhoto { } return nil }() - + deinit { clearCache() } - + private func generateKeyPhoto(from videoURL: URL) -> URL? { - var percent:Float = 0.5 + var percent: Float = 0.5 let videoAsset = AVURLAsset(url: videoURL) if let stillImageTime = videoAsset.stillImageTime() { percent = Float(stillImageTime.value) / Float(videoAsset.duration.value) @@ -79,7 +79,7 @@ class NCLivePhoto { try? FileManager.default.removeItem(at: cacheDirectory) } } - + private func generate(from imageURL: URL?, videoURL: URL, progress: @escaping (CGFloat) -> Void, completion: @escaping (PHLivePhoto?, LivePhotoResources?) -> Void) { guard let cacheDirectory = cacheDirectory else { DispatchQueue.main.async { @@ -95,9 +95,9 @@ class NCLivePhoto { } return } - addAssetID(assetIdentifier, toVideo: videoURL, saveTo: cacheDirectory.appendingPathComponent(assetIdentifier).appendingPathExtension("mov"), progress: progress) { (_videoURL) in + addAssetID(assetIdentifier, toVideo: videoURL, saveTo: cacheDirectory.appendingPathComponent(assetIdentifier).appendingPathExtension("mov"), progress: progress) { _videoURL in if let pairedVideoURL = _videoURL { - _ = PHLivePhoto.request(withResourceFileURLs: [pairedVideoURL, pairedImageURL], placeholderImage: nil, targetSize: CGSize.zero, contentMode: PHImageContentMode.aspectFit, resultHandler: { (livePhoto: PHLivePhoto?, info: [AnyHashable : Any]) -> Void in + _ = PHLivePhoto.request(withResourceFileURLs: [pairedVideoURL, pairedImageURL], placeholderImage: nil, targetSize: CGSize.zero, contentMode: PHImageContentMode.aspectFit, resultHandler: { (livePhoto: PHLivePhoto?, info: [AnyHashable: Any]) -> Void in if let isDegraded = info[PHLivePhotoInfoIsDegradedKey] as? Bool, isDegraded { return } @@ -112,7 +112,7 @@ class NCLivePhoto { } } } - + private func extractResources(from livePhoto: PHLivePhoto, to directoryURL: URL, completion: @escaping (LivePhotoResources?) -> Void) { let assetResources = PHAssetResource.assetResources(for: livePhoto) let group = DispatchGroup() @@ -123,9 +123,9 @@ class NCLivePhoto { let options = PHAssetResourceRequestOptions() options.isNetworkAccessAllowed = true group.enter() - PHAssetResourceManager.default().requestData(for: resource, options: options, dataReceivedHandler: { (data) in + PHAssetResourceManager.default().requestData(for: resource, options: options, dataReceivedHandler: { data in buffer.append(data) - }) { (error) in + }) { error in if error == nil { if resource.type == .pairedVideo { videoURL = self.saveAssetResource(resource, to: directoryURL, resourceData: buffer as Data) @@ -145,51 +145,51 @@ class NCLivePhoto { completion((pairedPhotoURL, pairedVideoURL)) } } - + private func extractResources(from livePhoto: PHLivePhoto, completion: @escaping (LivePhotoResources?) -> Void) { if let cacheDirectory = cacheDirectory { extractResources(from: livePhoto, to: cacheDirectory, completion: completion) } } - + private func saveAssetResource(_ resource: PHAssetResource, to directory: URL, resourceData: Data) -> URL? { - let fileExtension = UTTypeCopyPreferredTagWithClass(resource.uniformTypeIdentifier as CFString,kUTTagClassFilenameExtension)?.takeRetainedValue() - + let fileExtension = UTTypeCopyPreferredTagWithClass(resource.uniformTypeIdentifier as CFString, kUTTagClassFilenameExtension)?.takeRetainedValue() + guard let ext = fileExtension else { return nil } - + var fileUrl = directory.appendingPathComponent(NSUUID().uuidString) fileUrl = fileUrl.appendingPathExtension(ext as String) - + do { try resourceData.write(to: fileUrl, options: [Data.WritingOptions.atomic]) } catch { print("Could not save resource \(resource) to filepath \(String(describing: fileUrl))") return nil } - + return fileUrl } - + func addAssetID(_ assetIdentifier: String, toImage imageURL: URL, saveTo destinationURL: URL) -> URL? { guard let imageDestination = CGImageDestinationCreateWithURL(destinationURL as CFURL, kUTTypeJPEG, 1, nil), let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, nil), - var imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [AnyHashable : Any] else { return nil } + var imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [AnyHashable: Any] else { return nil } let assetIdentifierKey = "17" - let assetIdentifierInfo = [assetIdentifierKey : assetIdentifier] + let assetIdentifierInfo = [assetIdentifierKey: assetIdentifier] imageProperties[kCGImagePropertyMakerAppleDictionary] = assetIdentifierInfo CGImageDestinationAddImageFromSource(imageDestination, imageSource, 0, imageProperties as CFDictionary) CGImageDestinationFinalize(imageDestination) return destinationURL } - + var audioReader: AVAssetReader? var videoReader: AVAssetReader? var assetWriter: AVAssetWriter? - + func addAssetID(_ assetIdentifier: String, toVideo videoURL: URL, saveTo destinationURL: URL, progress: @escaping (CGFloat) -> Void, completion: @escaping (URL?) -> Void) { - + var audioWriterInput: AVAssetWriterInput? var audioReaderOutput: AVAssetReaderOutput? let videoAsset = AVURLAsset(url: videoURL) @@ -206,7 +206,7 @@ class NCLivePhoto { let videoReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings) videoReader?.add(videoReaderOutput) // Create Video Writer Input - let videoWriterInput = AVAssetWriterInput(mediaType: .video, outputSettings: [AVVideoCodecKey : AVVideoCodecType.h264, AVVideoWidthKey : videoTrack.naturalSize.width, AVVideoHeightKey : videoTrack.naturalSize.height]) + let videoWriterInput = AVAssetWriterInput(mediaType: .video, outputSettings: [AVVideoCodecKey: AVVideoCodecType.h264, AVVideoWidthKey: videoTrack.naturalSize.width, AVVideoHeightKey: videoTrack.naturalSize.height]) videoWriterInput.transform = videoTrack.preferredTransform videoWriterInput.expectsMediaDataInRealTime = true assetWriter?.add(videoWriterInput) @@ -236,7 +236,7 @@ class NCLivePhoto { assetWriter?.startSession(atSourceTime: CMTime.zero) // Add still image metadata let _stillImagePercent: Float = 0.5 - stillImageTimeMetadataAdapter.append(AVTimedMetadataGroup(items: [metadataItemForStillImageTime()],timeRange: videoAsset.makeStillImageTimeRange(percent: _stillImagePercent, inFrameCount: frameCount))) + stillImageTimeMetadataAdapter.append(AVTimedMetadataGroup(items: [metadataItemForStillImageTime()], timeRange: videoAsset.makeStillImageTimeRange(percent: _stillImagePercent, inFrameCount: frameCount))) // For end of writing / progress var writingVideoFinished = false var writingAudioFinished = false @@ -255,9 +255,9 @@ class NCLivePhoto { if videoReader?.startReading() ?? false { videoWriterInput.requestMediaDataWhenReady(on: DispatchQueue(label: "videoWriterInputQueue")) { while videoWriterInput.isReadyForMoreMediaData { - if let sampleBuffer = videoReaderOutput.copyNextSampleBuffer() { + if let sampleBuffer = videoReaderOutput.copyNextSampleBuffer() { currentFrameCount += 1 - let percent:CGFloat = CGFloat(currentFrameCount)/CGFloat(frameCount) + let percent: CGFloat = CGFloat(currentFrameCount)/CGFloat(frameCount) progress(percent) if !videoWriterInput.append(sampleBuffer) { print("Cannot write: \(String(describing: self.assetWriter?.error?.localizedDescription))") @@ -296,7 +296,7 @@ class NCLivePhoto { completion(nil) } } - + private func metadataForAssetID(_ assetIdentifier: String) -> AVMetadataItem { let item = AVMutableMetadataItem() let keyContentIdentifier = "com.apple.quicktime.content.identifier" @@ -307,22 +307,22 @@ class NCLivePhoto { item.dataType = "com.apple.metadata.datatype.UTF-8" return item } - + private func createMetadataAdaptorForStillImageTime() -> AVAssetWriterInputMetadataAdaptor { let keyStillImageTime = "com.apple.quicktime.still-image-time" let keySpaceQuickTimeMetadata = "mdta" - let spec : NSDictionary = [ + let spec: NSDictionary = [ kCMMetadataFormatDescriptionMetadataSpecificationKey_Identifier as NSString: "\(keySpaceQuickTimeMetadata)/\(keyStillImageTime)", kCMMetadataFormatDescriptionMetadataSpecificationKey_DataType as NSString: "com.apple.metadata.datatype.int8" ] - var desc : CMFormatDescription? = nil + var desc: CMFormatDescription? CMMetadataFormatDescriptionCreateWithMetadataSpecifications(allocator: kCFAllocatorDefault, metadataType: kCMMetadataFormatType_Boxed, metadataSpecifications: [spec] as CFArray, formatDescriptionOut: &desc) let input = AVAssetWriterInput(mediaType: .metadata, outputSettings: nil, sourceFormatHint: desc) return AVAssetWriterInputMetadataAdaptor(assetWriterInput: input) } - + private func metadataItemForStillImageTime() -> AVMetadataItem { let item = AVMutableMetadataItem() let keyStillImageTime = "com.apple.quicktime.still-image-time" @@ -333,30 +333,29 @@ class NCLivePhoto { item.dataType = "com.apple.metadata.datatype.int8" return item } - + } fileprivate extension AVAsset { - func countFrames(exact:Bool) -> Int { - + func countFrames(exact: Bool) -> Int { + var frameCount = 0 - - if let videoReader = try? AVAssetReader(asset: self) { - + + if let videoReader = try? AVAssetReader(asset: self) { + if let videoTrack = self.tracks(withMediaType: .video).first { - + frameCount = Int(CMTimeGetSeconds(self.duration) * Float64(videoTrack.nominalFrameRate)) - - + if exact { - + frameCount = 0 - + let videoReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: nil) videoReader.add(videoReaderOutput) - + videoReader.startReading() - + // count frames while true { let sampleBuffer = videoReaderOutput.copyNextSampleBuffer() @@ -365,36 +364,35 @@ fileprivate extension AVAsset { } frameCount += 1 } - + videoReader.cancelReading() } - - + } } - + return frameCount } - - func stillImageTime() -> CMTime? { - - var stillTime:CMTime? = nil - - if let videoReader = try? AVAssetReader(asset: self) { - + + func stillImageTime() -> CMTime? { + + var stillTime: CMTime? + + if let videoReader = try? AVAssetReader(asset: self) { + if let metadataTrack = self.tracks(withMediaType: .metadata).first { - + let videoReaderOutput = AVAssetReaderTrackOutput(track: metadataTrack, outputSettings: nil) - + videoReader.add(videoReaderOutput) - + videoReader.startReading() - + let keyStillImageTime = "com.apple.quicktime.still-image-time" let keySpaceQuickTimeMetadata = "mdta" - + var found = false - + while found == false { if let sampleBuffer = videoReaderOutput.copyNextSampleBuffer() { if CMSampleBufferGetNumSamples(sampleBuffer) != 0 { @@ -402,68 +400,64 @@ fileprivate extension AVAsset { for item in group?.items ?? [] { if item.key as? String == keyStillImageTime && item.keySpace!.rawValue == keySpaceQuickTimeMetadata { stillTime = group?.timeRange.start - //print("stillImageTime = \(CMTimeGetSeconds(stillTime!))") + // print("stillImageTime = \(CMTimeGetSeconds(stillTime!))") found = true break } } } - } - else { - break; + } else { + break } } - + videoReader.cancelReading() - + } } - + return stillTime } - - func makeStillImageTimeRange(percent:Float, inFrameCount:Int = 0) -> CMTimeRange { - + + func makeStillImageTimeRange(percent: Float, inFrameCount: Int = 0) -> CMTimeRange { + var time = self.duration - + var frameCount = inFrameCount - + if frameCount == 0 { frameCount = self.countFrames(exact: true) } - + let frameDuration = Int64(Float(time.value) / Float(frameCount)) - + time.value = Int64(Float(time.value) * percent) - - //print("stillImageTime = \(CMTimeGetSeconds(time))") - + + // print("stillImageTime = \(CMTimeGetSeconds(time))") + return CMTimeRangeMake(start: time, duration: CMTimeMake(value: frameDuration, timescale: time.timescale)) } - - func getAssetFrame(percent:Float) -> UIImage? - { - + + func getAssetFrame(percent: Float) -> UIImage? { + let imageGenerator = AVAssetImageGenerator(asset: self) imageGenerator.appliesPreferredTrackTransform = true - + imageGenerator.requestedTimeToleranceAfter = CMTimeMake(value: 1, timescale: 100) imageGenerator.requestedTimeToleranceBefore = CMTimeMake(value: 1, timescale: 100) - + var time = self.duration - + time.value = Int64(Float(time.value) * percent) - + do { var actualTime = CMTime.zero - let imageRef = try imageGenerator.copyCGImage(at: time, actualTime:&actualTime) - + let imageRef = try imageGenerator.copyCGImage(at: time, actualTime: &actualTime) + let img = UIImage(cgImage: imageRef) - + return img - } - catch let error as NSError - { + } catch let error as NSError { print("Image generation failed with error \(error)") return nil } diff --git a/iOSClient/Utility/NCPopupViewController.swift b/iOSClient/Utility/NCPopupViewController.swift index 2fde22d07..64f1015e3 100644 --- a/iOSClient/Utility/NCPopupViewController.swift +++ b/iOSClient/Utility/NCPopupViewController.swift @@ -23,7 +23,7 @@ import UIKit public protocol NCPopupViewControllerDelegate: AnyObject { - + func popupViewControllerDidDismissByTapGesture(_ sender: NCPopupViewController) } @@ -33,54 +33,54 @@ public extension NCPopupViewControllerDelegate { } public class NCPopupViewController: UIViewController { - + private var centerYConstraint: NSLayoutConstraint? - + // Popup width, it's nil if width is determined by view's intrinsic size private(set) public var popupWidth: CGFloat? - + // Popup height, it's nil if width is determined by view's intrinsic size private(set) public var popupHeight: CGFloat? - + // Background alpha, default is 0.3 public var backgroundAlpha: CGFloat = 0.3 - + // Background color, default is black public var backgroundColor = UIColor.black - + // Allow tap outside popup to dismiss, default is true public var canTapOutsideToDismiss = true - + // Corner radius, default is 10 (0 no rounded corner) public var cornerRadius: CGFloat = 10 - + // Shadow enabled, default is true public var shadowEnabled = true - + // Border enabled, default is false public var borderEnabled = false - + // Move the popup position H when show/hide keyboard public var keyboardPosizionEnabled = true // The pop up view controller. It's not mandatory. private(set) public var contentController: UIViewController? - + // The pop up view private(set) public var contentView: UIView? - + // The delegate to receive pop up event public weak var delegate: NCPopupViewControllerDelegate? - + private var containerView = UIView() - + // MARK: - View Life Cycle // NOTE: Don't use this init method required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } - + /** Init with content view controller. Your pop up content is a view controller (easiest way to design it is using storyboard) - Parameters: @@ -90,16 +90,16 @@ public class NCPopupViewController: UIViewController { */ public init(contentController: UIViewController, popupWidth: CGFloat? = nil, popupHeight: CGFloat? = nil) { super.init(nibName: nil, bundle: nil) - + self.contentController = contentController self.contentView = contentController.view self.popupWidth = popupWidth self.popupHeight = popupHeight - + modalPresentationStyle = .overFullScreen modalTransitionStyle = .crossDissolve } - + /** Init with content view - Parameters: @@ -107,82 +107,82 @@ public class NCPopupViewController: UIViewController { - popupWidth: Width of popup content. If it isn't set, width will be determine by popup content view intrinsic size. - popupHeight: Height of popup content. If it isn't set, height will be determine by popup content view intrinsic size. */ - + public init(contentView: UIView, popupWidth: CGFloat? = nil, popupHeight: CGFloat? = nil) { super.init(nibName: nil, bundle: nil) - + self.contentView = contentView self.popupWidth = popupWidth self.popupHeight = popupHeight - + modalPresentationStyle = .overFullScreen modalTransitionStyle = .crossDissolve } - + override public func viewDidLoad() { super.viewDidLoad() setupUI() setupViews() addDismissGesture() - + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) } - + // MARK: - Setup private func addDismissGesture() { - + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissTapGesture(gesture:))) tapGesture.delegate = self view.addGestureRecognizer(tapGesture) } - + private func setupUI() { - + containerView.translatesAutoresizingMaskIntoConstraints = false contentView?.translatesAutoresizingMaskIntoConstraints = false - + view.backgroundColor = backgroundColor.withAlphaComponent(backgroundAlpha) - + if cornerRadius > 0 { contentView?.layer.cornerRadius = cornerRadius contentView?.layer.masksToBounds = true } - + if shadowEnabled { containerView.layer.shadowOpacity = 0.5 containerView.layer.shadowColor = UIColor.black.cgColor containerView.layer.shadowOffset = CGSize(width: 5, height: 5) containerView.layer.shadowRadius = 5 } - + if borderEnabled { containerView.layer.cornerRadius = cornerRadius containerView.layer.borderWidth = 0.3 containerView.layer.borderColor = UIColor.gray.cgColor } } - + private func setupViews() { - + if let contentController = contentController { addChild(contentController) } - + addViews() addSizeConstraints() addCenterPositionConstraints() } - + private func addViews() { - + view.addSubview(containerView) - + if let contentView = contentView { containerView.addSubview(contentView) - + let topConstraint = NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal, toItem: containerView, attribute: .top, multiplier: 1, constant: 0) let leftConstraint = NSLayoutConstraint(item: contentView, attribute: .left, relatedBy: .equal, toItem: containerView, attribute: .left, multiplier: 1, constant: 0) let bottomConstraint = NSLayoutConstraint(item: contentView, attribute: .bottom, relatedBy: .equal, toItem: containerView, attribute: .bottom, multiplier: 1, constant: 0) @@ -190,37 +190,36 @@ public class NCPopupViewController: UIViewController { NSLayoutConstraint.activate([topConstraint, leftConstraint, bottomConstraint, rightConstraint]) } } - + // MARK: - Add constraints - + private func addSizeConstraints() { - + if let popupWidth = popupWidth { let widthConstraint = NSLayoutConstraint(item: containerView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: popupWidth) NSLayoutConstraint.activate([widthConstraint]) } - + if let popupHeight = popupHeight { let heightConstraint = NSLayoutConstraint(item: containerView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: popupHeight) NSLayoutConstraint.activate([heightConstraint]) } } - + private func addCenterPositionConstraints() { - + let centerXConstraint = NSLayoutConstraint(item: containerView, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0) centerYConstraint = NSLayoutConstraint(item: containerView, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: 0) NSLayoutConstraint.activate([centerXConstraint, centerYConstraint!]) } - + // MARK: - - + func addPath() { - + let balloon = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 250)) balloon.backgroundColor = UIColor.clear - let path = UIBezierPath() path.move(to: CGPoint(x: 0, y: 0)) path.addLine(to: CGPoint(x: 200, y: 0)) @@ -235,7 +234,7 @@ public class NCPopupViewController: UIViewController { path.close() let shape = CAShapeLayer() - //shape.backgroundColor = UIColor.blue.cgColor + // shape.backgroundColor = UIColor.blue.cgColor shape.fillColor = UIColor.blue.cgColor shape.path = path.cgPath balloon.layer.addSublayer(shape) @@ -243,45 +242,45 @@ public class NCPopupViewController: UIViewController { // [self.view addSubview:balloonView]; } - + // MARK: - Actions - + @objc func dismissTapGesture(gesture: UIGestureRecognizer) { dismiss(animated: true) { self.delegate?.popupViewControllerDidDismissByTapGesture(self) } } - + // MARK: - Keyboard notification - - @objc internal func keyboardWillShow(_ notification : Notification?) { - + + @objc internal func keyboardWillShow(_ notification: Notification?) { + var keyboardSize = CGSize.zero - + if let info = notification?.userInfo { let frameEndUserInfoKey = UIResponder.keyboardFrameEndUserInfoKey - + // Getting UIKeyboardSize. if let keyboardFrame = info[frameEndUserInfoKey] as? CGRect { - + let screenSize = UIScreen.main.bounds - - //Calculating actual keyboard displayed size, keyboard frame may be different when hardware keyboard is attached (Bug ID: #469) (Bug ID: #381) + + // Calculating actual keyboard displayed size, keyboard frame may be different when hardware keyboard is attached (Bug ID: #469) (Bug ID: #381) let intersectRect = keyboardFrame.intersection(screenSize) - + if intersectRect.isNull { keyboardSize = CGSize(width: screenSize.size.width, height: 0) } else { keyboardSize = intersectRect.size } - + if keyboardPosizionEnabled { - + let popupDiff = screenSize.height - ((screenSize.height - (popupHeight ?? 0)) / 2) let keyboardDiff = screenSize.height - keyboardSize.height let diff = popupDiff - keyboardDiff - + if centerYConstraint != nil && diff > 0 { centerYConstraint?.constant = -(diff + 15) } @@ -289,9 +288,9 @@ public class NCPopupViewController: UIViewController { } } } - + @objc func keyboardWillHide(_ notification: Notification) { - + if keyboardPosizionEnabled { if centerYConstraint != nil { centerYConstraint?.constant = 0 @@ -306,7 +305,7 @@ extension NCPopupViewController: UIGestureRecognizerDelegate { guard let touchView = touch.view, canTapOutsideToDismiss else { return false } - + return !touchView.isDescendant(of: containerView) } } diff --git a/iOSClient/Utility/NCStoreReview.swift b/iOSClient/Utility/NCStoreReview.swift index a247dbbe0..db48729cf 100644 --- a/iOSClient/Utility/NCStoreReview.swift +++ b/iOSClient/Utility/NCStoreReview.swift @@ -25,37 +25,37 @@ import UIKit import StoreKit class NCStoreReview: NSObject { - + let runIncrementerSetting = "numberOfRuns" let minimumRunCount = 5 - + func getRunCounts () -> Int { - + let uDefaults = UserDefaults() let savedRuns = uDefaults.value(forKey: runIncrementerSetting) - + var runs = 0 - if (savedRuns != nil) { + if savedRuns != nil { runs = savedRuns as! Int } - + print("Nextcloud iOS run Counts are \(runs)") return runs } - + @objc func incrementAppRuns() { - + let uDefaults = UserDefaults() let runs = getRunCounts() + 1 uDefaults.setValuesForKeys([runIncrementerSetting: runs]) uDefaults.synchronize() } - + @objc func showStoreReview() { - + let runs = getRunCounts() - - if (runs > minimumRunCount) { + + if runs > minimumRunCount { SKStoreReviewController.requestReview() } } diff --git a/iOSClient/Utility/NCUtility.swift b/iOSClient/Utility/NCUtility.swift index ba7894617..db79e1b96 100644 --- a/iOSClient/Utility/NCUtility.swift +++ b/iOSClient/Utility/NCUtility.swift @@ -29,7 +29,6 @@ import PDFKit import Accelerate import CoreMedia - // MARK: - NCUtility class NCUtility: NSObject { @@ -37,27 +36,27 @@ class NCUtility: NSObject { let instance = NCUtility() return instance }() - + private var activityIndicator: UIActivityIndicatorView? private var viewActivityIndicator: UIView? private var viewBackgroundActivityIndicator: UIView? func setLayoutForView(key: String, serverUrl: String, layoutForView: NCGlobal.layoutForViewType) { - + let string = layoutForView.layout + "|" + layoutForView.sort + "|" + "\(layoutForView.ascending)" + "|" + layoutForView.groupBy + "|" + "\(layoutForView.directoryOnTop)" + "|" + layoutForView.titleButtonHeader + "|" + "\(layoutForView.itemForLine)" + "|" + layoutForView.imageBackgroud + "|" + layoutForView.imageBackgroudContentMode var keyStore = key - + if serverUrl != "" { keyStore = serverUrl } - + UICKeyChainStore.setString(string, forKey: keyStore, service: NCGlobal.shared.serviceShareKeyChain) } - + func setLayoutForView(key: String, serverUrl: String, layout: String?) { - + var layoutForView: NCGlobal.layoutForViewType = NCUtility.shared.getLayoutForView(key: key, serverUrl: serverUrl) - + if let layout = layout { layoutForView.layout = layout setLayoutForView(key: key, serverUrl: serverUrl, layoutForView: layoutForView) @@ -65,24 +64,24 @@ class NCUtility: NSObject { } func setBackgroundImageForView(key: String, serverUrl: String, imageBackgroud: String, imageBackgroudContentMode: String) { - + var layoutForView: NCGlobal.layoutForViewType = NCUtility.shared.getLayoutForView(key: key, serverUrl: serverUrl) - + layoutForView.imageBackgroud = imageBackgroud layoutForView.imageBackgroudContentMode = imageBackgroudContentMode - + setLayoutForView(key: key, serverUrl: serverUrl, layoutForView: layoutForView) } - + func getLayoutForView(key: String, serverUrl: String, sort: String = "fileName", ascending: Bool = true, titleButtonHeader: String = "_sorted_by_name_a_z_") -> (NCGlobal.layoutForViewType) { - + var keyStore = key var layoutForView: NCGlobal.layoutForViewType = NCGlobal.layoutForViewType(layout: NCGlobal.shared.layoutList, sort: sort, ascending: ascending, groupBy: "none", directoryOnTop: true, titleButtonHeader: titleButtonHeader, itemForLine: 3, imageBackgroud: "", imageBackgroudContentMode: "") - + if serverUrl != "" { keyStore = serverUrl } - + guard let string = UICKeyChainStore.string(forKey: keyStore, service: NCGlobal.shared.serviceShareKeyChain) else { setLayoutForView(key: key, serverUrl: serverUrl, layoutForView: layoutForView) return layoutForView @@ -102,102 +101,102 @@ class NCUtility: NSObject { if array.count > 8 { layoutForView.imageBackgroud = array[7] layoutForView.imageBackgroudContentMode = array[8] - //layoutForView.lightColorBackground = array[9] WAS STRING - //layoutForView.darkColorBackground = array[10] WAS STRING + // layoutForView.lightColorBackground = array[9] WAS STRING + // layoutForView.darkColorBackground = array[10] WAS STRING } } - + return layoutForView } - - func convertSVGtoPNGWriteToUserData(svgUrlString: String, fileName: String?, width: CGFloat?, rewrite: Bool, account: String, closure: @escaping (String?) -> ()) { - + + func convertSVGtoPNGWriteToUserData(svgUrlString: String, fileName: String?, width: CGFloat?, rewrite: Bool, account: String, closure: @escaping (String?) -> Void) { + var fileNamePNG = "" - + guard let svgUrlString = svgUrlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let iconURL = URL(string: svgUrlString) else { return closure(nil) } - + if let fileName = fileName { fileNamePNG = fileName } else { fileNamePNG = iconURL.deletingPathExtension().lastPathComponent + ".png" } - + let imageNamePath = CCUtility.getDirectoryUserData() + "/" + fileNamePNG - + if !FileManager.default.fileExists(atPath: imageNamePath) || rewrite == true { - - NCCommunication.shared.downloadContent(serverUrl: iconURL.absoluteString) { (account, data, errorCode, errorMessage) in - + + NCCommunication.shared.downloadContent(serverUrl: iconURL.absoluteString) { _, data, errorCode, _ in + if errorCode == 0 && data != nil { - - if let image = UIImage.init(data: data!) { - + + if let image = UIImage(data: data!) { + var newImage: UIImage = image - + if width != nil { - + let ratio = image.size.height / image.size.width let newSize = CGSize(width: width!, height: width! * ratio) - + let renderFormat = UIGraphicsImageRendererFormat.default() renderFormat.opaque = false let renderer = UIGraphicsImageRenderer(size: CGSize(width: newSize.width, height: newSize.height), format: renderFormat) newImage = renderer.image { - (context) in + _ in image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)) } } - + guard let pngImageData = newImage.pngData() else { return closure(nil) } - - try? pngImageData.write(to: URL(fileURLWithPath:imageNamePath)) - + + try? pngImageData.write(to: URL(fileURLWithPath: imageNamePath)) + return closure(imageNamePath) - + } else { - + guard let svgImage: SVGKImage = SVGKImage(data: data) else { return closure(nil) } - + if width != nil { let scale = svgImage.size.height / svgImage.size.width svgImage.size = CGSize(width: width!, height: width! * scale) } - + guard let image: UIImage = svgImage.uiImage else { return closure(nil) } guard let pngImageData = image.pngData() else { return closure(nil) } - - try? pngImageData.write(to: URL(fileURLWithPath:imageNamePath)) - + + try? pngImageData.write(to: URL(fileURLWithPath: imageNamePath)) + return closure(imageNamePath) } } else { return closure(nil) } } - + } else { return closure(imageNamePath) } } - + @objc func isSimulatorOrTestFlight() -> Bool { guard let path = Bundle.main.appStoreReceiptURL?.path else { return false } return path.contains("CoreSimulator") || path.contains("sandboxReceipt") } - + @objc func isSimulator() -> Bool { guard let path = Bundle.main.appStoreReceiptURL?.path else { return false @@ -206,55 +205,55 @@ class NCUtility: NSObject { } @objc func isRichDocument(_ metadata: tableMetadata) -> Bool { - + guard let mimeType = CCUtility.getMimeType(metadata.fileNameView) else { return false } - + guard let richdocumentsMimetypes = NCManageDatabase.shared.getCapabilitiesServerArray(account: metadata.account, elements: NCElementsJSON.shared.capabilitiesRichdocumentsMimetypes) else { return false } - + // contentype for richdocumentMimetype: String in richdocumentsMimetypes { if richdocumentMimetype.contains(metadata.contentType) || metadata.contentType == "text/plain" { return true } } - + // mimetype if richdocumentsMimetypes.count > 0 && mimeType.components(separatedBy: ".").count > 2 { - + let mimeTypeArray = mimeType.components(separatedBy: ".") let mimeType = mimeTypeArray[mimeTypeArray.count - 2] + "." + mimeTypeArray[mimeTypeArray.count - 1] - + for richdocumentMimetype: String in richdocumentsMimetypes { if richdocumentMimetype.contains(mimeType) { return true } } } - + return false } - + @objc func isDirectEditing(account: String, contentType: String) -> [String] { - + var editor: [String] = [] - + guard let results = NCManageDatabase.shared.getDirectEditingEditors(account: account) else { return editor } - + for result: tableDirectEditingEditors in results { for mimetype in result.mimetypes { if mimetype == contentType { editor.append(result.editor) } - + // HARDCODE // https://github.com/nextcloud/text/issues/913 - + if mimetype == "text/markdown" && contentType == "text/x-markdown" { editor.append(result.editor) } @@ -268,36 +267,36 @@ class NCUtility: NSObject { } } } - + // HARDCODE - //if editor.count == 0 { + // if editor.count == 0 { // editor.append(NCGlobal.shared.editorText) - //} - + // } + return Array(Set(editor)) } - + @objc func removeAllSettings() { - + URLCache.shared.memoryCapacity = 0 URLCache.shared.diskCapacity = 0 KTVHTTPCache.cacheDeleteAllCaches() - + NCManageDatabase.shared.clearDatabase(account: nil, removeAccount: true) - + CCUtility.removeGroupDirectoryProviderStorage() CCUtility.removeGroupLibraryDirectory() - + CCUtility.removeDocumentsDirectory() CCUtility.removeTemporaryDirectory() - + CCUtility.createDirectoryStandard() - + CCUtility.deleteAllChainStore() } - + @objc func permissionsContainsString(_ metadataPermissions: String, permissions: String) -> Bool { - + for char in permissions { if metadataPermissions.contains(char) == false { return false @@ -305,19 +304,19 @@ class NCUtility: NSObject { } return true } - + @objc func getCustomUserAgentOnlyOffice() -> String { - + let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")! if UIDevice.current.userInterfaceIdiom == .pad { return "Mozilla/5.0 (iPad) Nextcloud-iOS/\(appVersion)" - }else{ + } else { return "Mozilla/5.0 (iPhone) Mobile Nextcloud-iOS/\(appVersion)" } } - + @objc func pdfThumbnail(url: URL, width: CGFloat = 240) -> UIImage? { - + guard let data = try? Data(contentsOf: url), let page = PDFDocument(data: data)?.page(at: 0) else { return nil } @@ -331,68 +330,68 @@ class NCUtility: NSObject { return page.thumbnail(of: screenSize, for: .mediaBox) } - + @objc func isQuickLookDisplayable(metadata: tableMetadata) -> Bool { return true } - + @objc func ocIdToFileId(ocId: String?) -> String? { - + guard let ocId = ocId else { return nil } - + let items = ocId.components(separatedBy: "oc") if items.count < 2 { return nil } guard let intFileId = Int(items[0]) else { return nil } return String(intFileId) } - + func getUserStatus(userIcon: String?, userStatus: String?, userMessage: String?) -> (onlineStatus: UIImage?, statusMessage: String, descriptionMessage: String) { - + var onlineStatus: UIImage? var statusMessage: String = "" var descriptionMessage: String = "" var messageUserDefined: String = "" - + if userStatus?.lowercased() == "online" { - onlineStatus = UIImage.init(named: "userStatusOnline")!.image(color: UIColor(red: 103.0/255.0, green: 176.0/255.0, blue: 134.0/255.0, alpha: 1.0), size: 50) + onlineStatus = UIImage(named: "userStatusOnline")!.image(color: UIColor(red: 103.0/255.0, green: 176.0/255.0, blue: 134.0/255.0, alpha: 1.0), size: 50) messageUserDefined = NSLocalizedString("_online_", comment: "") } if userStatus?.lowercased() == "away" { - onlineStatus = UIImage.init(named: "userStatusAway")!.image(color: UIColor(red: 233.0/255.0, green: 166.0/255.0, blue: 75.0/255.0, alpha: 1.0), size: 50) + onlineStatus = UIImage(named: "userStatusAway")!.image(color: UIColor(red: 233.0/255.0, green: 166.0/255.0, blue: 75.0/255.0, alpha: 1.0), size: 50) messageUserDefined = NSLocalizedString("_away_", comment: "") } if userStatus?.lowercased() == "dnd" { - onlineStatus = UIImage.init(named: "userStatusDnd")?.resizeImage(size: CGSize(width: 100, height: 100), isAspectRation: false) + onlineStatus = UIImage(named: "userStatusDnd")?.resizeImage(size: CGSize(width: 100, height: 100), isAspectRation: false) messageUserDefined = NSLocalizedString("_dnd_", comment: "") descriptionMessage = NSLocalizedString("_dnd_description_", comment: "") } - if userStatus?.lowercased() == "offline" || userStatus?.lowercased() == "invisible" { - onlineStatus = UIImage.init(named: "userStatusOffline")!.image(color: .black, size: 50) + if userStatus?.lowercased() == "offline" || userStatus?.lowercased() == "invisible" { + onlineStatus = UIImage(named: "userStatusOffline")!.image(color: .black, size: 50) messageUserDefined = NSLocalizedString("_invisible_", comment: "") descriptionMessage = NSLocalizedString("_invisible_description_", comment: "") } - + if let userIcon = userIcon { statusMessage = userIcon + " " } if let userMessage = userMessage { - statusMessage = statusMessage + userMessage + statusMessage += userMessage } statusMessage = statusMessage.trimmingCharacters(in: .whitespaces) if statusMessage == "" { statusMessage = messageUserDefined } - + return(onlineStatus, statusMessage, descriptionMessage) } // MARK: - func imageFromVideo(url: URL, at time: TimeInterval) -> UIImage? { - + let asset = AVURLAsset(url: url) let assetIG = AVAssetImageGenerator(asset: asset) - + assetIG.appliesPreferredTrackTransform = true assetIG.apertureMode = AVAssetImageGenerator.ApertureMode.encodedPixels @@ -407,13 +406,13 @@ class NCUtility: NSObject { return UIImage(cgImage: thumbnailImageRef) } - + func imageFromVideo(url: URL, at time: TimeInterval, completion: @escaping (UIImage?) -> Void) { DispatchQueue.global(qos: .background).async { - + let asset = AVURLAsset(url: url) let assetIG = AVAssetImageGenerator(asset: asset) - + assetIG.appliesPreferredTrackTransform = true assetIG.apertureMode = AVAssetImageGenerator.ApertureMode.encodedPixels @@ -431,41 +430,41 @@ class NCUtility: NSObject { } } } - + func createImageFrom(fileName: String, ocId: String, etag: String, classFile: String) { - + var originalImage, scaleImagePreview, scaleImageIcon: UIImage? - + let fileNamePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)! let fileNamePathPreview = CCUtility.getDirectoryProviderStoragePreviewOcId(ocId, etag: etag)! let fileNamePathIcon = CCUtility.getDirectoryProviderStorageIconOcId(ocId, etag: etag)! - + if FileManager().fileExists(atPath: fileNamePathPreview) && FileManager().fileExists(atPath: fileNamePathIcon) { return } if !CCUtility.fileProviderStorageExists(ocId, fileNameView: fileName) { return } if classFile != NCCommunicationCommon.typeClassFile.image.rawValue && classFile != NCCommunicationCommon.typeClassFile.video.rawValue { return } - + if classFile == NCCommunicationCommon.typeClassFile.image.rawValue { - - originalImage = UIImage.init(contentsOfFile: fileNamePath) - + + originalImage = UIImage(contentsOfFile: fileNamePath) + scaleImagePreview = originalImage?.resizeImage(size: CGSize(width: NCGlobal.shared.sizePreview, height: NCGlobal.shared.sizePreview), isAspectRation: false) scaleImageIcon = originalImage?.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon), isAspectRation: false) - + try? scaleImagePreview?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathPreview)) try? scaleImageIcon?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathIcon)) - + } else if classFile == NCCommunicationCommon.typeClassFile.video.rawValue { - + let videoPath = NSTemporaryDirectory()+"tempvideo.mp4" NCUtilityFileSystem.shared.linkItem(atPath: fileNamePath, toPath: videoPath) - + originalImage = imageFromVideo(url: URL(fileURLWithPath: videoPath), at: 0) - + try? originalImage?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathPreview)) try? originalImage?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathIcon)) } } - + @objc func getVersionApp() -> String { if let dictionary = Bundle.main.infoDictionary { if let version = dictionary["CFBundleShortVersionString"], let build = dictionary["CFBundleVersion"] { @@ -474,11 +473,11 @@ class NCUtility: NSObject { } return "" } - + func loadImage(named: String, color: UIColor = NCBrandColor.shared.gray, size: CGFloat = 50, symbolConfiguration: Any? = nil) -> UIImage { - + var image: UIImage? - + if #available(iOS 13.0, *) { if let symbolConfiguration = symbolConfiguration { image = UIImage(systemName: named, withConfiguration: symbolConfiguration as? UIImage.Configuration)?.imageColor(color) @@ -491,14 +490,14 @@ class NCUtility: NSObject { } else { image = UIImage(named: named)?.image(color: color, size: size) } - + if image != nil { return image! } - + return UIImage(named: "file")!.image(color: color, size: size) } - + @objc func loadUserImage(for user: String, displayName: String?, userBaseUrl: NCUserBaseUrl) -> UIImage { let fileName = userBaseUrl.userBaseUrl + "-" + user + ".png" @@ -512,7 +511,7 @@ class NCUtility: NSObject { return avatarImg } else { return getDefaultUserIcon() } } - + func getDefaultUserIcon() -> UIImage { if #available(iOS 13.0, *) { let config = UIImage.SymbolConfiguration(pointSize: 30) @@ -521,21 +520,21 @@ class NCUtility: NSObject { return NCUtility.shared.loadImage(named: "person.crop.circle", size: 30) } } - + @objc func createAvatar(image: UIImage, size: CGFloat) -> UIImage { - + var avatarImage = image let rect = CGRect(x: 0, y: 0, width: size, height: size) - + UIGraphicsBeginImageContextWithOptions(rect.size, false, 3.0) - UIBezierPath.init(roundedRect: rect, cornerRadius: rect.size.height).addClip() + UIBezierPath(roundedRect: rect, cornerRadius: rect.size.height).addClip() avatarImage.draw(in: rect) avatarImage = UIGraphicsGetImageFromCurrentImageContext() ?? image UIGraphicsEndImageContext() - + return avatarImage } - + func createAvatar(displayName: String, size: CGFloat) -> UIImage? { guard let initials = displayName.uppercaseInitials else { return nil @@ -543,10 +542,10 @@ class NCUtility: NSObject { let userColor = NCGlobal.shared.usernameToColor(displayName) let rect = CGRect(x: 0, y: 0, width: size, height: size) var avatarImage: UIImage? - + UIGraphicsBeginImageContextWithOptions(rect.size, false, 3.0) let context = UIGraphicsGetCurrentContext() - UIBezierPath.init(roundedRect: rect, cornerRadius: rect.size.height).addClip() + UIBezierPath(roundedRect: rect, cornerRadius: rect.size.height).addClip() context?.setFillColor(userColor) context?.fill(rect) let textStyle = NSMutableParagraphStyle() @@ -565,24 +564,24 @@ class NCUtility: NSObject { // MARK: - @objc func startActivityIndicator(backgroundView: UIView?, blurEffect: Bool, bottom: CGFloat = 0, style: UIActivityIndicatorView.Style = .whiteLarge) { - + if self.activityIndicator != nil { stopActivityIndicator() } - + DispatchQueue.main.async { - + self.activityIndicator = UIActivityIndicatorView(style: style) guard let activityIndicator = self.activityIndicator else { return } if self.viewBackgroundActivityIndicator != nil { return } - + activityIndicator.color = NCBrandColor.shared.label activityIndicator.hidesWhenStopped = true activityIndicator.translatesAutoresizingMaskIntoConstraints = false let sizeActivityIndicator = activityIndicator.frame.height + 50 - - self.viewActivityIndicator = UIView.init(frame: CGRect(x: 0, y: 0, width: sizeActivityIndicator, height: sizeActivityIndicator)) + + self.viewActivityIndicator = UIView(frame: CGRect(x: 0, y: 0, width: sizeActivityIndicator, height: sizeActivityIndicator)) self.viewActivityIndicator?.translatesAutoresizingMaskIntoConstraints = false self.viewActivityIndicator?.layer.cornerRadius = 10 self.viewActivityIndicator?.layer.masksToBounds = true @@ -603,69 +602,69 @@ class NCUtility: NSObject { #else self.viewBackgroundActivityIndicator = backgroundView #endif - + // VIEW ACTIVITY INDICATOR - + guard let viewActivityIndicator = self.viewActivityIndicator else { return } viewActivityIndicator.addSubview(activityIndicator) - + if blurEffect { let blurEffect = UIBlurEffect(style: .regular) let blurEffectView = UIVisualEffectView(effect: blurEffect) blurEffectView.frame = viewActivityIndicator.frame viewActivityIndicator.insertSubview(blurEffectView, at: 0) } - + NSLayoutConstraint.activate([ viewActivityIndicator.widthAnchor.constraint(equalToConstant: sizeActivityIndicator), viewActivityIndicator.heightAnchor.constraint(equalToConstant: sizeActivityIndicator), activityIndicator.centerXAnchor.constraint(equalTo: viewActivityIndicator.centerXAnchor), activityIndicator.centerYAnchor.constraint(equalTo: viewActivityIndicator.centerYAnchor) ]) - + // BACKGROUD VIEW ACTIVITY INDICATOR - + guard let viewBackgroundActivityIndicator = self.viewBackgroundActivityIndicator else { return } viewBackgroundActivityIndicator.addSubview(viewActivityIndicator) - + var verticalConstant: CGFloat = 0 if bottom > 0 { verticalConstant = (viewBackgroundActivityIndicator.frame.size.height / 2) - bottom } - + NSLayoutConstraint.activate([ viewActivityIndicator.centerXAnchor.constraint(equalTo: viewBackgroundActivityIndicator.centerXAnchor), viewActivityIndicator.centerYAnchor.constraint(equalTo: viewBackgroundActivityIndicator.centerYAnchor, constant: verticalConstant) ]) - + activityIndicator.startAnimating() } } - + @objc func stopActivityIndicator() { - + DispatchQueue.main.async { - + self.activityIndicator?.stopAnimating() self.activityIndicator?.removeFromSuperview() self.activityIndicator = nil - + self.viewActivityIndicator?.removeFromSuperview() self.viewActivityIndicator = nil - + if self.viewBackgroundActivityIndicator is NCViewActivityIndicator { self.viewBackgroundActivityIndicator?.removeFromSuperview() } self.viewBackgroundActivityIndicator = nil } } - + /* Facebook's comparison algorithm: */ - + func compare(tolerance: Float, expected: Data, observed: Data) throws -> Bool { - + enum customError: Error { case unableToGetUIImageFromData case unableToGetCGImageFromData @@ -673,7 +672,7 @@ class NCUtility: NSObject { case imagesHasDifferentSizes case unableToInitializeContext } - + guard let expectedUIImage = UIImage(data: expected), let observedUIImage = UIImage(data: observed) else { throw customError.unableToGetUIImageFromData } @@ -743,36 +742,36 @@ class NCUtility: NSObject { return isEqual } - + func stringFromTime(_ time: CMTime) -> String { - + let interval = Int(CMTimeGetSeconds(time)) - + let seconds = interval % 60 let minutes = (interval / 60) % 60 let hours = (interval / 3600) - + if hours > 0 { return String(format: "%02d:%02d:%02d", hours, minutes, seconds) } else { return String(format: "%02d:%02d", minutes, seconds) } } - + func colorNavigationController(_ navigationController: UINavigationController?, backgroundColor: UIColor, titleColor: UIColor, tintColor: UIColor?, withoutShadow: Bool) { - + if #available(iOS 13.0, *) { - + // iOS 14, 15 let appearance = UINavigationBarAppearance() appearance.titleTextAttributes = [.foregroundColor: titleColor] appearance.largeTitleTextAttributes = [.foregroundColor: titleColor] - + if withoutShadow { appearance.shadowColor = .clear appearance.shadowImage = UIImage() } - + if let tintColor = tintColor { navigationController?.navigationBar.tintColor = tintColor } @@ -782,19 +781,19 @@ class NCUtility: NSObject { navigationController?.navigationBar.standardAppearance = appearance navigationController?.navigationBar.compactAppearance = appearance navigationController?.navigationBar.scrollEdgeAppearance = appearance - + } else { - + navigationController?.navigationBar.isTranslucent = true navigationController?.navigationBar.barTintColor = backgroundColor - + if withoutShadow { navigationController?.navigationBar.shadowImage = UIImage() navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default) } - + let titleDict: NSDictionary = [NSAttributedString.Key.foregroundColor: titleColor] - navigationController?.navigationBar.titleTextAttributes = titleDict as? [NSAttributedString.Key : Any] + navigationController?.navigationBar.titleTextAttributes = titleDict as? [NSAttributedString.Key: Any] if let tintColor = tintColor { navigationController?.navigationBar.tintColor = tintColor } @@ -805,16 +804,14 @@ class NCUtility: NSObject { // MARK: - class NCViewActivityIndicator: UIView { - + // MARK: - View Life Cycle override init(frame: CGRect) { super.init(frame: frame) } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } - - diff --git a/iOSClient/Utility/NCUtilityFileSystem.swift b/iOSClient/Utility/NCUtilityFileSystem.swift index 17699201d..e64148a37 100644 --- a/iOSClient/Utility/NCUtilityFileSystem.swift +++ b/iOSClient/Utility/NCUtilityFileSystem.swift @@ -29,25 +29,25 @@ class NCUtilityFileSystem: NSObject { let instance = NCUtilityFileSystem() return instance }() - + let fileManager = FileManager.default - + @objc func getFileSize(asset: PHAsset) -> Int64 { - + let resources = PHAssetResource.assetResources(for: asset) - + if let resource = resources.first { if resource.responds(to: #selector(NSDictionary.fileSize)) { let unsignedInt64 = resource.value(forKey: "fileSize") as! CLong return Int64(bitPattern: UInt64(unsignedInt64)) } } - + return 0 } - + @objc func getFileSize(filePath: String) -> Int64 { - + do { let attributes = try fileManager.attributesOfItem(atPath: filePath) return attributes[FileAttributeKey.size] as? Int64 ?? 0 @@ -56,9 +56,9 @@ class NCUtilityFileSystem: NSObject { } return 0 } - + @objc func getFileModificationDate(filePath: String) -> NSDate? { - + do { let attributes = try fileManager.attributesOfItem(atPath: filePath) return attributes[FileAttributeKey.modificationDate] as? NSDate @@ -67,9 +67,9 @@ class NCUtilityFileSystem: NSObject { } return nil } - + @objc func getFileCreationDate(filePath: String) -> NSDate? { - + do { let attributes = try fileManager.attributesOfItem(atPath: filePath) return attributes[FileAttributeKey.creationDate] as? NSDate @@ -78,106 +78,99 @@ class NCUtilityFileSystem: NSObject { } return nil } - + @objc func writeFile(fileURL: URL, text: String) -> Bool { - + do { try FileManager.default.removeItem(at: fileURL) - } - catch { + } catch { print(error) } - + do { try text.write(to: fileURL, atomically: true, encoding: .utf8) return true - } - catch { + } catch { print(error) return false } } - + @objc func deleteFile(filePath: String) { - + do { try FileManager.default.removeItem(atPath: filePath) - } - catch { + } catch { print(error) } } - + @discardableResult @objc func moveFile(atPath: String, toPath: String) -> Bool { if atPath == toPath { return true } - + do { try FileManager.default.removeItem(atPath: toPath) - } - catch { + } catch { print(error) } - + do { try FileManager.default.copyItem(atPath: atPath, toPath: toPath) try FileManager.default.removeItem(atPath: atPath) return true - } - catch { + } catch { print(error) return false } } - + @discardableResult @objc func copyFile(atPath: String, toPath: String) -> Bool { if atPath == toPath { return true } - + do { try FileManager.default.removeItem(atPath: toPath) - } - catch { + } catch { print(error) } - + do { try FileManager.default.copyItem(atPath: atPath, toPath: toPath) return true - } - catch { + } catch { print(error) return false } } - + @objc func moveFileInBackground(atPath: String, toPath: String) { - + if atPath == toPath { return } - + DispatchQueue.global().async { - + try? FileManager.default.removeItem(atPath: toPath) try? FileManager.default.copyItem(atPath: atPath, toPath: toPath) try? FileManager.default.removeItem(atPath: atPath) } } - + @objc func linkItem(atPath: String, toPath: String) { - + try? FileManager.default.removeItem(atPath: toPath) try? FileManager.default.linkItem(atPath: atPath, toPath: toPath) } - + // MARK: - - + @objc func getWebDAV(account: String) -> String { - //return NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesWebDavRoot) ?? "remote.php/webdav" + // return NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesWebDavRoot) ?? "remote.php/webdav" return "remote.php/dav" } - + @objc func getHomeServer(account: String) -> String { var home = self.getWebDAV(account: account) if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) { @@ -185,32 +178,32 @@ class NCUtilityFileSystem: NSObject { } return home } - + @objc func getPath(metadata: tableMetadata) -> String { - + return metadata.path.replacingOccurrences(of: "/remote.php/dav/files/"+metadata.user, with: "") + metadata.fileName } - + @objc func deletingLastPathComponent(account: String, serverUrl: String) -> String { if getHomeServer(account: account) == serverUrl { return serverUrl } let fileName = (serverUrl as NSString).lastPathComponent let serverUrl = serverUrl.replacingOccurrences(of: "/"+fileName, with: "", options: String.CompareOptions.backwards, range: nil) return serverUrl } - + @objc func createFileName(_ fileName: String, serverUrl: String, account: String) -> String { - + var resultFileName = fileName var exitLoop = false - + while exitLoop == false { - + if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "fileNameView == %@ AND serverUrl == %@ AND account == %@", resultFileName, serverUrl, account)) != nil { - + var name = NSString(string: resultFileName).deletingPathExtension let ext = NSString(string: resultFileName).pathExtension let characters = Array(name) - + if characters.count < 2 { if ext == "" { resultFileName = name + " " + "1" @@ -221,7 +214,7 @@ class NCUtilityFileSystem: NSObject { let space = characters[characters.count-2] let numChar = characters[characters.count-1] var num = Int(String(numChar)) - if (space == " " && num != nil) { + if space == " " && num != nil { name = String(name.dropLast()) num = num! + 1 if ext == "" { @@ -237,38 +230,38 @@ class NCUtilityFileSystem: NSObject { } } } - + } else { exitLoop = true } } - + return resultFileName } - + @objc func getDirectorySize(directory: String) -> Int64 { - + let url = URL(fileURLWithPath: directory) let manager = FileManager.default var totalSize: Int64 = 0 - + if let enumerator = manager.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey], options: []) { for case let fileURL as URL in enumerator { if let attributes = try? manager.attributesOfItem(atPath: fileURL.path) { if let size = attributes[.size] as? Int64 { - totalSize = totalSize + size + totalSize += size } } } } - + return totalSize } - + func cleanUp(directory: String, days: TimeInterval) { - + if days == 0 { return} - + let minimumDate = Date().addingTimeInterval(-days*24*60*60) let url = URL(fileURLWithPath: directory) var offlineDir: [String] = [] @@ -279,16 +272,16 @@ class NCUtilityFileSystem: NSObject { offlineDir.append(CCUtility.getDirectoryProviderStorageOcId(directory.ocId)) } } - + let files = NCManageDatabase.shared.getTableLocalFiles(predicate: NSPredicate(format: "offline == true"), sorted: "fileName", ascending: true) for file: tableLocalFile in files { offlineFiles.append(CCUtility.getDirectoryProviderStorageOcId(file.ocId, fileNameView: file.fileName)) } - + func meetsRequirement(date: Date) -> Bool { return date < minimumDate } - + let manager = FileManager.default if let enumerator = manager.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey], options: []) { for case let fileURL as URL in enumerator { @@ -317,4 +310,3 @@ class NCUtilityFileSystem: NSObject { } } } - diff --git a/iOSClient/Viewer/NCViewer.swift b/iOSClient/Viewer/NCViewer.swift index fc7d90f9d..e34784f38 100644 --- a/iOSClient/Viewer/NCViewer.swift +++ b/iOSClient/Viewer/NCViewer.swift @@ -29,7 +29,7 @@ class NCViewer: NSObject { let instance = NCViewer() return instance }() - + let appDelegate = UIApplication.shared.delegate as! AppDelegate private var viewerQuickLook: NCViewerQuickLook? private var metadata = tableMetadata() @@ -39,16 +39,16 @@ class NCViewer: NSObject { self.metadata = metadata self.metadatas = metadatas - + var editor = editor var xxxxxxx = NCCommunicationCommon.shared.getInternalTypeIdentifier(typeIdentifier: metadata.contentType) - + // IMAGE AUDIO VIDEO if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue { - + if let navigationController = viewController.navigationController { - - let viewerMediaPageContainer:NCViewerMediaPage = UIStoryboard(name: "NCViewerMediaPage", bundle: nil).instantiateInitialViewController() as! NCViewerMediaPage + + let viewerMediaPageContainer: NCViewerMediaPage = UIStoryboard(name: "NCViewerMediaPage", bundle: nil).instantiateInitialViewController() as! NCViewerMediaPage var index = 0 for medatasImage in metadatas { if medatasImage.ocId == metadata.ocId { @@ -60,81 +60,81 @@ class NCViewer: NSObject { viewerMediaPageContainer.metadatas = metadatas navigationController.pushViewController(viewerMediaPageContainer, animated: true) } - + return } - + // DOCUMENTS if metadata.classFile == NCCommunicationCommon.typeClassFile.document.rawValue { - + // PDF if metadata.contentType == "application/pdf" || metadata.contentType == "com.adobe.pdf" { - + if let navigationController = viewController.navigationController { - - let viewController:NCViewerPDF = UIStoryboard(name: "NCViewerPDF", bundle: nil).instantiateInitialViewController() as! NCViewerPDF - + + let viewController: NCViewerPDF = UIStoryboard(name: "NCViewerPDF", bundle: nil).instantiateInitialViewController() as! NCViewerPDF + viewController.metadata = metadata viewController.imageIcon = imageIcon - + navigationController.pushViewController(viewController, animated: true) } return } - + // EDITORS let editors = NCUtility.shared.isDirectEditing(account: metadata.account, contentType: metadata.contentType) let availableRichDocument = NCUtility.shared.isRichDocument(metadata) - + // RichDocument: Collabora if (isRichDocument || (availableRichDocument && editors.count == 0)) && NCCommunication.shared.isNetworkReachable() { - + if metadata.url == "" { - + NCUtility.shared.startActivityIndicator(backgroundView: viewController.view, blurEffect: true) - NCCommunication.shared.createUrlRichdocuments(fileID: metadata.fileId) { (account, url, errorCode, errorDescription) in - + NCCommunication.shared.createUrlRichdocuments(fileID: metadata.fileId) { account, url, errorCode, errorDescription in + NCUtility.shared.stopActivityIndicator() if errorCode == 0 && account == self.appDelegate.account && url != nil { - + if let navigationController = viewController.navigationController { - - let viewController:NCViewerRichdocument = UIStoryboard(name: "NCViewerRichdocument", bundle: nil).instantiateInitialViewController() as! NCViewerRichdocument - + + let viewController: NCViewerRichdocument = UIStoryboard(name: "NCViewerRichdocument", bundle: nil).instantiateInitialViewController() as! NCViewerRichdocument + viewController.metadata = metadata viewController.link = url! viewController.imageIcon = imageIcon - + navigationController.pushViewController(viewController, animated: true) } - + } else if errorCode != 0 { - + NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } } - + } else { - + if let navigationController = viewController.navigationController { - - let viewController:NCViewerRichdocument = UIStoryboard(name: "NCViewerRichdocument", bundle: nil).instantiateInitialViewController() as! NCViewerRichdocument - + + let viewController: NCViewerRichdocument = UIStoryboard(name: "NCViewerRichdocument", bundle: nil).instantiateInitialViewController() as! NCViewerRichdocument + viewController.metadata = metadata viewController.link = metadata.url viewController.imageIcon = imageIcon - + navigationController.pushViewController(viewController, animated: true) } } - + return } - + // DirectEditing: Nextcloud Text - OnlyOffice if editors.count > 0 && NCCommunication.shared.isNetworkReachable() { - + if editor == "" { if editors.contains(NCGlobal.shared.editorText) { editor = NCGlobal.shared.editorText @@ -142,67 +142,67 @@ class NCViewer: NSObject { editor = NCGlobal.shared.editorOnlyoffice } } - + if editor == NCGlobal.shared.editorText || editor == NCGlobal.shared.editorOnlyoffice { - + if metadata.url == "" { - + var customUserAgent: String? let fileNamePath = CCUtility.returnFileNamePath(fromFileName: metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, account: metadata.account)! - + if editor == NCGlobal.shared.editorOnlyoffice { customUserAgent = NCUtility.shared.getCustomUserAgentOnlyOffice() } - + NCUtility.shared.startActivityIndicator(backgroundView: viewController.view, blurEffect: true) - NCCommunication.shared.NCTextOpenFile(fileNamePath: fileNamePath, editor: editor, customUserAgent: customUserAgent) { (account, url, errorCode, errorMessage) in - + NCCommunication.shared.NCTextOpenFile(fileNamePath: fileNamePath, editor: editor, customUserAgent: customUserAgent) { account, url, errorCode, errorMessage in + NCUtility.shared.stopActivityIndicator() - + if errorCode == 0 && account == self.appDelegate.account && url != nil { - + if let navigationController = viewController.navigationController { - - let viewController:NCViewerNextcloudText = UIStoryboard(name: "NCViewerNextcloudText", bundle: nil).instantiateInitialViewController() as! NCViewerNextcloudText - + + let viewController: NCViewerNextcloudText = UIStoryboard(name: "NCViewerNextcloudText", bundle: nil).instantiateInitialViewController() as! NCViewerNextcloudText + viewController.metadata = metadata viewController.editor = editor viewController.link = url! viewController.imageIcon = imageIcon - + navigationController.pushViewController(viewController, animated: true) } - + } else if errorCode != 0 { - + NCContentPresenter.shared.messageNotification("_error_", description: errorMessage, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } } - + } else { - + if let navigationController = viewController.navigationController { - - let viewController:NCViewerNextcloudText = UIStoryboard(name: "NCViewerNextcloudText", bundle: nil).instantiateInitialViewController() as! NCViewerNextcloudText - + + let viewController: NCViewerNextcloudText = UIStoryboard(name: "NCViewerNextcloudText", bundle: nil).instantiateInitialViewController() as! NCViewerNextcloudText + viewController.metadata = metadata viewController.editor = editor viewController.link = metadata.url viewController.imageIcon = imageIcon - + navigationController.pushViewController(viewController, animated: true) } } - + } else { - + NCContentPresenter.shared.messageNotification("_error_", description: "_editor_unknown_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError) } - + return } } - + // OTHER let fileNamePath = NSTemporaryDirectory() + metadata.fileNameView @@ -211,28 +211,28 @@ class NCViewer: NSObject { let viewerQuickLook = NCViewerQuickLook(with: URL(fileURLWithPath: fileNamePath), editingMode: false, metadata: metadata) let navigationController = UINavigationController(rootViewController: viewerQuickLook) navigationController.modalPresentationStyle = .overFullScreen - + viewController.present(navigationController, animated: true) } } -//MARK: - SELECT +// MARK: - SELECT extension NCViewer: NCSelectDelegate { func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) { if let serverUrl = serverUrl { let metadata = items[0] as! tableMetadata if move { - NCNetworking.shared.moveMetadata(metadata, serverUrlTo: serverUrl, overwrite: overwrite) { (errorCode, errorDescription) in + NCNetworking.shared.moveMetadata(metadata, serverUrlTo: serverUrl, overwrite: overwrite) { errorCode, errorDescription in if errorCode != 0 { - + NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } } } else if copy { - NCNetworking.shared.copyMetadata(metadata, serverUrlTo: serverUrl, overwrite: overwrite) { (errorCode, errorDescription) in + NCNetworking.shared.copyMetadata(metadata, serverUrlTo: serverUrl, overwrite: overwrite) { errorCode, errorDescription in if errorCode != 0 { - + NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } } diff --git a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCKTVHTTPCache.swift b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCKTVHTTPCache.swift index 3db12e7c7..5a213bcf1 100644 --- a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCKTVHTTPCache.swift +++ b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCKTVHTTPCache.swift @@ -30,105 +30,105 @@ class NCKTVHTTPCache: NSObject { instance.setupHTTPCache() return instance }() - + func getVideoURL(metadata: tableMetadata) -> URL? { - + if CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { - + return URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)) - + } else { - + guard let stringURL = (metadata.serverUrl + "/" + metadata.fileName).addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return nil } - + return NCKTVHTTPCache.shared.getProxyURL(stringURL: stringURL) } } - + func restartProxy(user: String, password: String) { - + if KTVHTTPCache.proxyIsRunning() { KTVHTTPCache.proxyStop() } - + startProxy(user: user, password: password) } - + private func startProxy(user: String, password: String) { - + guard let authData = (user + ":" + password).data(using: .utf8) else { return } - + let authValue = "Basic " + authData.base64EncodedString(options: []) - KTVHTTPCache.downloadSetAdditionalHeaders(["Authorization":authValue, "User-Agent":CCUtility.getUserAgent()]) - + KTVHTTPCache.downloadSetAdditionalHeaders(["Authorization": authValue, "User-Agent": CCUtility.getUserAgent()]) + if !KTVHTTPCache.proxyIsRunning() { do { try KTVHTTPCache.proxyStart() } catch let error { print("Proxy Start error : \(error)") } - } + } } - + private func stopProxy() { - + if KTVHTTPCache.proxyIsRunning() { KTVHTTPCache.proxyStop() } } - + func getProxyURL(stringURL: String) -> URL { - + return KTVHTTPCache.proxyURL(withOriginalURL: URL(string: stringURL)) } - + func getCacheCompleteFileURL(videoURL: URL?) -> URL? { - + return KTVHTTPCache.cacheCompleteFileURL(with: videoURL) } - + func deleteCache(videoURL: URL?) { - + KTVHTTPCache.cacheDelete(with: videoURL) } - + func saveCache(metadata: tableMetadata) { - - if !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView:metadata.fileNameView) { - + + if !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { + guard let stringURL = (metadata.serverUrl + "/" + metadata.fileName).addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return } - + let videoURL = URL(string: stringURL) guard let url = KTVHTTPCache.cacheCompleteFileURL(with: videoURL) else { return } - + CCUtility.copyFile(atPath: url.path, toPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)) NCManageDatabase.shared.addLocalFile(metadata: metadata) KTVHTTPCache.cacheDelete(with: videoURL) - - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["ocId":metadata.ocId, "serverUrl":metadata.serverUrl]) + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl]) } } - + private func setupHTTPCache() { - + KTVHTTPCache.cacheSetMaxCacheLength(NCGlobal.shared.maxHTTPCache) - + if ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil { KTVHTTPCache.logSetConsoleLogEnable(true) } - + do { try KTVHTTPCache.proxyStart() } catch let error { print("Proxy Start error : \(error)") } - - KTVHTTPCache.encodeSetURLConverter { (url) -> URL? in + + KTVHTTPCache.encodeSetURLConverter { url -> URL? in print("URL Filter received URL : " + String(describing: url)) return url } - - KTVHTTPCache.downloadSetUnacceptableContentTypeDisposer { (url, contentType) -> Bool in + + KTVHTTPCache.downloadSetUnacceptableContentTypeDisposer { url, contentType -> Bool in print("Unsupport Content-Type Filter received URL : " + String(describing: url) + " " + String(describing: contentType)) return false } diff --git a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayer.swift b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayer.swift index 68a07520e..a04eb68b0 100644 --- a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayer.swift +++ b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayer.swift @@ -30,8 +30,12 @@ import MediaPlayer class NCPlayer: NSObject { private let appDelegate = UIApplication.shared.delegate as! AppDelegate + + private var url: URL private var playerToolBar: NCPlayerToolBar? + private var imageVideoContainer: imageVideoContainerView private var detailView: NCViewerMediaDetailView? + private var viewController: UIViewController private var observerAVPlayerItemDidPlayToEndTime: Any? private var observerAVPlayertTime: Any? @@ -39,17 +43,20 @@ class NCPlayer: NSObject { public var durationTime: CMTime = .zero public var metadata: tableMetadata public var videoLayer: AVPlayerLayer? - + // MARK: - View Life Cycle - init(url: URL, autoPlay: Bool, imageVideoContainer: imageVideoContainerView, playerToolBar: NCPlayerToolBar?, metadata: tableMetadata, detailView: NCViewerMediaDetailView?) { + init(url: URL, autoPlay: Bool, imageVideoContainer: imageVideoContainerView, playerToolBar: NCPlayerToolBar?, metadata: tableMetadata, detailView: NCViewerMediaDetailView?, viewController: UIViewController) { + self.url = url + self.imageVideoContainer = imageVideoContainer + self.playerToolBar = playerToolBar self.metadata = metadata + self.detailView = detailView + self.viewController = viewController super.init() - self.detailView = detailView - do { try AVAudioSession.sharedInstance().setCategory(.playback) try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.PortOverride.none) @@ -58,8 +65,67 @@ class NCPlayer: NSObject { print(error) } - print("Play URL: \(url)") - player = AVPlayer(url: url) + // Exists the file video encoded + if CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: NCGlobal.shared.fileNameVideoEncoded) { + self.url = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: NCGlobal.shared.fileNameVideoEncoded)) + } + + openAVPlayer() { status, error in + + switch status { + case .loaded: + if autoPlay { + self.player?.play() + } + break + case .failed: + if error?.code == AVError.Code.fileFormatNotRecognized.rawValue && !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: NCGlobal.shared.fileNameVideoEncoded) && !NCBrandOptions.shared.disable_ff { + let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_video_format_not_recognized_", comment: ""), preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { action in + /* + ncFF.convertVideo { session, url in + let returnCode = session?.getReturnCode() + + if returnCode?.isSuccess() ?? false { + self.url = url + self.openAVPlayer() { status, error in + if let error = error { + NCContentPresenter.shared.messageNotification(error.localizedDescription, description: error.localizedFailureReason, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorGeneric, priority: .max) + } + } + } else if returnCode?.isCancel() ?? false { + // nothing + } else { + NCContentPresenter.shared.messageNotification("_error_", description: "_error_something_wrong_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorGeneric, priority: .max) + } + } + */ + })) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in + NCContentPresenter.shared.messageNotification("_info_", description: "_video_conversion_available_after_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorNoError, priority: .max) + })) + self.appDelegate.window?.rootViewController?.present(alertController, animated: true) + } else { + if let title = error?.localizedDescription, let description = error?.localizedFailureReason { + NCContentPresenter.shared.messageNotification(title, description: description, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorGeneric, priority: .max) + } else { + NCContentPresenter.shared.messageNotification("_error_", description: "_error_something_wrong_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorGeneric, priority: .max) + } + } + break + + case .cancelled: + break + default: + break + } + } + } + + internal func openAVPlayer(completion: @escaping (_ status: AVKeyValueStatus, _ error: NSError?)->()) { + + print("Play URL: \(self.url)") + player = AVPlayer(url: self.url) if metadata.livePhoto { player?.isMuted = false @@ -71,166 +137,155 @@ class NCPlayer: NSObject { player?.seek(to: time) } } - + player?.currentItem?.asset.loadValuesAsynchronously(forKeys: ["playable"], completionHandler: { + var error: NSError? = nil - let status = self.player?.currentItem?.asset.statusOfValue(forKey: "playable", error: &error) - switch status { - case .loaded: - DispatchQueue.main.async { - + let status = self.player?.currentItem?.asset.statusOfValue(forKey: "playable", error: &error) ?? .unknown + + DispatchQueue.main.async { + if status == .loaded { self.durationTime = self.player?.currentItem?.asset.duration ?? .zero - NCManageDatabase.shared.addVideoTime(metadata: metadata, time: nil, durationTime: self.durationTime) + NCManageDatabase.shared.addVideoTime(metadata: self.metadata, time: nil, durationTime: self.durationTime) - self.activateObserver(playerToolBar: playerToolBar) + self.activateObserver(playerToolBar: self.playerToolBar) self.videoLayer = AVPlayerLayer(player: self.player) - self.videoLayer!.frame = imageVideoContainer.bounds + self.videoLayer!.frame = self.imageVideoContainer.bounds self.videoLayer!.videoGravity = .resizeAspect - if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue { + if self.metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue { - imageVideoContainer.layer.addSublayer(self.videoLayer!) - imageVideoContainer.playerLayer = self.videoLayer - imageVideoContainer.metadata = self.metadata - imageVideoContainer.image = imageVideoContainer.image?.image(alpha: 0) + self.imageVideoContainer.layer.addSublayer(self.videoLayer!) + self.imageVideoContainer.playerLayer = self.videoLayer + self.imageVideoContainer.metadata = self.metadata + self.imageVideoContainer.image = self.imageVideoContainer.image?.image(alpha: 0) } - self.playerToolBar?.setBarPlayer(ncplayer: self, metadata: metadata) + self.playerToolBar?.setBarPlayer(ncplayer: self, metadata: self.metadata) self.generatorImagePreview() - if !(detailView?.isShow() ?? false) { - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShowPlayerToolBar, userInfo: ["ocId":metadata.ocId, "enableTimerAutoHide": false]) - } - - if autoPlay { - self.player?.play() + if !(self.detailView?.isShow() ?? false) { + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShowPlayerToolBar, userInfo: ["ocId":self.metadata.ocId, "enableTimerAutoHide": false]) } } - break - case .failed: - DispatchQueue.main.async { - if let title = error?.localizedDescription, let description = error?.localizedFailureReason { - NCContentPresenter.shared.messageNotification(title, description: description, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorGeneric, priority: .max) - } else { - NCContentPresenter.shared.messageNotification("_error_", description: "_error_something_wrong_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorGeneric, priority: .max) - } - } - break - case .cancelled: - DispatchQueue.main.async { - //do something, show alert, put a placeholder image etc. - } - break - default: - break + + completion(status, error) } }) } deinit { print("deinit NCPlayer") - + deactivateObserver() } - + func activateObserver(playerToolBar: NCPlayerToolBar?) { - + self.playerToolBar = playerToolBar - + // At end go back to start & show toolbar - observerAVPlayerItemDidPlayToEndTime = NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player?.currentItem, queue: .main) { (notification) in + observerAVPlayerItemDidPlayToEndTime = NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player?.currentItem, queue: .main) { notification in if let item = notification.object as? AVPlayerItem, let currentItem = self.player?.currentItem, item == currentItem { + NCKTVHTTPCache.shared.saveCache(metadata: self.metadata) + self.videoSeek(time: .zero) + if !(self.detailView?.isShow() ?? false) { - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShowPlayerToolBar, userInfo: ["ocId":self.metadata.ocId, "enableTimerAutoHide": false]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShowPlayerToolBar, userInfo: ["ocId": self.metadata.ocId, "enableTimerAutoHide": false]) } + self.playerToolBar?.updateToolBar() } } - + // Evey 1 second update toolbar - observerAVPlayertTime = player?.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(1, preferredTimescale: 1), queue: .main, using: { (CMTime) in + observerAVPlayertTime = player?.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(1, preferredTimescale: 1), queue: .main, using: { _ in if self.player?.currentItem?.status == .readyToPlay { self.playerToolBar?.updateToolBar() } }) - + NotificationCenter.default.addObserver(self, selector: #selector(generatorImagePreview), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationWillResignActive), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidEnterBackground), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(playerPause), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterPauseMedia), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(playerPlay), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterPlayMedia), object: nil) } - + func deactivateObserver() { - + if isPlay() { playerPause() } - + self.playerToolBar = nil - + if let observerAVPlayerItemDidPlayToEndTime = self.observerAVPlayerItemDidPlayToEndTime { NotificationCenter.default.removeObserver(observerAVPlayerItemDidPlayToEndTime) } self.observerAVPlayerItemDidPlayToEndTime = nil - + if let observerAVPlayertTime = self.observerAVPlayertTime { player?.removeTimeObserver(observerAVPlayertTime) } self.observerAVPlayertTime = nil - + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationWillResignActive), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidEnterBackground), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil) + + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterPauseMedia), object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterPlayMedia), object: nil) } - - //MARK: - NotificationCenter + + // MARK: - NotificationCenter @objc func applicationDidEnterBackground(_ notification: NSNotification) { - - guard let playerToolBar = self.playerToolBar else { return } - - if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue { + + if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue, let playerToolBar = self.playerToolBar { if !playerToolBar.isPictureInPictureActive() { playerPause() } } } - + @objc func applicationDidBecomeActive(_ notification: NSNotification) { - + playerToolBar?.updateToolBar() } - - //MARK: - - + + // MARK: - + func isPlay() -> Bool { - + if player?.rate == 1 { return true } else { return false } } - func playerPlay() { + @objc func playerPlay() { player?.play() self.playerToolBar?.updateToolBar() } - func playerPause() { + @objc func playerPause() { player?.pause() self.playerToolBar?.updateToolBar() - + if let playerToolBar = self.playerToolBar, playerToolBar.isPictureInPictureActive() { playerToolBar.pictureInPictureController?.stopPictureInPicture() } } - + func videoSeek(time: CMTime) { - + player?.seek(to: time) self.saveTime(time) } - + func saveTime(_ time: CMTime) { if metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue { return } @@ -238,16 +293,16 @@ class NCPlayer: NSObject { NCManageDatabase.shared.addVideoTime(metadata: metadata, time: time, durationTime: nil) generatorImagePreview() } - + func saveCurrentTime() { - + if let player = self.player { saveTime(player.currentTime()) } } - + @objc func generatorImagePreview() { - + guard let time = player?.currentTime() else { return } if metadata.livePhoto { return } if metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue { return } @@ -266,25 +321,21 @@ class NCPlayer: NSObject { // Update Playing Info Center let mediaItemPropertyTitle = MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPMediaItemPropertyTitle] as? String if let image = image, mediaItemPropertyTitle == metadata.fileNameView { - MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size) { size in + MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size) { _ in return image } } // Preview if let data = image?.jpegData(compressionQuality: 0.5) { - try data.write(to: URL.init(fileURLWithPath: fileNamePreviewLocalPath), options: .atomic) + try data.write(to: URL(fileURLWithPath: fileNamePreviewLocalPath), options: .atomic) } // Icon if let data = image?.jpegData(compressionQuality: 0.5) { - try data.write(to: URL.init(fileURLWithPath: fileNameIconLocalPath), options: .atomic) + try data.write(to: URL(fileURLWithPath: fileNameIconLocalPath), options: .atomic) } - } - catch let error as NSError { + } catch let error as NSError { print(error.localizedDescription) } } } } - - - diff --git a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift index 2943c203a..cd3abadf2 100644 --- a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift +++ b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift @@ -29,7 +29,7 @@ import AVKit import MediaPlayer class NCPlayerToolBar: UIView { - + @IBOutlet weak var playerTopToolBarView: UIView! @IBOutlet weak var pipButton: UIButton! @IBOutlet weak var muteButton: UIButton! @@ -39,20 +39,19 @@ class NCPlayerToolBar: UIView { @IBOutlet weak var playbackSlider: UISlider! @IBOutlet weak var labelLeftTime: UILabel! @IBOutlet weak var labelCurrentTime: UILabel! - + enum sliderEventType { case began case ended case moved } - - private let appDelegate = UIApplication.shared.delegate as! AppDelegate + private var ncplayer: NCPlayer? private var metadata: tableMetadata? private var wasInPlay: Bool = false private var playbackSliderEvent: sliderEventType = .ended private var timerAutoHide: Timer? - + var pictureInPictureController: AVPictureInPictureController? weak var viewerMediaPage: NCViewerMediaPage? @@ -60,74 +59,74 @@ class NCPlayerToolBar: UIView { override func awakeFromNib() { super.awakeFromNib() - + // for disable gesture of UIPageViewController let panRecognizer = UIPanGestureRecognizer(target: self, action: nil) addGestureRecognizer(panRecognizer) let singleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didSingleTapWith(gestureRecognizer:))) addGestureRecognizer(singleTapGestureRecognizer) - + self.layer.cornerRadius = 15 self.layer.masksToBounds = true - + let blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) blurEffectView.frame = self.bounds blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - self.insertSubview(blurEffectView, at:0) - + self.insertSubview(blurEffectView, at: 0) + playerTopToolBarView.layer.cornerRadius = 10 playerTopToolBarView.layer.masksToBounds = true - + let blurEffectTopToolBarView = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) blurEffectTopToolBarView.frame = playerTopToolBarView.bounds blurEffectTopToolBarView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - playerTopToolBarView.insertSubview(blurEffectTopToolBarView, at:0) - + playerTopToolBarView.insertSubview(blurEffectTopToolBarView, at: 0) + pipButton.setImage(NCUtility.shared.loadImage(named: "pip.enter", color: .lightGray), for: .normal) pipButton.isEnabled = false - + muteButton.setImage(NCUtility.shared.loadImage(named: "audioOff", color: .lightGray), for: .normal) muteButton.isEnabled = false - + playbackSlider.value = 0 playbackSlider.minimumValue = 0 playbackSlider.maximumValue = 0 playbackSlider.isContinuous = true playbackSlider.tintColor = .lightGray playbackSlider.isEnabled = false - + labelCurrentTime.text = NCUtility.shared.stringFromTime(.zero) labelCurrentTime.textColor = .lightGray labelLeftTime.text = NCUtility.shared.stringFromTime(.zero) labelLeftTime.textColor = .lightGray - + backButton.isEnabled = false playButton.setImage(NCUtility.shared.loadImage(named: "play.fill", color: .lightGray), for: .normal) playButton.isEnabled = false forwardButton.isEnabled = false - + NotificationCenter.default.addObserver(self, selector: #selector(handleInterruption), name: AVAudioSession.interruptionNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleRouteChange), name: AVAudioSession.routeChangeNotification, object: nil) } - + required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } - + deinit { print("deinit NCPlayerToolBar") - + NotificationCenter.default.removeObserver(self, name: AVAudioSession.interruptionNotification, object: nil) NotificationCenter.default.removeObserver(self, name: AVAudioSession.routeChangeNotification, object: nil) } - + // MARK: - func setBarPlayer(ncplayer: NCPlayer, metadata: tableMetadata) { - + self.ncplayer = ncplayer self.metadata = metadata - + playbackSlider.value = 0 playbackSlider.minimumValue = 0 playbackSlider.maximumValue = Float(ncplayer.durationTime.seconds) @@ -135,14 +134,14 @@ class NCPlayerToolBar: UIView { labelCurrentTime.text = NCUtility.shared.stringFromTime(.zero) labelLeftTime.text = "-" + NCUtility.shared.stringFromTime(ncplayer.durationTime) - + updateToolBar() } - + public func updateToolBar() { - + guard let ncplayer = self.ncplayer else { return } - + // MUTE if let muteButton = muteButton { if CCUtility.getAudioMute() { @@ -152,7 +151,7 @@ class NCPlayerToolBar: UIView { } muteButton.isEnabled = true } - + // PIP if let pipButton = pipButton { if metadata?.classFile == NCCommunicationCommon.typeClassFile.video.rawValue && AVPictureInPictureController.isPictureInPictureSupported() { @@ -163,7 +162,7 @@ class NCPlayerToolBar: UIView { pipButton.isEnabled = false } } - + // SLIDER TIME (START - END) let time = (ncplayer.player?.currentTime() ?? .zero).convertScale(1000, method: .default) playbackSlider.value = Float(time.seconds) @@ -171,7 +170,7 @@ class NCPlayerToolBar: UIView { playbackSlider.isEnabled = true labelCurrentTime.text = NCUtility.shared.stringFromTime(time) labelLeftTime.text = "-" + NCUtility.shared.stringFromTime(ncplayer.durationTime - time) - + // BACK if #available(iOS 13.0, *) { backButton.setImage(NCUtility.shared.loadImage(named: "gobackward.10", color: .white), for: .normal) @@ -179,7 +178,7 @@ class NCPlayerToolBar: UIView { backButton.setImage(NCUtility.shared.loadImage(named: "gobackward.10", color: .white, size: 30), for: .normal) } backButton.isEnabled = true - + // PLAY if ncplayer.isPlay() { MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyPlaybackRate] = 1 @@ -193,7 +192,7 @@ class NCPlayerToolBar: UIView { playButton.setImage(NCUtility.shared.loadImage(named: namedPlay, color: .white, size: 30), for: .normal) } playButton.isEnabled = true - + // FORWARD if #available(iOS 13.0, *) { forwardButton.setImage(NCUtility.shared.loadImage(named: "goforward.10", color: .white), for: .normal) @@ -202,12 +201,12 @@ class NCPlayerToolBar: UIView { } forwardButton.isEnabled = true } - + // MARK: Handle Notifications - + @objc func handleRouteChange(notification: Notification) { - guard let userInfo = notification.userInfo, let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt, let reason = AVAudioSession.RouteChangeReason(rawValue:reasonValue) else { return } - + guard let userInfo = notification.userInfo, let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt, let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else { return } + switch reason { case .newDeviceAvailable: let session = AVAudioSession.sharedInstance() @@ -233,11 +232,11 @@ class NCPlayerToolBar: UIView { default: () } } - + @objc func handleInterruption(notification: Notification) { - + guard let userInfo = notification.userInfo, let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt, let type = AVAudioSession.InterruptionType(rawValue: typeValue) else { return } - + if type == .began { print("Interruption began") } else if type == .ended { @@ -253,73 +252,73 @@ class NCPlayerToolBar: UIView { } } } - + // MARK: - public func show(enableTimerAutoHide: Bool = false) { - + if metadata?.classFile != NCCommunicationCommon.typeClassFile.video.rawValue && metadata?.classFile != NCCommunicationCommon.typeClassFile.audio.rawValue { return } if let metadata = self.metadata, metadata.livePhoto { return } - + timerAutoHide?.invalidate() if enableTimerAutoHide { startTimerAutoHide() } - + if !self.isHidden { return } - + UIView.animate(withDuration: 0.3, animations: { self.alpha = 1 self.playerTopToolBarView.alpha = 1 - }, completion: { (value: Bool) in + }, completion: { (_: Bool) in self.isHidden = false self.playerTopToolBarView.isHidden = false }) - + updateToolBar() } - + func isShow() -> Bool { - + return !self.isHidden } - + public func hide() { - + UIView.animate(withDuration: 0.3, animations: { self.alpha = 0 self.playerTopToolBarView.alpha = 0 - }, completion: { (value: Bool) in + }, completion: { (_: Bool) in self.isHidden = true self.playerTopToolBarView.isHidden = true }) } - + @objc private func automaticHide() { - + if let metadata = self.metadata { - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterHidePlayerToolBar, userInfo: ["ocId":metadata.ocId]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterHidePlayerToolBar, userInfo: ["ocId": metadata.ocId]) } } - + private func startTimerAutoHide() { - + timerAutoHide?.invalidate() timerAutoHide = Timer.scheduledTimer(timeInterval: 3.5, target: self, selector: #selector(automaticHide), userInfo: nil, repeats: false) } - + private func reStartTimerAutoHide() { - + if let timerAutoHide = timerAutoHide, timerAutoHide.isValid { startTimerAutoHide() } } - + func skip(seconds: Float64) { - + guard let ncplayer = ncplayer else { return } guard let player = ncplayer.player else { return } - + let currentTime = player.currentTime() var newTime: CMTime = .zero let timeToAdd: CMTime = CMTimeMakeWithSeconds(abs(seconds), preferredTimescale: 1) @@ -342,34 +341,34 @@ class NCPlayerToolBar: UIView { } ncplayer.videoSeek(time: newTime) } - + updateToolBar() reStartTimerAutoHide() } - + func isPictureInPictureActive() -> Bool { - + if let pictureInPictureController = self.pictureInPictureController, pictureInPictureController.isPictureInPictureActive { return true } else { return false } } - + func stopTimerAutoHide() { - + timerAutoHide?.invalidate() } - - //MARK: - Event / Gesture - + + // MARK: - Event / Gesture + @objc func onSliderValChanged(slider: UISlider, event: UIEvent) { - + if let touchEvent = event.allTouches?.first, let ncplayer = ncplayer { - + let seconds: Int64 = Int64(self.playbackSlider.value) let targetTime: CMTime = CMTimeMake(value: seconds, timescale: 1) - + switch touchEvent.phase { case .began: wasInPlay = ncplayer.isPlay() @@ -387,27 +386,27 @@ class NCPlayerToolBar: UIView { default: break } - + reStartTimerAutoHide() } } - - //MARK: - Action - + + // MARK: - Action + @objc func didSingleTapWith(gestureRecognizer: UITapGestureRecognizer) { // nothing } - + @IBAction func buttonPlayerToolBarTouchInside(_ sender: UIButton) { // nothing } - + @IBAction func buttonPlayerTopToolBarTouchInside(_ sender: UIButton) { // nothing } - + @IBAction func playerPause(_ sender: Any) { - + if ncplayer?.player?.timeControlStatus == .playing { ncplayer?.playerPause() ncplayer?.saveCurrentTime() @@ -431,42 +430,42 @@ class NCPlayerToolBar: UIView { } } } - + @IBAction func setMute(_ sender: Any) { - + let mute = CCUtility.getAudioMute() - + CCUtility.setAudioMute(!mute) ncplayer?.player?.isMuted = !mute updateToolBar() reStartTimerAutoHide() } - + @IBAction func setPip(_ sender: Any) { - + guard let videoLayer = ncplayer?.videoLayer else { return } - + if let pictureInPictureController = self.pictureInPictureController, pictureInPictureController.isPictureInPictureActive { pictureInPictureController.stopPictureInPicture() } - + if pictureInPictureController == nil { pictureInPictureController = AVPictureInPictureController(playerLayer: videoLayer) pictureInPictureController?.delegate = self } - + if let pictureInPictureController = pictureInPictureController, pictureInPictureController.isPictureInPicturePossible, let metadata = self.metadata { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { pictureInPictureController.startPictureInPicture() - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterHidePlayerToolBar, userInfo: ["ocId":metadata.ocId]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterHidePlayerToolBar, userInfo: ["ocId": metadata.ocId]) } } } - + @IBAction func forwardButtonSec(_ sender: Any) { - + skip(seconds: 10) - + /* if metadata?.classFile == NCCommunicationCommon.typeClassFile.video.rawValue { skip(seconds: 10) @@ -475,11 +474,11 @@ class NCPlayerToolBar: UIView { } */ } - + @IBAction func backButtonSec(_ sender: Any) { - + skip(seconds: -10) - + /* if metadata?.classFile == NCCommunicationCommon.typeClassFile.video.rawValue { skip(seconds: -10) @@ -488,47 +487,46 @@ class NCPlayerToolBar: UIView { } */ } - + func forward() { - + var index: Int = 0 - + if let currentIndex = self.viewerMediaPage?.currentIndex, let metadatas = self.viewerMediaPage?.metadatas, let ncplayer = self.ncplayer { - + if currentIndex == metadatas.count - 1 { index = 0 } else { index = currentIndex + 1 } - + self.viewerMediaPage?.goTo(index: index, direction: .forward, autoPlay: ncplayer.isPlay()) } } - + func backward() { - + var index: Int = 0 if let currentIndex = self.viewerMediaPage?.currentIndex, let metadatas = self.viewerMediaPage?.metadatas, let ncplayer = self.ncplayer { - + if currentIndex == 0 { index = metadatas.count - 1 } else { index = currentIndex - 1 } - + self.viewerMediaPage?.goTo(index: index, direction: .reverse, autoPlay: ncplayer.isPlay()) } } } extension NCPlayerToolBar: AVPictureInPictureControllerDelegate { - + func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { if let metadata = self.metadata, let ncplayer = self.ncplayer, !ncplayer.isPlay() { - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShowPlayerToolBar, userInfo: ["ocId":metadata.ocId, "enableTimerAutoHide": false]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShowPlayerToolBar, userInfo: ["ocId": metadata.ocId, "enableTimerAutoHide": false]) } } } - diff --git a/iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift b/iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift index 2437f8d1b..997c53706 100644 --- a/iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift +++ b/iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift @@ -26,7 +26,7 @@ import SVGKit import NCCommunication class NCViewerMedia: UIViewController { - + @IBOutlet weak var detailViewTopConstraint: NSLayoutConstraint! @IBOutlet weak var detailViewHeighConstraint: NSLayoutConstraint! @IBOutlet weak var imageViewTopConstraint: NSLayoutConstraint! @@ -37,7 +37,7 @@ class NCViewerMedia: UIViewController { @IBOutlet weak var statusLabel: UILabel! @IBOutlet weak var detailView: NCViewerMediaDetailView! @IBOutlet weak var playerToolBar: NCPlayerToolBar! - + private var _autoPlay: Bool = false let appDelegate = UIApplication.shared.delegate as! AppDelegate @@ -49,7 +49,7 @@ class NCViewerMedia: UIViewController { var doubleTapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer() var imageViewConstraint: CGFloat = 0 var isDetailViewInitializze: Bool = false - + var autoPlay: Bool { get { let temp = _autoPlay @@ -60,48 +60,48 @@ class NCViewerMedia: UIViewController { _autoPlay = newVal } } - + // MARK: - View Life Cycle required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - + doubleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didDoubleTapWith(gestureRecognizer:))) doubleTapGestureRecognizer.numberOfTapsRequired = 2 } - + deinit { print("deinit NCViewerMedia") - + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterOpenMediaDetail), object: nil) } - + override func viewDidLoad() { super.viewDidLoad() - + scrollView.delegate = self scrollView.maximumZoomScale = 4 scrollView.minimumZoomScale = 1 - + view.addGestureRecognizer(doubleTapGestureRecognizer) - + if NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) != nil { statusViewImage.image = NCUtility.shared.loadImage(named: "livephoto", color: .gray) statusLabel.text = "LIVE" - } else { + } else { statusViewImage.image = nil statusLabel.text = "" } - + playerToolBar.viewerMediaPage = viewerMediaPage - + detailViewTopConstraint.constant = 0 detailView.hide() - + self.image = nil self.imageVideoContainer.image = nil - loadImage(metadata: metadata) { ocId, image in + loadImage(metadata: metadata) { _, image in self.image = image // do not update if is present the videoLayer let numSublayers = self.imageVideoContainer.layer.sublayers?.count @@ -110,75 +110,75 @@ class NCViewerMedia: UIViewController { } } } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + viewerMediaPage?.navigationController?.navigationBar.prefersLargeTitles = false viewerMediaPage?.navigationItem.title = metadata.fileNameView - + if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue, let viewerMediaPage = self.viewerMediaPage { viewerMediaPage.currentScreenMode = viewerMediaPage.saveScreenModeImage } - + if viewerMediaPage?.currentScreenMode == .full { - + viewerMediaPage?.navigationController?.setNavigationBarHidden(true, animated: true) - + NCUtility.shared.colorNavigationController(viewerMediaPage?.navigationController, backgroundColor: .black, titleColor: .white, tintColor: nil, withoutShadow: false) - + viewerMediaPage?.view.backgroundColor = .black viewerMediaPage?.textColor = .white viewerMediaPage?.progressView.isHidden = true - + } else { - + viewerMediaPage?.navigationController?.setNavigationBarHidden(false, animated: true) - + NCUtility.shared.colorNavigationController(viewerMediaPage?.navigationController, backgroundColor: NCBrandColor.shared.systemBackground, titleColor: NCBrandColor.shared.label, tintColor: nil, withoutShadow: false) - + viewerMediaPage?.view.backgroundColor = NCBrandColor.shared.systemBackground viewerMediaPage?.textColor = NCBrandColor.shared.label viewerMediaPage?.progressView.isHidden = false } } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - - if (metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue) { - + + if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue { + NCKTVHTTPCache.shared.restartProxy(user: appDelegate.user, password: appDelegate.password) - + if ncplayer == nil, let url = NCKTVHTTPCache.shared.getVideoURL(metadata: metadata) { - self.ncplayer = NCPlayer.init(url: url, autoPlay: self.autoPlay, imageVideoContainer: self.imageVideoContainer, playerToolBar: self.playerToolBar, metadata: self.metadata, detailView: self.detailView) + self.ncplayer = NCPlayer.init(url: url, autoPlay: self.autoPlay, imageVideoContainer: self.imageVideoContainer, playerToolBar: self.playerToolBar, metadata: self.metadata, detailView: self.detailView, viewController: self) } else { self.ncplayer?.activateObserver(playerToolBar: self.playerToolBar) if detailView.isShow() == false && ncplayer?.isPlay() == false { - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShowPlayerToolBar, userInfo: ["ocId":metadata.ocId, "enableTimerAutoHide": false]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShowPlayerToolBar, userInfo: ["ocId": metadata.ocId, "enableTimerAutoHide": false]) } } - + if let ncplayer = self.ncplayer { self.viewerMediaPage?.updateCommandCenter(ncplayer: ncplayer, metadata: self.metadata) } - + } else if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue { - + viewerMediaPage?.clearCommandCenter() } - + NotificationCenter.default.addObserver(self, selector: #selector(openDetail(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterOpenMediaDetail), object: nil) } - + override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) } - + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) - - coordinator.animate(alongsideTransition: { (context) in + + coordinator.animate(alongsideTransition: { context in // back to the original size self.scrollView.zoom(to: CGRect(x: 0, y: 0, width: self.scrollView.bounds.width, height: self.scrollView.bounds.height), animated: false) self.view.layoutIfNeeded() @@ -187,16 +187,16 @@ class NCViewerMedia: UIViewController { self.openDetail() } } - }) { (_) in } + }) { _ in } } - - //MARK: - Image - - func loadImage(metadata: tableMetadata, completion: @escaping (_ ocId: String, _ image: UIImage?)->()) { - + + // MARK: - Image + + func loadImage(metadata: tableMetadata, completion: @escaping (_ ocId: String, _ image: UIImage?) -> Void) { + // Download preview if metadata.hasPreview && !CCUtility.fileProviderStoragePreviewIconExists(metadata.ocId, etag: metadata.etag) { - + var etagResource: String? let fileNamePath = CCUtility.returnFileNamePath(fromFileName: metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, account: metadata.account)! let fileNamePreviewLocalPath = CCUtility.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)! @@ -204,97 +204,104 @@ class NCViewerMedia: UIViewController { if FileManager.default.fileExists(atPath: fileNameIconLocalPath) && FileManager.default.fileExists(atPath: fileNamePreviewLocalPath) { etagResource = metadata.etagResource } - - NCCommunication.shared.downloadPreview(fileNamePathOrFileId: fileNamePath, fileNamePreviewLocalPath: fileNamePreviewLocalPath , widthPreview: NCGlobal.shared.sizePreview, heightPreview: NCGlobal.shared.sizePreview, fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon, etag: etagResource, queue: NCCommunicationCommon.shared.backgroundQueue) { (account, imagePreview, imageIcon, imageOriginal, etag, errorCode, errorDescription) in - - if errorCode == 0 && imageIcon != nil { - NCManageDatabase.shared.setMetadataEtagResource(ocId: metadata.ocId, etagResource: etag) + + NCCommunication.shared.downloadPreview( + fileNamePathOrFileId: fileNamePath, + fileNamePreviewLocalPath: fileNamePreviewLocalPath, + widthPreview: NCGlobal.shared.sizePreview, + heightPreview: NCGlobal.shared.sizePreview, + fileNameIconLocalPath: fileNameIconLocalPath, + sizeIcon: NCGlobal.shared.sizeIcon, etag: etagResource, + queue: NCCommunicationCommon.shared.backgroundQueue) { _, _, imageIcon, _, etag, errorCode, _ in + + if errorCode == 0 && imageIcon != nil { + NCManageDatabase.shared.setMetadataEtagResource(ocId: metadata.ocId, etagResource: etag) + } + + // Download file max resolution + downloadFile(metadata: metadata) + // Download file live photo + if metadata.livePhoto { downloadFileLivePhoto(metadata: metadata) } } - - // Download file max resolution - downloadFile(metadata: metadata) - // Download file live photo - if metadata.livePhoto { downloadFileLivePhoto(metadata: metadata) } - } } else { - + // Download file max resolution downloadFile(metadata: metadata) // Download file live photo if metadata.livePhoto { downloadFileLivePhoto(metadata: metadata) } } - + // Download file max resolution func downloadFile(metadata: tableMetadata) { - + let isFolderEncrypted = CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase) let ext = CCUtility.getExtension(metadata.fileNameView) - + if (CCUtility.getAutomaticDownloadImage() || (metadata.contentType == "image/heic" && metadata.hasPreview == false) || ext == "GIF" || ext == "SVG" || isFolderEncrypted) && (metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue && !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) && metadata.session == "") { - - NCNetworking.shared.download(metadata: metadata, selector: "") { (_) in - + + NCNetworking.shared.download(metadata: metadata, selector: "") { _ in + DispatchQueue.main.async { let image = getImageMetadata(metadata) completion(metadata.ocId, image) } } - + } else { - + DispatchQueue.main.async { let image = getImageMetadata(metadata) completion(metadata.ocId, image) } } } - + // Download Live Photo func downloadFileLivePhoto(metadata: tableMetadata) { - + let fileName = (metadata.fileNameView as NSString).deletingPathExtension + ".mov" if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView LIKE[c] %@", metadata.account, metadata.serverUrl, fileName)), !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { - NCNetworking.shared.download(metadata: metadata, selector: "") { (_) in } + NCNetworking.shared.download(metadata: metadata, selector: "") { _ in } } } - + func getImageMetadata(_ metadata: tableMetadata) -> UIImage? { - + if let image = getImage(metadata: metadata) { return image } - + if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue && !metadata.hasPreview { NCUtility.shared.createImageFrom(fileName: metadata.fileNameView, ocId: metadata.ocId, etag: metadata.etag, classFile: metadata.classFile) } - + if CCUtility.fileProviderStoragePreviewIconExists(metadata.ocId, etag: metadata.etag) { if let imagePreviewPath = CCUtility.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag) { - return UIImage.init(contentsOfFile: imagePreviewPath) + return UIImage(contentsOfFile: imagePreviewPath) } } - + if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue { - return UIImage.init(named: "noPreviewVideo")!.image(color: .gray, size: view.frame.width) + return UIImage(named: "noPreviewVideo")!.image(color: .gray, size: view.frame.width) } else if metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue { - return UIImage.init(named: "noPreviewAudio")!.image(color: .gray, size: view.frame.width) + return UIImage(named: "noPreviewAudio")!.image(color: .gray, size: view.frame.width) } else { - return UIImage.init(named: "noPreview")!.image(color: .gray, size: view.frame.width) + return UIImage(named: "noPreview")!.image(color: .gray, size: view.frame.width) } } - + func getImage(metadata: tableMetadata) -> UIImage? { - + let ext = CCUtility.getExtension(metadata.fileNameView) var image: UIImage? - + if CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) && metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue { - + let previewPath = CCUtility.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)! let imagePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! - + if ext == "GIF" { if !FileManager().fileExists(atPath: previewPath) { NCUtility.shared.createImageFrom(fileName: metadata.fileNameView, ocId: metadata.ocId, etag: metadata.etag, classFile: metadata.classFile) @@ -318,29 +325,29 @@ class NCViewerMedia: UIViewController { } } else { NCUtility.shared.createImageFrom(fileName: metadata.fileNameView, ocId: metadata.ocId, etag: metadata.etag, classFile: metadata.classFile) - image = UIImage.init(contentsOfFile: imagePath) + image = UIImage(contentsOfFile: imagePath) } } - + return image } } - - //MARK: - Gesture + + // MARK: - Gesture @objc func didDoubleTapWith(gestureRecognizer: UITapGestureRecognizer) { - + if detailView.isShow() { return } // NO ZOOM for Audio if metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue { return } - + let pointInView = gestureRecognizer.location(in: self.imageVideoContainer) var newZoomScale = self.scrollView.maximumZoomScale - + if self.scrollView.zoomScale >= newZoomScale || abs(self.scrollView.zoomScale - newZoomScale) <= 0.01 { newZoomScale = self.scrollView.minimumZoomScale } - + let width = self.scrollView.bounds.width / newZoomScale let height = self.scrollView.bounds.height / newZoomScale let originX = pointInView.x - (width / 2.0) @@ -348,15 +355,15 @@ class NCViewerMedia: UIViewController { let rectToZoomTo = CGRect(x: originX, y: originY, width: width, height: height) self.scrollView.zoom(to: rectToZoomTo, animated: true) } - + @objc func didPanWith(gestureRecognizer: UIPanGestureRecognizer) { - + let currentLocation = gestureRecognizer.translation(in: self.view) - + switch gestureRecognizer.state { - + case .began: - + // let velocity = gestureRecognizer.velocity(in: self.view) // gesture moving Up @@ -366,7 +373,7 @@ class NCViewerMedia: UIViewController { break case .ended: - + if detailView.isShow() { self.imageViewTopConstraint.constant = -imageViewConstraint self.imageViewBottomConstraint.constant = imageViewConstraint @@ -376,60 +383,60 @@ class NCViewerMedia: UIViewController { } case .changed: - + imageViewTopConstraint.constant = (currentLocation.y - imageViewConstraint) imageViewBottomConstraint.constant = -(currentLocation.y - imageViewConstraint) - + // DISMISS VIEW if detailView.isHidden && (currentLocation.y > 20) { - + viewerMediaPage?.navigationController?.popViewController(animated: true) gestureRecognizer.state = .ended } - + // CLOSE DETAIL if !detailView.isHidden && (currentLocation.y > 20) { - + self.closeDetail() gestureRecognizer.state = .ended } // OPEN DETAIL if detailView.isHidden && (currentLocation.y < -20) { - + self.openDetail() gestureRecognizer.state = .ended } - + default: break } } } -//MARK: - +// MARK: - extension NCViewerMedia { - + @objc func openDetail(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, ocId == metadata.ocId { openDetail() } } - + private func openDetail() { - - CCUtility.setExif(metadata) { (latitude, longitude, location, date, lensModel) in - - if (latitude != -1 && latitude != 0 && longitude != -1 && longitude != 0) { + + CCUtility.setExif(metadata) { latitude, longitude, location, date, lensModel in + + if latitude != -1 && latitude != 0 && longitude != -1 && longitude != 0 { self.detailViewHeighConstraint.constant = self.view.bounds.height / 2 } else { self.detailViewHeighConstraint.constant = 170 } self.view.layoutIfNeeded() - self.detailView.show(metadata:self.metadata, image: self.image, textColor: self.viewerMediaPage?.textColor, latitude: latitude, longitude: longitude, location: location, date: date, lensModel: lensModel, delegate: self) + self.detailView.show(metadata:self.metadata, image: self.image, textColor: self.viewerMediaPage?.textColor, latitude: latitude, longitude: longitude, location: location, date: date, lensModel: lensModel, ncplayer: self.ncplayer ,delegate: self) if let image = self.imageVideoContainer.image { let ratioW = self.imageVideoContainer.frame.width / image.size.width @@ -439,62 +446,62 @@ extension NCViewerMedia { self.imageViewConstraint = self.detailView.frame.height - ((self.view.frame.height - imageHeight) / 2) + self.view.safeAreaInsets.bottom if self.imageViewConstraint < 0 { self.imageViewConstraint = 0 } } - + UIView.animate(withDuration: 0.3) { self.imageViewTopConstraint.constant = -self.imageViewConstraint self.imageViewBottomConstraint.constant = self.imageViewConstraint self.detailViewTopConstraint.constant = self.detailViewHeighConstraint.constant self.view.layoutIfNeeded() - } completion: { (_) in + } completion: { _ in } - + self.scrollView.pinchGestureRecognizer?.isEnabled = false self.playerToolBar.hide() } } - + private func closeDetail() { - + self.detailView.hide() imageViewConstraint = 0 - + UIView.animate(withDuration: 0.3) { self.imageViewTopConstraint.constant = 0 self.imageViewBottomConstraint.constant = 0 self.detailViewTopConstraint.constant = 0 self.view.layoutIfNeeded() - } completion: { (_) in + } completion: { _ in } - + scrollView.pinchGestureRecognizer?.isEnabled = true if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue && !metadata.livePhoto && ncplayer?.player?.timeControlStatus == .paused { - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShowPlayerToolBar, userInfo: ["ocId":metadata.ocId, "enableTimerAutoHide": false]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShowPlayerToolBar, userInfo: ["ocId": metadata.ocId, "enableTimerAutoHide": false]) } } - + func reloadDetail() { - + if self.detailView.isShow() { CCUtility.setExif(metadata) { (latitude, longitude, location, date, lensModel) in - self.detailView.show(metadata:self.metadata, image: self.image, textColor: self.viewerMediaPage?.textColor, latitude: latitude, longitude: longitude, location: location, date: date, lensModel: lensModel, delegate: self) + self.detailView.show(metadata:self.metadata, image: self.image, textColor: self.viewerMediaPage?.textColor, latitude: latitude, longitude: longitude, location: location, date: date, lensModel: lensModel, ncplayer: self.ncplayer ,delegate: self) } } } } -//MARK: - +// MARK: - extension NCViewerMedia: UIScrollViewDelegate { - + func viewForZooming(in scrollView: UIScrollView) -> UIView? { return imageVideoContainer } - + func scrollViewDidZoom(_ scrollView: UIScrollView) { - + if scrollView.zoomScale > 1 { if let image = imageVideoContainer.image { - + let ratioW = imageVideoContainer.frame.width / image.size.width let ratioH = imageVideoContainer.frame.height / image.size.height let ratio = ratioW < ratioH ? ratioW : ratioH @@ -503,29 +510,29 @@ extension NCViewerMedia: UIScrollViewDelegate { let conditionLeft = newWidth*scrollView.zoomScale > imageVideoContainer.frame.width let left = 0.5 * (conditionLeft ? newWidth - imageVideoContainer.frame.width : (scrollView.frame.width - scrollView.contentSize.width)) let conditioTop = newHeight*scrollView.zoomScale > imageVideoContainer.frame.height - + let top = 0.5 * (conditioTop ? newHeight - imageVideoContainer.frame.height : (scrollView.frame.height - scrollView.contentSize.height)) - + scrollView.contentInset = UIEdgeInsets(top: top, left: left, bottom: top, right: left) } } else { scrollView.contentInset = .zero } } - + func scrollViewDidScroll(_ scrollView: UIScrollView) { } } -extension NCViewerMedia: NCViewerMediaDetailViewDelegate { - +extension NCViewerMedia: NCViewerMediaDetailViewDelegate { + func downloadFullResolution() { closeDetail() - NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorOpenDetail) { (_) in } + NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorOpenDetail) { _ in } } } -//MARK: - +// MARK: - class imageVideoContainerView: UIImageView { var playerLayer: CALayer? diff --git a/iOSClient/Viewer/NCViewerMedia/NCViewerMediaDetailView.swift b/iOSClient/Viewer/NCViewerMedia/NCViewerMediaDetailView.swift index 9ad5e540a..dc15718fc 100644 --- a/iOSClient/Viewer/NCViewerMedia/NCViewerMediaDetailView.swift +++ b/iOSClient/Viewer/NCViewerMedia/NCViewerMediaDetailView.swift @@ -25,12 +25,12 @@ import UIKit import MapKit import NCCommunication -public protocol NCViewerMediaDetailViewDelegate { +public protocol NCViewerMediaDetailViewDelegate: AnyObject { func downloadFullResolution() } class NCViewerMediaDetailView: UIView { - + @IBOutlet weak var separator: UIView! @IBOutlet weak var sizeLabel: UILabel! @IBOutlet weak var sizeValue: UILabel! @@ -43,7 +43,7 @@ class NCViewerMediaDetailView: UIView { @IBOutlet weak var messageButton: UIButton! @IBOutlet weak var mapContainer: UIView! @IBOutlet weak var locationButton: UIButton! - + var latitude: Double = 0 var longitude: Double = 0 var location: String? @@ -51,11 +51,12 @@ class NCViewerMediaDetailView: UIView { var lensModel: String? var metadata: tableMetadata? var mapView: MKMapView? + var ncplayer: NCPlayer? var delegate: NCViewerMediaDetailViewDelegate? override func awakeFromNib() { super.awakeFromNib() - + separator.backgroundColor = NCBrandColor.shared.separator sizeLabel.text = "" sizeValue.text = "" @@ -65,18 +66,18 @@ class NCViewerMediaDetailView: UIView { dimValue.text = "" lensModelLabel.text = "" lensModelValue.text = "" - messageButton.setTitle("" , for: .normal) - locationButton.setTitle("" , for: .normal) + messageButton.setTitle("", for: .normal) + locationButton.setTitle("", for: .normal) } - + deinit { print("deinit NCViewerMediaDetailView") - + self.mapView?.removeFromSuperview() self.mapView = nil } - func show(metadata: tableMetadata, image: UIImage?, textColor: UIColor?, latitude: Double, longitude: Double, location: String?, date: Date?, lensModel: String?, delegate: NCViewerMediaDetailViewDelegate?) { + func show(metadata: tableMetadata, image: UIImage?, textColor: UIColor?, latitude: Double, longitude: Double, location: String?, date: Date?, lensModel: String?, ncplayer: NCPlayer?, delegate: NCViewerMediaDetailViewDelegate?) { self.metadata = metadata self.latitude = latitude @@ -84,25 +85,26 @@ class NCViewerMediaDetailView: UIView { self.location = location self.date = date self.lensModel = lensModel + self.ncplayer = ncplayer self.delegate = delegate - + if mapView == nil && (latitude != -1 && latitude != 0 && longitude != -1 && longitude != 0) { - + let annotation = MKPointAnnotation() annotation.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) - - self.mapView = MKMapView.init() + + self.mapView = MKMapView() if let mapView = self.mapView { mapView.translatesAutoresizingMaskIntoConstraints = false self.mapContainer.addSubview(mapView) - + NSLayoutConstraint.activate([ mapView.topAnchor.constraint(equalTo: self.mapContainer.topAnchor), mapView.bottomAnchor.constraint(equalTo: self.mapContainer.bottomAnchor), mapView.leadingAnchor.constraint(equalTo: self.mapContainer.leadingAnchor), - mapView.trailingAnchor.constraint(equalTo: self.mapContainer.trailingAnchor), + mapView.trailingAnchor.constraint(equalTo: self.mapContainer.trailingAnchor) ]) - + mapView.layer.cornerRadius = 6 mapView.isZoomEnabled = true mapView.isScrollEnabled = false @@ -111,19 +113,19 @@ class NCViewerMediaDetailView: UIView { mapView.setRegion(MKCoordinateRegion(center: annotation.coordinate, latitudinalMeters: 500, longitudinalMeters: 500), animated: false) } } - + // Size sizeLabel.text = NSLocalizedString("_size_", comment: "") sizeValue.text = CCUtility.transformedSize(metadata.size) sizeValue.textColor = textColor - + // Date if let date = date { let formatter = DateFormatter() formatter.dateStyle = .full formatter.timeStyle = .medium let dateString = formatter.string(from: date as Date) - + dateLabel.text = NSLocalizedString("_date_", comment: "") dateValue.text = dateString } else { @@ -131,14 +133,14 @@ class NCViewerMediaDetailView: UIView { dateValue.text = NSLocalizedString("_not_available_", comment: "") } dateValue.textColor = textColor - + // Dimension / Duration if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue { if let image = image { dimLabel.text = NSLocalizedString("_resolution_", comment: "") dimValue.text = "\(Int(image.size.width)) x \(Int(image.size.height))" } - } else if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue { + } else if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue { if let durationTime = NCManageDatabase.shared.getVideoDurationTime(metadata: metadata) { self.dimLabel.text = NSLocalizedString("_duration_", comment: "") self.dimValue.text = NCUtility.shared.stringFromTime(durationTime) @@ -152,46 +154,46 @@ class NCViewerMediaDetailView: UIView { lensModelValue.text = lensModel lensModelValue.textColor = textColor } - + // Message if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue && !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) && metadata.session == "" { messageButton.setTitle(NSLocalizedString("_try_download_full_resolution_", comment: ""), for: .normal) messageButton.isHidden = false } else { - messageButton.setTitle("" , for: .normal) + messageButton.setTitle("", for: .normal) messageButton.isHidden = true } - + // Location if let location = location { locationButton.setTitle(location, for: .normal) locationButton.isHidden = false } else { - locationButton.setTitle("" , for: .normal) + locationButton.setTitle("", for: .normal) locationButton.isHidden = true } - + self.isHidden = false } - + func hide() { self.isHidden = true } - + func isShow() -> Bool { return !self.isHidden } - - //MARK: - Action + + // MARK: - Action @IBAction func touchLocation(_ sender: Any) { - + if latitude != -1 && latitude != 0 && longitude != -1 && longitude != 0 { - + let latitude: CLLocationDegrees = self.latitude let longitude: CLLocationDegrees = self.longitude - let regionDistance:CLLocationDistance = 10000 + let regionDistance: CLLocationDistance = 10000 let coordinates = CLLocationCoordinate2DMake(latitude, longitude) let regionSpan = MKCoordinateRegion(center: coordinates, latitudinalMeters: regionDistance, longitudinalMeters: regionDistance) let options = [ @@ -204,18 +206,18 @@ class NCViewerMediaDetailView: UIView { mapItem.openInMaps(launchOptions: options) } } - + @IBAction func touchFavorite(_ sender: Any) { - + } - + @IBAction func touchMessage(_ sender: Any) { - + delegate?.downloadFullResolution() } - - //MARK: - - func secondsToHoursMinutesSeconds (seconds : Int) -> (Int, Int, Int) { + + // MARK: - + func secondsToHoursMinutesSeconds (seconds: Int) -> (Int, Int, Int) { return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60) } } diff --git a/iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.swift b/iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.swift index e2ba26f52..afe06d96f 100644 --- a/iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.swift +++ b/iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.swift @@ -28,7 +28,7 @@ import MediaPlayer class NCViewerMediaPage: UIViewController { @IBOutlet weak var progressView: UIProgressView! - + enum ScreenMode { case full, normal } @@ -38,37 +38,33 @@ class NCViewerMediaPage: UIViewController { var pageViewController: UIPageViewController { return self.children[0] as! UIPageViewController } - + var currentViewController: NCViewerMedia { return self.pageViewController.viewControllers![0] as! NCViewerMedia } - - let appDelegate = UIApplication.shared.delegate as! AppDelegate var metadatas: [tableMetadata] = [] var currentIndex = 0 var nextIndex: Int? - var IndexInPlay: Int = -1 var ncplayerLivePhoto: NCPlayer? var panGestureRecognizer: UIPanGestureRecognizer! var singleTapGestureRecognizer: UITapGestureRecognizer! var longtapGestureRecognizer: UILongPressGestureRecognizer! - var textColor: UIColor = NCBrandColor.shared.label + var textColor: UIColor = NCBrandColor.shared.label var playCommand: Any? var pauseCommand: Any? var skipForwardCommand: Any? var skipBackwardCommand: Any? var nextTrackCommand: Any? var previousTrackCommand: Any? - // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - - navigationItem.rightBarButtonItem = UIBarButtonItem.init(image: UIImage(named: "more")!.image(color: NCBrandColor.shared.label, size: 25), style: .plain, target: self, action: #selector(self.openMenuMore)) - + + navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "more")!.image(color: NCBrandColor.shared.label, size: 25), style: .plain, target: self, action: #selector(self.openMenuMore)) + singleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didSingleTapWith(gestureRecognizer:))) panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(didPanWith(gestureRecognizer:))) longtapGestureRecognizer = UILongPressGestureRecognizer() @@ -76,39 +72,41 @@ class NCViewerMediaPage: UIViewController { longtapGestureRecognizer.minimumPressDuration = 0.3 longtapGestureRecognizer.delegate = self longtapGestureRecognizer.addTarget(self, action: #selector(didLongpressGestureEvent(gestureRecognizer:))) - + pageViewController.delegate = self pageViewController.dataSource = self pageViewController.view.addGestureRecognizer(panGestureRecognizer) pageViewController.view.addGestureRecognizer(singleTapGestureRecognizer) pageViewController.view.addGestureRecognizer(longtapGestureRecognizer) - let viewerMedia = getViewerMedia(index: currentIndex, metadata: metadatas[currentIndex], direction: .forward) + let viewerMedia = getViewerMedia(index: currentIndex, metadata: metadatas[currentIndex]) pageViewController.setViewControllers([viewerMedia], direction: .forward, animated: true, completion: nil) - + NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(viewUnload), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMenuDetailClose), object: nil) - + progressView.tintColor = NCBrandColor.shared.brandElement progressView.trackTintColor = .clear progressView.progress = 0 - + NotificationCenter.default.addObserver(self, selector: #selector(deleteFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDeleteFile), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(renameFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterRenameFile), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(moveFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMoveFile), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(downloadedFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(triggerProgressTask(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask), object:nil) - + NotificationCenter.default.addObserver(self, selector: #selector(triggerProgressTask(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(hidePlayerToolBar(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterHidePlayerToolBar), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(showPlayerToolBar(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterShowPlayerToolBar), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(reloadMediaPage(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadMediaPage), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil) } - + override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) - + // Clear if let ncplayer = currentViewController.ncplayer, ncplayer.isPlay() { ncplayer.playerPause() @@ -116,10 +114,10 @@ class NCViewerMediaPage: UIViewController { } currentViewController.playerToolBar.stopTimerAutoHide() clearCommandCenter() - + metadatas.removeAll() ncplayerLivePhoto = nil - + // Remove Observer NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDeleteFile), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterRenameFile), object: nil) @@ -127,25 +125,27 @@ class NCViewerMediaPage: UIViewController { NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask), object: nil) - + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterHidePlayerToolBar), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterShowPlayerToolBar), object: nil) - + + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadMediaPage), object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil) } - + override var preferredStatusBarStyle: UIStatusBarStyle { - + if currentScreenMode == .normal { return .default } else { return .lightContent } } - + // MARK: - - func getViewerMedia(index: Int, metadata: tableMetadata, direction: UIPageViewController.NavigationDirection) -> NCViewerMedia { + func getViewerMedia(index: Int, metadata: tableMetadata) -> NCViewerMedia { let viewerMedia = UIStoryboard(name: "NCViewerMediaPage", bundle: nil).instantiateViewController(withIdentifier: "NCViewerMedia") as! NCViewerMedia viewerMedia.index = index @@ -153,66 +153,66 @@ class NCViewerMediaPage: UIViewController { viewerMedia.viewerMediaPage = self singleTapGestureRecognizer.require(toFail: viewerMedia.doubleTapGestureRecognizer) - + return viewerMedia } @objc func viewUnload() { - + navigationController?.popViewController(animated: true) } - + @objc func openMenuMore() { - + let imageIcon = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(currentViewController.metadata.ocId, etag: currentViewController.metadata.etag)) NCViewer.shared.toggleMenu(viewController: self, metadata: currentViewController.metadata, webView: false, imageIcon: imageIcon) } - + func changeScreenMode(mode: ScreenMode, enableTimerAutoHide: Bool = false) { - + if mode == .normal { - + navigationController?.setNavigationBarHidden(false, animated: true) progressView.isHidden = false if !currentViewController.detailView.isShow() { currentViewController.playerToolBar.show(enableTimerAutoHide: enableTimerAutoHide) } - + NCUtility.shared.colorNavigationController(navigationController, backgroundColor: NCBrandColor.shared.systemBackground, titleColor: NCBrandColor.shared.label, tintColor: nil, withoutShadow: false) view.backgroundColor = NCBrandColor.shared.systemBackground textColor = NCBrandColor.shared.label - + } else { - + navigationController?.setNavigationBarHidden(true, animated: true) progressView.isHidden = true - + currentViewController.playerToolBar.hide() view.backgroundColor = .black textColor = .white } - + currentScreenMode = mode - + if currentViewController.metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue { saveScreenModeImage = mode } - + setNeedsStatusBarAppearanceUpdate() currentViewController.reloadDetail() } - - //MARK: - NotificationCenter + + // MARK: - NotificationCenter @objc func downloadedFile(_ notification: NSNotification) { - + progressView.progress = 0 } - + @objc func triggerProgressTask(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let progressNumber = userInfo["progress"] as? NSNumber { let progress = progressNumber.floatValue @@ -224,28 +224,28 @@ class NCViewerMediaPage: UIViewController { } } } - + @objc func deleteFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String { - + let metadatas = self.metadatas.filter { $0.ocId != ocId } if self.metadatas.count == metadatas.count { return } self.metadatas = metadatas - + if ocId == currentViewController.metadata.ocId { shiftCurrentPage() } } } } - + @objc func renameFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - + if let index = metadatas.firstIndex(where: {$0.ocId == metadata.ocId}) { metadatas[index] = metadata if index == currentIndex { @@ -257,50 +257,55 @@ class NCViewerMediaPage: UIViewController { } } } - + @objc func moveFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - + if metadatas.firstIndex(where: {$0.ocId == metadata.ocId}) != nil { deleteFile(notification) } } } } - + @objc func changeTheming() { } - + @objc func hidePlayerToolBar(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String { if currentViewController.metadata.ocId == ocId { changeScreenMode(mode: .full) } } } - + @objc func showPlayerToolBar(_ notification: NSNotification) { - - if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let enableTimerAutoHide = userInfo["enableTimerAutoHide"] as? Bool{ + + if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let enableTimerAutoHide = userInfo["enableTimerAutoHide"] as? Bool { if currentViewController.metadata.ocId == ocId, let playerToolBar = currentViewController.playerToolBar, !playerToolBar.isPictureInPictureActive() { changeScreenMode(mode: .normal, enableTimerAutoHide: enableTimerAutoHide) } } } - @objc func applicationDidBecomeActive(_ notification: NSNotification) { + @objc func reloadMediaPage(_ notification: NSNotification) { - progressView.progress = 0 + self.reloadCurrentPage() } + @objc func applicationDidBecomeActive(_ notification: NSNotification) { + + progressView.progress = 0 + } + // MARK: - Command Center func updateCommandCenter(ncplayer: NCPlayer, metadata: tableMetadata) { - var nowPlayingInfo = [String : Any]() + var nowPlayingInfo = [String: Any]() // Clear clearCommandCenter() @@ -308,46 +313,46 @@ class NCViewerMediaPage: UIViewController { // Add handler for Play Command MPRemoteCommandCenter.shared().playCommand.isEnabled = true - playCommand = MPRemoteCommandCenter.shared().playCommand.addTarget { event in - + playCommand = MPRemoteCommandCenter.shared().playCommand.addTarget { _ in + if !ncplayer.isPlay() { ncplayer.playerPlay() return .success } return .commandFailed } - + // Add handler for Pause Command MPRemoteCommandCenter.shared().pauseCommand.isEnabled = true - pauseCommand = MPRemoteCommandCenter.shared().pauseCommand.addTarget { event in - + pauseCommand = MPRemoteCommandCenter.shared().pauseCommand.addTarget { _ in + if ncplayer.isPlay() { ncplayer.playerPause() return .success } return .commandFailed } - + // VIDEO / AUDIO () () if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue { - + MPRemoteCommandCenter.shared().skipForwardCommand.isEnabled = true skipForwardCommand = MPRemoteCommandCenter.shared().skipForwardCommand.addTarget { event in - + let seconds = Float64((event as! MPSkipIntervalCommandEvent).interval) self.currentViewController.playerToolBar.skip(seconds: seconds) return.success } - + MPRemoteCommandCenter.shared().skipBackwardCommand.isEnabled = true skipBackwardCommand = MPRemoteCommandCenter.shared().skipBackwardCommand.addTarget { event in - + let seconds = Float64((event as! MPSkipIntervalCommandEvent).interval) self.currentViewController.playerToolBar.skip(seconds: -seconds) return.success } } - + // AUDIO < > /* if metadata?.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue { @@ -367,11 +372,11 @@ class NCViewerMediaPage: UIViewController { } } */ - + nowPlayingInfo[MPMediaItemPropertyTitle] = metadata.fileNameView nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = ncplayer.durationTime.seconds if let image = currentViewController.image { - nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size) { size in + nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size) { _ in return image } } @@ -379,7 +384,7 @@ class NCViewerMediaPage: UIViewController { } func clearCommandCenter() { - + UIApplication.shared.endReceivingRemoteControlEvents() MPNowPlayingInfoCenter.default().nowPlayingInfo = [:] @@ -420,163 +425,171 @@ class NCViewerMediaPage: UIViewController { // MARK: - UIPageViewController Delegate Datasource extension NCViewerMediaPage: UIPageViewControllerDelegate, UIPageViewControllerDataSource { - + func shiftCurrentPage() { - + if metadatas.count == 0 { self.viewUnload() return } - + var direction: UIPageViewController.NavigationDirection = .forward - + if currentIndex == metadatas.count { currentIndex -= 1 direction = .reverse } - + currentViewController.ncplayer?.deactivateObserver() - let viewerMedia = getViewerMedia(index: currentIndex, metadata: metadatas[currentIndex], direction: direction) + let viewerMedia = getViewerMedia(index: currentIndex, metadata: metadatas[currentIndex]) pageViewController.setViewControllers([viewerMedia], direction: direction, animated: true, completion: nil) } - func goTo(index: Int, direction: UIPageViewController.NavigationDirection, autoPlay: Bool) { + func reloadCurrentPage() { - currentIndex = index + currentViewController.ncplayer?.deactivateObserver() + let viewerMedia = getViewerMedia(index: currentIndex, metadata: metadatas[currentIndex]) + viewerMedia.autoPlay = false + pageViewController.setViewControllers([viewerMedia], direction: .forward, animated: false, completion: nil) + } + + func goTo(index: Int, direction: UIPageViewController.NavigationDirection, autoPlay: Bool) { + + currentIndex = index + currentViewController.ncplayer?.deactivateObserver() - let viewerMedia = getViewerMedia(index: currentIndex, metadata: metadatas[currentIndex], direction: direction) + let viewerMedia = getViewerMedia(index: currentIndex, metadata: metadatas[currentIndex]) viewerMedia.autoPlay = autoPlay pageViewController.setViewControllers([viewerMedia], direction: direction, animated: true, completion: nil) } - + func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { - + if currentIndex == 0 { return nil } - let viewerMedia = getViewerMedia(index: currentIndex-1, metadata: metadatas[currentIndex-1], direction: .reverse) + let viewerMedia = getViewerMedia(index: currentIndex-1, metadata: metadatas[currentIndex-1]) return viewerMedia } - + func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { - + if currentIndex == metadatas.count-1 { return nil } - let viewerMedia = getViewerMedia(index: currentIndex+1, metadata: metadatas[currentIndex+1], direction: .forward) + let viewerMedia = getViewerMedia(index: currentIndex+1, metadata: metadatas[currentIndex+1]) return viewerMedia } - + // START TRANSITION func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) { - + // Save time video if let ncplayer = currentViewController.ncplayer, ncplayer.isPlay() { ncplayer.saveCurrentTime() } - + guard let nextViewController = pendingViewControllers.first as? NCViewerMedia else { return } - nextIndex = nextViewController.index + nextIndex = nextViewController.index } - + // END TRANSITION func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { - - if (completed && nextIndex != nil) { + + if completed && nextIndex != nil { previousViewControllers.forEach { viewController in let viewerMedia = viewController as! NCViewerMedia viewerMedia.ncplayer?.deactivateObserver() } currentIndex = nextIndex! } - + self.nextIndex = nil } } -//MARK: - UIGestureRecognizerDelegate +// MARK: - UIGestureRecognizerDelegate extension NCViewerMediaPage: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { - + if let gestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer { let velocity = gestureRecognizer.velocity(in: self.view) - - var velocityCheck : Bool = false - + + var velocityCheck: Bool = false + if UIDevice.current.orientation.isLandscape { velocityCheck = velocity.x < 0 - } - else { + } else { velocityCheck = velocity.y < 0 } if velocityCheck { return false } } - + return true } - + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { - + if otherGestureRecognizer == currentViewController.scrollView.panGestureRecognizer { if self.currentViewController.scrollView.contentOffset.y == 0 { return true } } - + return false } @objc func didPanWith(gestureRecognizer: UIPanGestureRecognizer) { - + currentViewController.didPanWith(gestureRecognizer: gestureRecognizer) } - + @objc func didSingleTapWith(gestureRecognizer: UITapGestureRecognizer) { - + if let playerToolBar = currentViewController.playerToolBar, playerToolBar.isPictureInPictureActive() { playerToolBar.pictureInPictureController?.stopPictureInPicture() } - + if currentScreenMode == .full { - + changeScreenMode(mode: .normal, enableTimerAutoHide: true) - + } else { - + changeScreenMode(mode: .full) } } - + // // LIVE PHOTO // @objc func didLongpressGestureEvent(gestureRecognizer: UITapGestureRecognizer) { - + if !currentViewController.metadata.livePhoto { return } - + if gestureRecognizer.state == .began { - + currentViewController.updateViewConstraints() currentViewController.statusViewImage.isHidden = true currentViewController.statusLabel.isHidden = true - + let fileName = (currentViewController.metadata.fileNameView as NSString).deletingPathExtension + ".mov" if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView LIKE[c] %@", currentViewController.metadata.account, currentViewController.metadata.serverUrl, fileName)), CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { - + AudioServicesPlaySystemSound(1519) // peek feedback - + if let url = NCKTVHTTPCache.shared.getVideoURL(metadata: metadata) { - self.ncplayerLivePhoto = NCPlayer.init(url: url, autoPlay: true, imageVideoContainer: self.currentViewController.imageVideoContainer, playerToolBar: nil, metadata: metadata, detailView: nil) + self.ncplayerLivePhoto = NCPlayer.init(url: url, autoPlay: true, imageVideoContainer: self.currentViewController.imageVideoContainer, playerToolBar: nil, metadata: metadata, detailView: nil, viewController: self) } } - + } else if gestureRecognizer.state == .ended { - + currentViewController.statusViewImage.isHidden = false currentViewController.statusLabel.isHidden = false currentViewController.imageVideoContainer.image = currentViewController.image diff --git a/iOSClient/Viewer/NCViewerNextcloudText/NCViewerNextcloudText.swift b/iOSClient/Viewer/NCViewerNextcloudText/NCViewerNextcloudText.swift index 64e6a0509..a567e3ed2 100644 --- a/iOSClient/Viewer/NCViewerNextcloudText/NCViewerNextcloudText.swift +++ b/iOSClient/Viewer/NCViewerNextcloudText/NCViewerNextcloudText.swift @@ -25,187 +25,187 @@ import UIKit import WebKit class NCViewerNextcloudText: UIViewController, WKNavigationDelegate, WKScriptMessageHandler { - + let appDelegate = UIApplication.shared.delegate as! AppDelegate var webView = WKWebView() - var bottomConstraint : NSLayoutConstraint? + var bottomConstraint: NSLayoutConstraint? var link: String = "" var editor: String = "" var metadata: tableMetadata = tableMetadata() var imageIcon: UIImage? - + // MARK: - View Life Cycle required init?(coder: NSCoder) { super.init(coder: coder) } - + override func viewDidLoad() { super.viewDidLoad() - - navigationItem.rightBarButtonItem = UIBarButtonItem.init(image: UIImage(named: "more")!.image(color: NCBrandColor.shared.label, size: 25), style: .plain, target: self, action: #selector(self.openMenuMore)) - + + navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "more")!.image(color: NCBrandColor.shared.label, size: 25), style: .plain, target: self, action: #selector(self.openMenuMore)) + navigationController?.navigationBar.prefersLargeTitles = false navigationItem.title = metadata.fileNameView - + let config = WKWebViewConfiguration() config.websiteDataStore = WKWebsiteDataStore.nonPersistent() let contentController = config.userContentController contentController.add(self, name: "DirectEditingMobileInterface") - + webView = WKWebView(frame: CGRect.zero, configuration: config) webView.navigationDelegate = self view.addSubview(webView) - + webView.translatesAutoresizingMaskIntoConstraints = false webView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true webView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true webView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true bottomConstraint = webView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0) bottomConstraint?.isActive = true - + var request = URLRequest(url: URL(string: link)!) request.addValue("true", forHTTPHeaderField: "OCS-APIRequest") let language = NSLocale.preferredLanguages[0] as String request.addValue(language, forHTTPHeaderField: "Accept-Language") - + if editor == NCGlobal.shared.editorOnlyoffice { webView.customUserAgent = NCUtility.shared.getCustomUserAgentOnlyOffice() } else { webView.customUserAgent = CCUtility.getUserAgent() } - + webView.load(request) } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + appDelegate.activeViewController = self - + // NotificationCenter.default.addObserver(self, selector: #selector(favoriteFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterFavoriteFile), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(viewUnload), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMenuDetailClose), object: nil) - + NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: UIResponder.keyboardDidShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) } - + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - + if let navigationController = self.navigationController { if !navigationController.viewControllers.contains(self) { } } - + // NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterFavoriteFile), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMenuDetailClose), object: nil) - + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardDidShowNotification, object: nil) NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) } - + @objc func viewUnload() { - + navigationController?.popViewController(animated: true) } - - //MARK: - NotificationCenter - + + // MARK: - NotificationCenter + @objc func favoriteFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - + if metadata.ocId == self.metadata.ocId { self.metadata = metadata } } } } - + @objc func keyboardDidShow(notification: Notification) { - + guard let info = notification.userInfo else { return } guard let frameInfo = info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return } let keyboardFrame = frameInfo.cgRectValue let height = keyboardFrame.size.height bottomConstraint?.constant = -height } - + @objc func keyboardWillHide(notification: Notification) { - + bottomConstraint?.constant = 0 } - - //MARK: - Action - + + // MARK: - Action + @objc func openMenuMore() { - if imageIcon == nil { imageIcon = UIImage.init(named: "file_txt") } + if imageIcon == nil { imageIcon = UIImage(named: "file_txt") } NCViewer.shared.toggleMenu(viewController: self, metadata: metadata, webView: true, imageIcon: imageIcon) } - - //MARK: - + + // MARK: - public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - - if (message.name == "DirectEditingMobileInterface") { - + + if message.name == "DirectEditingMobileInterface" { + if message.body as? String == "close" { viewUnload() } - + if message.body as? String == "share" { - NCFunctionCenter.shared.openShare(ViewController: self, metadata: metadata, indexPage: .sharing) + NCFunctionCenter.shared.openShare(viewController: self, metadata: metadata, indexPage: .sharing) } - + if message.body as? String == "loading" { print("loading") } - + if message.body as? String == "loaded" { print("loaded") } - + if message.body as? String == "paste" { self.paste(self) } } } - - //MARK: - + + // MARK: - public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if let serverTrust = challenge.protectionSpace.serverTrust { completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust)) } else { - completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil); + completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil) } } - + public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - print("didStartProvisionalNavigation"); + print("didStartProvisionalNavigation") } - + public func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { - print("didReceiveServerRedirectForProvisionalNavigation"); + print("didReceiveServerRedirectForProvisionalNavigation") } - + public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { NCUtility.shared.stopActivityIndicator() } } -extension NCViewerNextcloudText : UINavigationControllerDelegate { +extension NCViewerNextcloudText: UINavigationControllerDelegate { override func didMove(toParent parent: UIViewController?) { super.didMove(toParent: parent) - + if parent == nil { - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced, userInfo: ["serverUrl":self.metadata.serverUrl]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced, userInfo: ["serverUrl": self.metadata.serverUrl]) } } } diff --git a/iOSClient/Viewer/NCViewerPDF/NCViewerPDF.swift b/iOSClient/Viewer/NCViewerPDF/NCViewerPDF.swift index 2f7f1bdc5..c0884fa77 100644 --- a/iOSClient/Viewer/NCViewerPDF/NCViewerPDF.swift +++ b/iOSClient/Viewer/NCViewerPDF/NCViewerPDF.swift @@ -25,18 +25,18 @@ import UIKit import PDFKit class NCViewerPDF: UIViewController, NCViewerPDFSearchDelegate { - + let appDelegate = UIApplication.shared.delegate as! AppDelegate var metadata = tableMetadata() var imageIcon: UIImage? - + private var pdfView = PDFView() private var thumbnailViewHeight: CGFloat = 40 private var pdfThumbnailView = PDFThumbnailView() private var pdfDocument: PDFDocument? private let pageView = UIView() private let pageViewLabel = UILabel() - private var pageViewWidthAnchor : NSLayoutConstraint? + private var pageViewWidthAnchor: NSLayoutConstraint? private var filePath = "" // MARK: - View Life Cycle @@ -44,14 +44,14 @@ class NCViewerPDF: UIViewController, NCViewerPDFSearchDelegate { required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } - + override func viewDidLoad() { - + filePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! - pdfView = PDFView.init(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)) + pdfView = PDFView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)) pdfDocument = PDFDocument(url: URL(fileURLWithPath: filePath)) - + pdfView.document = pdfDocument pdfView.backgroundColor = NCBrandColor.shared.systemBackground pdfView.displayMode = .singlePageContinuous @@ -59,61 +59,61 @@ class NCViewerPDF: UIViewController, NCViewerPDFSearchDelegate { pdfView.displayDirection = CCUtility.getPDFDisplayDirection() pdfView.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleTopMargin, .flexibleBottomMargin] pdfView.usePageViewController(true, withViewOptions: nil) - + view.addSubview(pdfView) - + pdfThumbnailView.translatesAutoresizingMaskIntoConstraints = false pdfThumbnailView.pdfView = pdfView pdfThumbnailView.layoutMode = .horizontal pdfThumbnailView.thumbnailSize = CGSize(width: 40, height: thumbnailViewHeight) pdfThumbnailView.backgroundColor = .clear - //pdfThumbnailView.layer.shadowOffset.height = -5 - //pdfThumbnailView.layer.shadowOpacity = 0.25 - + // pdfThumbnailView.layer.shadowOffset.height = -5 + // pdfThumbnailView.layer.shadowOpacity = 0.25 + view.addSubview(pdfThumbnailView) - + pdfThumbnailView.heightAnchor.constraint(equalToConstant: thumbnailViewHeight).isActive = true pdfThumbnailView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true pdfThumbnailView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true pdfThumbnailView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true - + pageView.translatesAutoresizingMaskIntoConstraints = false pageView.layer.cornerRadius = 10 pageView.backgroundColor = UIColor.gray.withAlphaComponent(0.3) - + view.addSubview(pageView) - + pageView.heightAnchor.constraint(equalToConstant: 30).isActive = true pageViewWidthAnchor = pageView.widthAnchor.constraint(equalToConstant: 10) pageViewWidthAnchor?.isActive = true pageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 4).isActive = true pageView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 7).isActive = true - + pageViewLabel.translatesAutoresizingMaskIntoConstraints = false pageViewLabel.textAlignment = .center pageViewLabel.textColor = .gray - + pageView.addSubview(pageViewLabel) - + pageViewLabel.leftAnchor.constraint(equalTo: pageView.leftAnchor).isActive = true pageViewLabel.rightAnchor.constraint(equalTo: pageView.rightAnchor).isActive = true pageViewLabel.topAnchor.constraint(equalTo: pageView.topAnchor).isActive = true pageViewLabel.bottomAnchor.constraint(equalTo: pageView.bottomAnchor).isActive = true - + pdfView.backgroundColor = NCBrandColor.shared.systemBackground pdfView.layoutIfNeeded() handlePageChange() - + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap(_:))) tapGesture.numberOfTapsRequired = 1 pdfView.addGestureRecognizer(tapGesture) - + // recognize single / double tap for gesture in pdfView.gestureRecognizers! { - tapGesture.require(toFail:gesture) + tapGesture.require(toFail: gesture) } } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) @@ -131,17 +131,17 @@ class NCViewerPDF: UIViewController, NCViewerPDFSearchDelegate { NotificationCenter.default.addObserver(self, selector: #selector(direction(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMenuPDFDisplayDirection), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(goToPage), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMenuGotToPageInPDF), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handlePageChange), name: Notification.Name.PDFViewPageChanged, object: nil) - + // - navigationItem.rightBarButtonItem = UIBarButtonItem.init(image: UIImage(named: "more")!.image(color: NCBrandColor.shared.label, size: 25), style: .plain, target: self, action: #selector(self.openMenuMore)) - + navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "more")!.image(color: NCBrandColor.shared.label, size: 25), style: .plain, target: self, action: #selector(self.openMenuMore)) + navigationController?.navigationBar.prefersLargeTitles = true navigationItem.title = metadata.fileNameView } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterFavoriteFile), 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.notificationCenterRenameFile), object: nil) @@ -155,16 +155,16 @@ class NCViewerPDF: UIViewController, NCViewerPDFSearchDelegate { NotificationCenter.default.removeObserver(self, name: Notification.Name.PDFViewPageChanged, object: nil) } - + @objc func viewUnload() { - + navigationController?.popViewController(animated: true) } - - //MARK: - NotificationCenter - + + // MARK: - NotificationCenter + @objc func uploadedFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId), let errorCode = userInfo["errorCode"] as? Int { if errorCode == 0 && metadata.ocId == self.metadata.ocId { @@ -175,33 +175,33 @@ class NCViewerPDF: UIViewController, NCViewerPDFSearchDelegate { } } } - + @objc func favoriteFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - + if metadata.ocId == self.metadata.ocId { self.metadata = metadata } } } } - + @objc func moveFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let ocIdNew = userInfo["ocIdNew"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId), let metadataNew = NCManageDatabase.shared.getMetadataFromOcId(ocIdNew) { - + if metadata.ocId == self.metadata.ocId { self.metadata = metadataNew } } } } - + @objc func deleteFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["OcId"] as? String { if ocId == self.metadata.ocId { @@ -210,12 +210,12 @@ class NCViewerPDF: UIViewController, NCViewerPDFSearchDelegate { } } } - + @objc func renameFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - + if metadata.ocId == self.metadata.ocId { self.metadata = metadata navigationItem.title = metadata.fileNameView @@ -225,17 +225,17 @@ class NCViewerPDF: UIViewController, NCViewerPDFSearchDelegate { } @objc func searchText() { - - let viewerPDFSearch = UIStoryboard.init(name: "NCViewerPDF", bundle: nil).instantiateViewController(withIdentifier: "NCViewerPDFSearch") as! NCViewerPDFSearch + + let viewerPDFSearch = UIStoryboard(name: "NCViewerPDF", bundle: nil).instantiateViewController(withIdentifier: "NCViewerPDFSearch") as! NCViewerPDFSearch viewerPDFSearch.delegate = self viewerPDFSearch.pdfDocument = pdfDocument - - let navigaionController = UINavigationController.init(rootViewController: viewerPDFSearch) + + let navigaionController = UINavigationController(rootViewController: viewerPDFSearch) self.present(navigaionController, animated: true) } - + @objc func direction(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let direction = userInfo["direction"] as? PDFDisplayDirection { pdfView.displayDirection = direction @@ -244,7 +244,7 @@ class NCViewerPDF: UIViewController, NCViewerPDFSearchDelegate { } } } - + @objc func goToPage() { guard let pdfDocument = pdfView.document else { return } @@ -267,28 +267,28 @@ class NCViewerPDF: UIViewController, NCViewerPDFSearchDelegate { self.present(alertController, animated: true) } - //MARK: - Action - + // MARK: - Action + @objc func openMenuMore() { - if imageIcon == nil { imageIcon = UIImage.init(named: "file_pdf") } + if imageIcon == nil { imageIcon = UIImage(named: "file_pdf") } NCViewer.shared.toggleMenu(viewController: self, metadata: metadata, webView: false, imageIcon: imageIcon) } - - //MARK: - Gesture Recognizer - + + // MARK: - Gesture Recognizer + @objc func didTap(_ recognizer: UITapGestureRecognizer) { - + if navigationController?.isNavigationBarHidden ?? false { - + navigationController?.setNavigationBarHidden(false, animated: false) pdfThumbnailView.isHidden = false pdfView.backgroundColor = NCBrandColor.shared.systemBackground } else { - + let point = recognizer.location(in: pdfView) if point.y > pdfView.frame.height - thumbnailViewHeight { return } - + navigationController?.setNavigationBarHidden(true, animated: false) pdfThumbnailView.isHidden = true pdfView.backgroundColor = .black @@ -296,32 +296,32 @@ class NCViewerPDF: UIViewController, NCViewerPDFSearchDelegate { handlePageChange() } - - //MARK: - - + + // MARK: - + @objc func handlePageChange() { - + guard let curPage = pdfView.currentPage?.pageRef?.pageNumber else { pageView.alpha = 0; return } guard let totalPages = pdfView.document?.pageCount else { return } - + pageView.alpha = 1 pageViewLabel.text = String(curPage) + " " + NSLocalizedString("_of_", comment: "") + " " + String(totalPages) pageViewWidthAnchor?.constant = pageViewLabel.intrinsicContentSize.width + 10 - + UIView.animate(withDuration: 1.0, delay: 3.0, animations: { self.pageView.alpha = 0 }) } - + func searchPdfSelection(_ pdfSelection: PDFSelection) { - + pdfSelection.color = .yellow pdfView.currentSelection = pdfSelection pdfView.go(to: pdfSelection) } - - private func selectPage(with label:String) { - + + private func selectPage(with label: String) { + guard let pdf = pdfView.document else { return } if let pageNr = Int(label) { diff --git a/iOSClient/Viewer/NCViewerPDF/NCViewerPDFSearch.swift b/iOSClient/Viewer/NCViewerPDF/NCViewerPDFSearch.swift index 857ab9c8b..d86c840c9 100644 --- a/iOSClient/Viewer/NCViewerPDF/NCViewerPDFSearch.swift +++ b/iOSClient/Viewer/NCViewerPDF/NCViewerPDFSearch.swift @@ -24,137 +24,137 @@ import UIKit import PDFKit -@objc protocol NCViewerPDFSearchDelegate : AnyObject { +@objc protocol NCViewerPDFSearchDelegate: AnyObject { func searchPdfSelection(_ pdfSelection: PDFSelection) } class NCViewerPDFSearch: UITableViewController, UISearchBarDelegate, PDFDocumentDelegate { - + var searchBar = UISearchBar() var pdfDocument: PDFDocument? var searchResultArray: [PDFSelection] = [] - + weak var delegate: NCViewerPDFSearchDelegate? - + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - + searchBar.delegate = self searchBar.sizeToFit() searchBar.searchBarStyle = .minimal - + navigationItem.titleView = searchBar - + tableView.dataSource = self tableView.delegate = self - tableView.register(UINib.init(nibName: "NCViewerPDFSearchCell", bundle: nil), forCellReuseIdentifier: "Cell") + tableView.register(UINib(nibName: "NCViewerPDFSearchCell", bundle: nil), forCellReuseIdentifier: "Cell") } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) searchBar.becomeFirstResponder() } - - //MARK: - UITableView DataSource / Delegate - + + // MARK: - UITableView DataSource / Delegate + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 82 } - + override func numberOfSections(in tableView: UITableView) -> Int { return 1 } - + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.searchResultArray.count } - + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! NCViewerPDFSearchCell let pdfSelection = searchResultArray[indexPath.row] as PDFSelection - - //if let pdfOutline = pdfDocument?.outlineItem(for: pdfSelection) { + + // if let pdfOutline = pdfDocument?.outlineItem(for: pdfSelection) { // cell.outlineLabel.text = pdfOutline.label - //} - + // } + let pdfPage = pdfSelection.pages.first cell.pageNumberLabel.text = NSLocalizedString("_scan_document_pdf_page_", comment: "") + ": " + (pdfPage?.label ?? "") - + let extendSelection = pdfSelection.copy() as! PDFSelection extendSelection.extend(atStart: 10) extendSelection.extend(atEnd: 90) extendSelection.extendForLineBoundaries() - + let nsRange = NSString(string: extendSelection.string!).range(of: pdfSelection.string!, options: String.CompareOptions.caseInsensitive) if nsRange.location != NSNotFound { - let attributedSubString = NSAttributedString.init(string: NSString(string: extendSelection.string!).substring(with: nsRange), attributes: [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 17)]) - let attributedString = NSMutableAttributedString.init(string: extendSelection.string!) + let attributedSubString = NSAttributedString(string: NSString(string: extendSelection.string!).substring(with: nsRange), attributes: [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 17)]) + let attributedString = NSMutableAttributedString(string: extendSelection.string!) attributedString.replaceCharacters(in: nsRange, with: attributedSubString) cell.searchResultTextLabel.attributedText = attributedString } - + return cell } - + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - + let pdfSelection = searchResultArray[indexPath.row] delegate?.searchPdfSelection(pdfSelection) dismiss(animated: true) } - - //MARK: - PDFSelection Delegate - + + // MARK: - PDFSelection Delegate + func didMatchString(_ instance: PDFSelection) { searchResultArray.append(instance) tableView.reloadData() } - - //MARK: - UIScrollView Delegate - + + // MARK: - UIScrollView Delegate + override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { searchBar.resignFirstResponder() } - - //MARK: - UISearchBarDelegate - + + // MARK: - UISearchBarDelegate + func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { searchBar.resignFirstResponder() } - + func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { pdfDocument?.cancelFindString() navigationItem.setRightBarButton(nil, animated: false) dismiss(animated: true) } - + func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { if searchText.count < 2 { return } - + searchResultArray.removeAll() tableView.reloadData() pdfDocument?.cancelFindString() pdfDocument?.delegate = self pdfDocument?.beginFindString(searchText, withOptions: .caseInsensitive) } - + func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool { - - let cancelBarButtonItem = UIBarButtonItem.init(title: NSLocalizedString("_cancel_", comment: ""), style: .plain, target: self, action: #selector(cancelBarButtonItemClicked)) + + let cancelBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: .plain, target: self, action: #selector(cancelBarButtonItemClicked)) navigationItem.setRightBarButton(cancelBarButtonItem, animated: true) return true } - + @objc func cancelBarButtonItemClicked() { searchBarCancelButtonClicked(searchBar) } } class NCViewerPDFSearchCell: UITableViewCell { - + @IBOutlet weak var outlineLabel: UILabel! @IBOutlet weak var pageNumberLabel: UILabel! @IBOutlet weak var searchResultTextLabel: UILabel! @@ -163,4 +163,3 @@ class NCViewerPDFSearchCell: UITableViewCell { super.awakeFromNib() } } - diff --git a/iOSClient/Viewer/NCViewerProviderContextMenu.swift b/iOSClient/Viewer/NCViewerProviderContextMenu.swift index c032c505f..58965dd99 100644 --- a/iOSClient/Viewer/NCViewerProviderContextMenu.swift +++ b/iOSClient/Viewer/NCViewerProviderContextMenu.swift @@ -26,7 +26,7 @@ import AVFoundation import NCCommunication import SVGKit -class NCViewerProviderContextMenu: UIViewController { +class NCViewerProviderContextMenu: UIViewController { private let imageView = UIImageView() private var videoLayer: AVPlayerLayer? @@ -34,100 +34,100 @@ class NCViewerProviderContextMenu: UIViewController { private var metadata: tableMetadata? private var metadataLivePhoto: tableMetadata? private var image: UIImage? - + private let sizeIcon: CGFloat = 150 - + // MARK: - View Life Cycle required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + init(metadata: tableMetadata, image: UIImage?) { super.init(nibName: nil, bundle: nil) - + self.metadata = metadata self.metadataLivePhoto = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) self.image = image - + if metadata.directory { - + var imageFolder = UIImage(named: "folder")!.image(color: NCBrandColor.shared.brandElement, size: sizeIcon*2) - + if let image = self.image { imageFolder = image.image(color: NCBrandColor.shared.brandElement, size: sizeIcon*2) } - + imageView.image = imageFolder imageView.frame = resize(CGSize(width: sizeIcon, height: sizeIcon)) } else { - + // ICON - if let image = UIImage.init(named: metadata.iconName)?.resizeImage(size: CGSize(width: sizeIcon*2, height: sizeIcon*2), isAspectRation: true) { - + if let image = UIImage(named: metadata.iconName)?.resizeImage(size: CGSize(width: sizeIcon*2, height: sizeIcon*2), isAspectRation: true) { + imageView.image = image imageView.frame = resize(CGSize(width: sizeIcon, height: sizeIcon)) } - + // PREVIEW if CCUtility.fileProviderStoragePreviewIconExists(metadata.ocId, etag: metadata.etag) { - - if let image = UIImage.init(contentsOfFile: CCUtility.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)) { + + if let image = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)) { imageView.image = image imageView.frame = resize(image.size) } } - + // VIEW IMAGE if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue && CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { - + viewImage(metadata: metadata) } // VIEW LIVE PHOTO if metadataLivePhoto != nil && CCUtility.fileProviderStorageExists(metadataLivePhoto!.ocId, fileNameView: metadataLivePhoto!.fileNameView) { - + viewVideo(metadata: metadataLivePhoto!) } - + // VIEW VIDEO if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue && CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { viewVideo(metadata: metadata) } - + // PLAY SOUND if metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue && CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) { playSound(metadata: metadata) } - + // AUTO DOWNLOAD VIDEO / AUDIO // if !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) && (metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue || metadata.contentType == "application/pdf") { if !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) && (metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue || metadata.classFile == NCCommunicationCommon.typeClassFile.audio.rawValue) { - + var maxDownload: UInt64 = 0 - + if NCNetworking.shared.networkReachability == NCCommunicationCommon.typeReachability.reachableCellular { maxDownload = NCGlobal.shared.maxAutoDownloadCellular } else { maxDownload = NCGlobal.shared.maxAutoDownload } - + if metadata.size <= maxDownload { NCOperationQueue.shared.download(metadata: metadata, selector: "") } } - + // AUTO DOWNLOAD IMAGE GIF if !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) && metadata.contentType == "image/gif" { NCOperationQueue.shared.download(metadata: metadata, selector: "") } - + // AUTO DOWNLOAD IMAGE SVG if !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) && metadata.contentType == "image/svg+xml" { NCOperationQueue.shared.download(metadata: metadata, selector: "") } - + // AUTO DOWNLOAD LIVE PHOTO if let metadataLivePhoto = self.metadataLivePhoto { if !CCUtility.fileProviderStorageExists(metadataLivePhoto.ocId, fileNameView: metadataLivePhoto.fileNameView) { @@ -136,31 +136,31 @@ class NCViewerProviderContextMenu: UIViewController { } } } - + override func loadView() { view = imageView imageView.contentMode = .scaleAspectFill } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + NotificationCenter.default.addObserver(self, selector: #selector(downloadStartFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadStartFile), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(downloadedFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(downloadCancelFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadCancelFile), object: nil) } - + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - + 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) } - + override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() - + if let videoLayer = self.videoLayer { if videoLayer.frame == CGRect.zero { videoLayer.frame = imageView.frame @@ -170,11 +170,11 @@ class NCViewerProviderContextMenu: UIViewController { } preferredContentSize = imageView.frame.size } - + // MARK: - NotificationCenter @objc func downloadStartFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String { if ocId == self.metadata?.ocId || ocId == self.metadataLivePhoto?.ocId { @@ -183,9 +183,9 @@ class NCViewerProviderContextMenu: UIViewController { } } } - + @objc func downloadedFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId), let errorCode = userInfo["errorCode"] as? Int { if errorCode == 0 && metadata.ocId == self.metadata?.ocId { @@ -206,9 +206,9 @@ class NCViewerProviderContextMenu: UIViewController { } } } - + @objc func downloadCancelFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String { if ocId == self.metadata?.ocId || ocId == self.metadataLivePhoto?.ocId { @@ -217,15 +217,15 @@ class NCViewerProviderContextMenu: UIViewController { } } } - + // MARK: - Viewer - + private func viewImage(metadata: tableMetadata) { - + var image: UIImage? let filePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! - + if metadata.contentType == "image/gif" { image = UIImage.animatedImage(withAnimatedGIFURL: URL(fileURLWithPath: filePath)) } else if metadata.contentType == "image/svg+xml" { @@ -235,15 +235,15 @@ class NCViewerProviderContextMenu: UIViewController { image = svgImage.uiImage } } else { - image = UIImage.init(contentsOfFile: filePath) + image = UIImage(contentsOfFile: filePath) } imageView.image = image imageView.frame = resize(image?.size) } - + func playSound(metadata: tableMetadata) { - + let filePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! do { @@ -256,18 +256,18 @@ class NCViewerProviderContextMenu: UIViewController { } catch let error { print(error.localizedDescription) } - + preferredContentSize = imageView.frame.size } - + private func viewVideo(metadata: tableMetadata) { - + let filePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)! if let resolutionVideo = resolutionForLocalVideo(url: URL(fileURLWithPath: filePath)) { - + let player = AVPlayer(url: URL(fileURLWithPath: filePath)) - + self.videoLayer = AVPlayerLayer(player: player) if let videoLayer = self.videoLayer { videoLayer.videoGravity = .resizeAspectFill @@ -275,37 +275,37 @@ class NCViewerProviderContextMenu: UIViewController { imageView.frame = resize(resolutionVideo) imageView.layer.addSublayer(videoLayer) } - + player.isMuted = true player.play() } } - + private func resolutionForLocalVideo(url: URL) -> CGSize? { guard let track = AVURLAsset(url: url).tracks(withMediaType: AVMediaType.video).first else { return nil } let size = track.naturalSize.applying(track.preferredTransform) return CGSize(width: abs(size.width), height: abs(size.height)) } - + private func resize(_ size: CGSize?) -> CGRect { - + var frame = CGRect.zero - + guard let size = size else { preferredContentSize = frame.size return frame } - + if size.width <= UIScreen.main.bounds.width { frame = CGRect(x: 0, y: 0, width: size.width, height: size.height) preferredContentSize = frame.size return frame } - + let originRatio = size.width / size.height let newRatio = UIScreen.main.bounds.width / UIScreen.main.bounds.height var newSize = CGSize.zero - + if originRatio < newRatio { newSize.height = UIScreen.main.bounds.height newSize.width = UIScreen.main.bounds.height * originRatio @@ -313,7 +313,7 @@ class NCViewerProviderContextMenu: UIViewController { newSize.width = UIScreen.main.bounds.width newSize.height = UIScreen.main.bounds.width / originRatio } - + frame = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height) preferredContentSize = frame.size return frame diff --git a/iOSClient/Viewer/NCViewerQuickLook/NCViewerQuickLook.swift b/iOSClient/Viewer/NCViewerQuickLook/NCViewerQuickLook.swift index ddee6e1ac..7a96388d9 100644 --- a/iOSClient/Viewer/NCViewerQuickLook/NCViewerQuickLook.swift +++ b/iOSClient/Viewer/NCViewerQuickLook/NCViewerQuickLook.swift @@ -26,49 +26,49 @@ import QuickLook import NCCommunication @objc class NCViewerQuickLook: QLPreviewController { - + let appDelegate = UIApplication.shared.delegate as! AppDelegate var url: URL? var previewItems: [PreviewItem] = [] var editingMode: Bool - enum saveModeType{ + enum saveModeType { case overwrite case copy case discard } var saveMode: saveModeType = .discard var metadata: tableMetadata? - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + @objc init(with url: URL, editingMode: Bool, metadata: tableMetadata?) { - + self.url = url self.editingMode = editingMode if let metadata = metadata { self.metadata = tableMetadata.init(value: metadata) } - + let previewItem = PreviewItem() previewItem.previewItemURL = url self.previewItems.append(previewItem) super.init(nibName: nil, bundle: nil) - + self.dataSource = self self.delegate = self self.currentPreviewItemIndex = 0 self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissPreviewController)) } - + override func viewDidLoad() { super.viewDidLoad() - + if editingMode && metadata?.classFile == NCCommunicationCommon.typeClassFile.image.rawValue { - Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { (t) in + Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { t in if self.navigationItem.rightBarButtonItems?.count ?? 0 > 1 || !(self.navigationController?.isToolbarHidden ?? false) { if #available(iOS 14.0, *) { if self.navigationItem.rightBarButtonItems?.count ?? 0 > 1 { @@ -89,59 +89,59 @@ import NCCommunication } }) } - + if editingMode && metadata?.livePhoto == true { NCContentPresenter.shared.messageNotification("", description: "_message_disable_overwrite_livephoto_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode: NCGlobal.shared.errorCharactersForbidden) } } - + @objc func dismissPreviewController() { - + if editingMode { - + let alertController = UIAlertController(title: NSLocalizedString("_save_", comment: ""), message: "", preferredStyle: .alert) - + if metadata?.livePhoto == false { - alertController.addAction(UIAlertAction(title: NSLocalizedString("_overwrite_original_", comment: ""), style: .default) { (action:UIAlertAction) in + alertController.addAction(UIAlertAction(title: NSLocalizedString("_overwrite_original_", comment: ""), style: .default) { (_: UIAlertAction) in self.saveMode = .overwrite self.dismiss(animated: true) }) } - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_save_as_copy_", comment: ""), style: .default) { (action:UIAlertAction) in + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_save_as_copy_", comment: ""), style: .default) { (_: UIAlertAction) in self.saveMode = .copy self.dismiss(animated: true) }) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_discard_changes_", comment: ""), style: .destructive) { (action:UIAlertAction) in + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_discard_changes_", comment: ""), style: .destructive) { (_: UIAlertAction) in self.saveMode = .discard self.dismiss(animated: true) }) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { (action:UIAlertAction) in }) - + + alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { (_: UIAlertAction) in }) + self.present(alertController, animated: true) - + } else { - + self.dismiss(animated: true) } } } extension NCViewerQuickLook: QLPreviewControllerDataSource, QLPreviewControllerDelegate { - + func numberOfPreviewItems(in controller: QLPreviewController) -> Int { previewItems.count } - + func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem { previewItems[index] } - + func previewController(_ controller: QLPreviewController, didUpdateContentsOf previewItem: QLPreviewItem) { } - + @available(iOS 13.0, *) func previewController(_ controller: QLPreviewController, editingModeFor previewItem: QLPreviewItem) -> QLPreviewItemEditingMode { if editingMode { @@ -150,32 +150,32 @@ extension NCViewerQuickLook: QLPreviewControllerDataSource, QLPreviewControllerD return .disabled } } - + func previewController(_ controller: QLPreviewController, didSaveEditedCopyOf previewItem: QLPreviewItem, at modifiedContentsURL: URL) { - + if saveMode != .discard { - + guard let metadata = self.metadata else { return } let ocId = NSUUID().uuidString let size = NCUtilityFileSystem.shared.getFileSize(filePath: modifiedContentsURL.path) - + if saveMode == .copy { let fileName = NCUtilityFileSystem.shared.createFileName(metadata.fileNameView, serverUrl: metadata.serverUrl, account: metadata.account) metadata.fileName = fileName metadata.fileNameView = fileName - } - + } + let fileNamePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: metadata.fileNameView)! - + if NCUtilityFileSystem.shared.copyFile(atPath: modifiedContentsURL.path, toPath: fileNamePath) { - + let metadataForUpload = NCManageDatabase.shared.createMetadata(account: metadata.account, user: metadata.user, userId: metadata.userId, fileName: metadata.fileName, fileNameView: metadata.fileNameView, ocId: ocId, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, url: modifiedContentsURL.path, contentType: "", livePhoto: false) - + metadataForUpload.session = NCNetworking.shared.sessionIdentifierBackground metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile metadataForUpload.size = size metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload - + appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: [metadataForUpload]) } } diff --git a/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichdocument.swift b/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichdocument.swift index 597569db6..afd3e4519 100644 --- a/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichdocument.swift +++ b/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichdocument.swift @@ -26,51 +26,51 @@ import WebKit import NCCommunication class NCViewerRichdocument: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, NCSelectDelegate { - + let appDelegate = UIApplication.shared.delegate as! AppDelegate var webView = WKWebView() - var bottomConstraint : NSLayoutConstraint? + var bottomConstraint: NSLayoutConstraint? var documentController: UIDocumentInteractionController? - + var link: String = "" var metadata: tableMetadata = tableMetadata() var imageIcon: UIImage? - + // MARK: - View Life Cycle required init?(coder: NSCoder) { super.init(coder: coder) } - + override func viewDidLoad() { super.viewDidLoad() - + let config = WKWebViewConfiguration() config.websiteDataStore = WKWebsiteDataStore.nonPersistent() let contentController = config.userContentController contentController.add(self, name: "RichDocumentsMobileInterface") - + webView = WKWebView(frame: CGRect.zero, configuration: config) webView.navigationDelegate = self view.addSubview(webView) - + webView.translatesAutoresizingMaskIntoConstraints = false webView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true webView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true webView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true bottomConstraint = webView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0) bottomConstraint?.isActive = true - + var request = URLRequest(url: URL(string: link)!) request.addValue("true", forHTTPHeaderField: "OCS-APIRequest") let language = NSLocale.preferredLanguages[0] as String request.addValue(language, forHTTPHeaderField: "Accept-Language") - + webView.customUserAgent = CCUtility.getUserAgent() - + webView.load(request) } - + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) @@ -84,131 +84,131 @@ class NCViewerRichdocument: UIViewController, WKNavigationDelegate, WKScriptMess NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: UIResponder.keyboardDidShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) - + // - navigationItem.rightBarButtonItem = UIBarButtonItem.init(image: UIImage(named: "more")!.image(color: NCBrandColor.shared.label, size: 25), style: .plain, target: self, action: #selector(self.openMenuMore)) - + navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "more")!.image(color: NCBrandColor.shared.label, size: 25), style: .plain, target: self, action: #selector(self.openMenuMore)) + navigationItem.hidesBackButton = true navigationController?.navigationBar.prefersLargeTitles = false navigationItem.title = metadata.fileNameView } - + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if let navigationController = self.navigationController { if !navigationController.viewControllers.contains(self) { let functionJS = "OCA.RichDocuments.documentsMain.onClose()" - webView.evaluateJavaScript(functionJS) { (result, error) in + webView.evaluateJavaScript(functionJS) { _, _ in print("close") } } } - + // NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterFavoriteFile), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMenuDetailClose), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterRichdocumentGrabFocus), object: nil) - + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardDidShowNotification, object: nil) NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) } - + @objc func viewUnload() { - + navigationController?.popViewController(animated: true) } - - //MARK: - NotificationCenter - + + // MARK: - NotificationCenter + @objc func favoriteFile(_ notification: NSNotification) { - + if let userInfo = notification.userInfo as NSDictionary? { if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - + if metadata.ocId == self.metadata.ocId { self.metadata = metadata } } } } - + @objc func keyboardDidShow(notification: Notification) { - + guard let info = notification.userInfo else { return } guard let frameInfo = info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return } let keyboardFrame = frameInfo.cgRectValue let height = keyboardFrame.size.height bottomConstraint?.constant = -height } - + @objc func keyboardWillHide(notification: Notification) { - + bottomConstraint?.constant = 0 } - - //MARK: - Action - + + // MARK: - Action + @objc func openMenuMore() { - if imageIcon == nil { imageIcon = UIImage.init(named: "file_txt") } + if imageIcon == nil { imageIcon = UIImage(named: "file_txt") } NCViewer.shared.toggleMenu(viewController: self, metadata: metadata, webView: true, imageIcon: imageIcon) } - - //MARK: - + + // MARK: - public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - - if (message.name == "RichDocumentsMobileInterface") { - + + if message.name == "RichDocumentsMobileInterface" { + if message.body as? String == "close" { viewUnload() } - + if message.body as? String == "insertGraphic" { - + let storyboard = UIStoryboard(name: "NCSelect", bundle: nil) let navigationController = storyboard.instantiateInitialViewController() as! UINavigationController let viewController = navigationController.topViewController as! NCSelect - + viewController.delegate = self viewController.typeOfCommandView = .select viewController.enableSelectFile = true viewController.includeImages = true viewController.type = "" - + self.present(navigationController, animated: true, completion: nil) } - + if message.body as? String == "share" { - NCFunctionCenter.shared.openShare(ViewController: self, metadata: metadata, indexPage: .sharing) + NCFunctionCenter.shared.openShare(viewController: self, metadata: metadata, indexPage: .sharing) } - - if let param = message.body as? Dictionary<AnyHashable,Any> { - + + if let param = message.body as? [AnyHashable: Any] { + if param["MessageName"] as? String == "downloadAs" { - if let values = param["Values"] as? Dictionary<AnyHashable,Any> { + if let values = param["Values"] as? [AnyHashable: Any] { guard let type = values["Type"] as? String else { return } guard let urlString = values["URL"] as? String else { return } guard let url = URL(string: urlString) else { return } let fileNameLocalPath = CCUtility.getDirectoryUserData() + "/" + metadata.fileNameWithoutExt - + NCUtility.shared.startActivityIndicator(backgroundView: view, blurEffect: true) - - NCCommunication.shared.download(serverUrlFileName: url, fileNameLocalPath: fileNameLocalPath, requestHandler: { (_) in - - }, taskHandler: { (_) in - - }, progressHandler: { (_) in - - }, completionHandler: { (account, etag, date, lenght, allHeaderFields, error, errorCode, errorDescription) in - + + NCCommunication.shared.download(serverUrlFileName: url, fileNameLocalPath: fileNameLocalPath, requestHandler: { _ in + + }, taskHandler: { _ in + + }, progressHandler: { _ in + + }, completionHandler: { account, _, _, _, allHeaderFields, error, errorCode, errorDescription in + NCUtility.shared.stopActivityIndicator() - + if errorCode == 0 && account == self.metadata.account { - + var item = fileNameLocalPath - + if let allHeaderFields = allHeaderFields { if let disposition = allHeaderFields["Content-Disposition"] as? String { let components = disposition.components(separatedBy: "filename=") @@ -218,7 +218,7 @@ class NCViewerRichdocument: UIViewController, WKNavigationDelegate, WKScriptMess } } } - + if type == "print" { let pic = UIPrintInteractionController.shared let printInfo = UIPrintInfo.printInfo() @@ -227,20 +227,20 @@ class NCViewerRichdocument: UIViewController, WKNavigationDelegate, WKScriptMess printInfo.jobName = "Document" pic.printInfo = printInfo pic.printingItem = URL(fileURLWithPath: item) - pic.present(from: CGRect.zero, in: self.view, animated: true, completionHandler: { (pci, completed, error) in }) + pic.present(from: CGRect.zero, in: self.view, animated: true, completionHandler: { _, _, _ in }) } else { self.documentController = UIDocumentInteractionController() self.documentController?.url = URL(fileURLWithPath: item) self.documentController?.presentOptionsMenu(from: CGRect.zero, in: self.view, animated: true) } } else { - + NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode) } }) } } else if param["MessageName"] as? String == "fileRename" { - if let values = param["Values"] as? Dictionary<AnyHashable,Any> { + if let values = param["Values"] as? [AnyHashable: Any] { guard let newName = values["NewName"] as? String else { return } @@ -248,7 +248,7 @@ class NCViewerRichdocument: UIViewController, WKNavigationDelegate, WKScriptMess metadata.fileNameView = newName } } else if param["MessageName"] as? String == "hyperlink" { - if let values = param["Values"] as? Dictionary<AnyHashable,Any> { + if let values = param["Values"] as? [AnyHashable: Any] { guard let urlString = values["Url"] as? String else { return } @@ -258,37 +258,37 @@ class NCViewerRichdocument: UIViewController, WKNavigationDelegate, WKScriptMess } } } - + if message.body as? String == "documentLoaded" { print("documentLoaded") } - + if message.body as? String == "paste" { // ? } } } - - //MARK: - + + // MARK: - @objc func grabFocus() { - + let functionJS = "OCA.RichDocuments.documentsMain.postGrabFocus()" - webView.evaluateJavaScript(functionJS) { (result, error) in } + webView.evaluateJavaScript(functionJS) { _, _ in } } - - //MARK: - - + + // MARK: - + func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) { - + if serverUrl != nil && metadata != nil { - + let path = CCUtility.returnFileNamePath(fromFileName: metadata!.fileName, serverUrl: serverUrl!, urlBase: appDelegate.urlBase, account: metadata!.account)! - - NCCommunication.shared.createAssetRichdocuments(path: path) { (account, url, errorCode, errorDescription) in + + NCCommunication.shared.createAssetRichdocuments(path: path) { account, url, errorCode, errorDescription in if errorCode == 0 && account == self.appDelegate.account { let functionJS = "OCA.RichDocuments.documentsMain.postAsset('\(metadata!.fileNameView)', '\(url!)')" - self.webView.evaluateJavaScript(functionJS, completionHandler: { (result, error) in }) + self.webView.evaluateJavaScript(functionJS, completionHandler: { _, _ in }) } else if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError) } else { @@ -297,15 +297,15 @@ class NCViewerRichdocument: UIViewController, WKNavigationDelegate, WKScriptMess } } } - + func select(_ metadata: tableMetadata!, serverUrl: String!) { - + let path = CCUtility.returnFileNamePath(fromFileName: metadata!.fileName, serverUrl: serverUrl!, urlBase: appDelegate.urlBase, account: metadata!.account)! - - NCCommunication.shared.createAssetRichdocuments(path: path) { (account, url, errorCode, errorDescription) in + + NCCommunication.shared.createAssetRichdocuments(path: path) { account, url, errorCode, errorDescription in if errorCode == 0 && account == self.appDelegate.account { let functionJS = "OCA.RichDocuments.documentsMain.postAsset('\(metadata.fileNameView)', '\(url!)')" - self.webView.evaluateJavaScript(functionJS, completionHandler: { (result, error) in }) + self.webView.evaluateJavaScript(functionJS, completionHandler: { _, _ in }) } else if errorCode != 0 { NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError) } else { @@ -313,37 +313,37 @@ class NCViewerRichdocument: UIViewController, WKNavigationDelegate, WKScriptMess } } } - - //MARK: - + + // MARK: - public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if let serverTrust = challenge.protectionSpace.serverTrust { completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust)) } else { - completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil); + completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil) } } - + public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - print("didStartProvisionalNavigation"); + print("didStartProvisionalNavigation") } - + public func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { - print("didReceiveServerRedirectForProvisionalNavigation"); + print("didReceiveServerRedirectForProvisionalNavigation") } - + public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { NCUtility.shared.stopActivityIndicator() } } -extension NCViewerRichdocument : UINavigationControllerDelegate { +extension NCViewerRichdocument: UINavigationControllerDelegate { override func didMove(toParent parent: UIViewController?) { super.didMove(toParent: parent) - + if parent == nil { - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced, userInfo: ["serverUrl":self.metadata.serverUrl]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced, userInfo: ["serverUrl": self.metadata.serverUrl]) } } } |