diff --git a/Brand/File_Provider_Extension.entitlements b/Brand/File_Provider_Extension.entitlements index 4ecc3f0d13..0123881826 100755 --- a/Brand/File_Provider_Extension.entitlements +++ b/Brand/File_Provider_Extension.entitlements @@ -4,11 +4,19 @@ com.apple.security.application-groups - group.it.twsweb.Crypto-Cloud + group.de.magentacloud.next.dev2.client keychain-access-groups - $(AppIdentifierPrefix)it.twsweb.Crypto-Cloud + $(AppIdentifierPrefix)de.magentacloud.next.dev2.client + com.apple.security.application-groups + + group.com.t-systems.pu-ds.magentacloud.qa + + keychain-access-groups + + $(AppIdentifierPrefix)MagentaCLOUD + diff --git a/Brand/File_Provider_Extension.plist b/Brand/File_Provider_Extension.plist index 7179d95e3a..f824f92cb6 100755 --- a/Brand/File_Provider_Extension.plist +++ b/Brand/File_Provider_Extension.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - Nextcloud + MagentaCLOUD CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -27,13 +27,8 @@ NSExtension - NSExtensionAttributes - - NSFileProviderSupportsMultipleDomains - - NSExtensionFileProviderDocumentGroup - group.it.twsweb.Crypto-Cloud + group.de.telekom.Mediencenter NSExtensionFileProviderSupportsEnumeration NSExtensionFileProviderSupportsPickingFolders diff --git a/Brand/Notification_Service_Extension.entitlements b/Brand/Notification_Service_Extension.entitlements index 9cf2061f89..f0d4f751b3 100644 --- a/Brand/Notification_Service_Extension.entitlements +++ b/Brand/Notification_Service_Extension.entitlements @@ -6,13 +6,25 @@ com.apple.security.application-groups - group.it.twsweb.Crypto-Cloud + group.de.magentacloud.next.dev2.client com.apple.security.network.client keychain-access-groups - $(AppIdentifierPrefix)it.twsweb.Crypto-Cloud + $(AppIdentifierPrefix)de.magentacloud.next.dev2.client + com.apple.security.app-sandbox + + com.apple.security.application-groups + + group.com.t-systems.pu-ds.magentacloud.qa + + com.apple.security.network.client + + keychain-access-groups + + $(AppIdentifierPrefix)MagentaCLOUD + diff --git a/Brand/Share.entitlements b/Brand/Share.entitlements index 9cf2061f89..f0d4f751b3 100755 --- a/Brand/Share.entitlements +++ b/Brand/Share.entitlements @@ -6,13 +6,25 @@ com.apple.security.application-groups - group.it.twsweb.Crypto-Cloud + group.de.magentacloud.next.dev2.client com.apple.security.network.client keychain-access-groups - $(AppIdentifierPrefix)it.twsweb.Crypto-Cloud + $(AppIdentifierPrefix)de.magentacloud.next.dev2.client + com.apple.security.app-sandbox + + com.apple.security.application-groups + + group.com.t-systems.pu-ds.magentacloud.qa + + com.apple.security.network.client + + keychain-access-groups + + $(AppIdentifierPrefix)MagentaCLOUD + diff --git a/Brand/Share.plist b/Brand/Share.plist index 567991a236..98af08a5bd 100755 --- a/Brand/Share.plist +++ b/Brand/Share.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - Nextcloud + MagentaCLOUD CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -23,7 +23,7 @@ NSAppTransportSecurity NSAllowsArbitraryLoads - + NSExtension diff --git a/Brand/iOSClient.entitlements b/Brand/iOSClient.entitlements index f4b9c9dcce..63987b375f 100755 --- a/Brand/iOSClient.entitlements +++ b/Brand/iOSClient.entitlements @@ -8,8 +8,8 @@ com.apple.security.application-groups - group.com.nextcloud.apps - group.it.twsweb.Crypto-Cloud + group.de.magentacloud.next.dev2.client.apps + group.de.magentacloud.next.dev2.client com.apple.security.device.audio-input @@ -23,7 +23,29 @@ keychain-access-groups - $(AppIdentifierPrefix)it.twsweb.Crypto-Cloud + $(AppIdentifierPrefix)de.magentacloud.next.dev2.client + aps-environment + development + com.apple.security.app-sandbox + + com.apple.security.application-groups + + group.com.t-systems.pu-ds.magentacloud.qa + + com.apple.security.device.audio-input + + com.apple.security.device.camera + + com.apple.security.network.client + + com.apple.security.personal-information.location + + com.apple.security.personal-information.photos-library + + keychain-access-groups + + $(AppIdentifierPrefix)MagentaCLOUD + diff --git a/Brand/iOSClient.plist b/Brand/iOSClient.plist index ec039e4074..66e0980c9d 100755 --- a/Brand/iOSClient.plist +++ b/Brand/iOSClient.plist @@ -12,13 +12,13 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - Nextcloud + MagentaCLOUD CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion - 6.0 + $(MARKETING_VERSION) CFBundleName $(PRODUCT_NAME) CFBundlePackageType @@ -43,9 +43,7 @@ CFBundleVersion $(CURRENT_PROJECT_VERSION) ITSAppUsesNonExemptEncryption - - ITSEncryptionExportComplianceCode - 8e9f9874-938e-460b-a9be-f82cb3393971 + LSApplicationQueriesSchemes nextcloudtalk @@ -60,18 +58,18 @@ NSAppTransportSecurity NSAllowsArbitraryLoads - + NSCameraUsageDescription Camera access is required to scan documents and make photo and video. NSFaceIDUsageDescription Face ID is required to authenticate using face recognition. NSLocationAlwaysAndWhenInUseUsageDescription - This app needs access to your location even in the background to automatically start uploading files when significant movement is detected. GPS is not used. + The app will show your location on a map. NSLocationAlwaysUsageDescription - The app uses your location to automatically trigger file uploads when you move between areas. + The app will show your location on a map. NSLocationWhenInUseUsageDescription - This app uses your location to detect movement and automatically upload files. It does not use GPS and does not store your location. + The app will show your location on a map. NSMicrophoneUsageDescription Microphone access is required to create voice notes. NSPhotoLibraryAddUsageDescription @@ -83,6 +81,8 @@ AccountIntent DashboardIntent + NSUserTrackingUsageDescription + App would like to access IDFA for tracking purpose PHPhotoLibraryPreventAutomaticLimitedAccessAlert UIAppFonts diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 8dd4c5545f..6aa63de37c 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 3704EB2A23D5A58400455C5B /* NCMenu.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3704EB2923D5A58400455C5B /* NCMenu.storyboard */; }; 370D26AF248A3D7A00121797 /* NCCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370D26AE248A3D7A00121797 /* NCCellProtocol.swift */; }; 371B5A2E23D0B04500FAFAE9 /* NCMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371B5A2D23D0B04500FAFAE9 /* NCMenu.swift */; }; + 3781B9B023DB2B7E006B4B1D /* AppDelegate+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3781B9AF23DB2B7E006B4B1D /* AppDelegate+Menu.swift */; }; 8491B1CD273BBA82001C8C5B /* UIViewController+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */; }; AA3C85E82D36B08C00F74F12 /* UITestBackend.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA3C85E72D36B08C00F74F12 /* UITestBackend.swift */; }; AA3C85EB2D36BBFB00F74F12 /* OCSResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA3C85EA2D36BBF400F74F12 /* OCSResponse.swift */; }; @@ -43,7 +44,6 @@ AAA7BC2E2D3E39F1008F1A22 /* CapabilitiesResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA7BC2D2D3E39EC008F1A22 /* CapabilitiesResponse.swift */; }; AAA7BC302D3E3B88008F1A22 /* CapabilityResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA7BC2F2D3E3B83008F1A22 /* CapabilityResponse.swift */; }; AABD0C8A2D5F67A400F009E6 /* XCUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = AABD0C892D5F67A200F009E6 /* XCUIElement.swift */; }; - AABD0C9B2D5F73FC00F009E6 /* Placeholder.swift in Sources */ = {isa = PBXBuildFile; fileRef = AABD0C9A2D5F73FA00F009E6 /* Placeholder.swift */; }; AAE330042D2ED20200B04903 /* NCShareNavigationTitleSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE330032D2ED1FF00B04903 /* NCShareNavigationTitleSetting.swift */; }; AF1A9B6427D0CA1E00F17A9E /* UIAlertController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1A9B6327D0CA1E00F17A9E /* UIAlertController+Extension.swift */; }; AF1A9B6527D0CC0500F17A9E /* UIAlertController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1A9B6327D0CA1E00F17A9E /* UIAlertController+Extension.swift */; }; @@ -85,6 +85,199 @@ AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */; }; AFCE353727E4ED7B00FEA6C2 /* NCShareCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */; }; AFCE353927E5DE0500FEA6C2 /* Shareable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* Shareable.swift */; }; + B560B95A2EF5597A00E55904 /* NCAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560B9582EF5597A00E55904 /* NCAccount.swift */; }; + B560B95B2EF5597A00E55904 /* NCShareAccounts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560B9532EF5597A00E55904 /* NCShareAccounts.swift */; }; + B560B95C2EF5597A00E55904 /* NCAccountSettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560B9552EF5597A00E55904 /* NCAccountSettingsModel.swift */; }; + B560B95D2EF5597A00E55904 /* NCAccountSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560B9562EF5597A00E55904 /* NCAccountSettingsView.swift */; }; + B560B95E2EF5597A00E55904 /* NCAccountRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560B9512EF5597A00E55904 /* NCAccountRequest.swift */; }; + B560B95F2EF5597A00E55904 /* NCShareAccounts.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B560B9522EF5597A00E55904 /* NCShareAccounts.storyboard */; }; + B560B9602EF5597A00E55904 /* NCAccountRequest.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B560B9502EF5597A00E55904 /* NCAccountRequest.storyboard */; }; + B560B9612EF559C100E55904 /* NCAccountRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560B9512EF5597A00E55904 /* NCAccountRequest.swift */; }; + B560B9622EF559C100E55904 /* NCAccountRequest.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B560B9502EF5597A00E55904 /* NCAccountRequest.storyboard */; }; + B5BEBD2F2E93AD540002C9E5 /* iOSClient.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2A2E93AD540002C9E5 /* iOSClient.plist */; }; + B5BEBD302E93AD540002C9E5 /* Share.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2E2E93AD540002C9E5 /* Share.plist */; }; + B5BEBD312E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2C2E93AD540002C9E5 /* Notification_Service_Extension.plist */; }; + B5BEBD322E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD282E93AD540002C9E5 /* File_Provider_Extension.plist */; }; + B5BEBD332E93AD540002C9E5 /* iOSClient.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2A2E93AD540002C9E5 /* iOSClient.plist */; }; + B5BEBD342E93AD540002C9E5 /* Share.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2E2E93AD540002C9E5 /* Share.plist */; }; + B5BEBD352E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2C2E93AD540002C9E5 /* Notification_Service_Extension.plist */; }; + B5BEBD362E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD282E93AD540002C9E5 /* File_Provider_Extension.plist */; }; + B5BEBD372E93AD540002C9E5 /* iOSClient.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2A2E93AD540002C9E5 /* iOSClient.plist */; }; + B5BEBD382E93AD540002C9E5 /* Share.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2E2E93AD540002C9E5 /* Share.plist */; }; + B5BEBD392E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2C2E93AD540002C9E5 /* Notification_Service_Extension.plist */; }; + B5BEBD3A2E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD282E93AD540002C9E5 /* File_Provider_Extension.plist */; }; + B5BEBD3B2E93AD540002C9E5 /* iOSClient.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2A2E93AD540002C9E5 /* iOSClient.plist */; }; + B5BEBD3C2E93AD540002C9E5 /* Share.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2E2E93AD540002C9E5 /* Share.plist */; }; + B5BEBD3D2E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2C2E93AD540002C9E5 /* Notification_Service_Extension.plist */; }; + B5BEBD3E2E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD282E93AD540002C9E5 /* File_Provider_Extension.plist */; }; + B5BEBD3F2E93AD540002C9E5 /* iOSClient.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2A2E93AD540002C9E5 /* iOSClient.plist */; }; + B5BEBD402E93AD540002C9E5 /* Share.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2E2E93AD540002C9E5 /* Share.plist */; }; + B5BEBD412E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2C2E93AD540002C9E5 /* Notification_Service_Extension.plist */; }; + B5BEBD422E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD282E93AD540002C9E5 /* File_Provider_Extension.plist */; }; + B5BEBD432E93AD540002C9E5 /* iOSClient.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2A2E93AD540002C9E5 /* iOSClient.plist */; }; + B5BEBD442E93AD540002C9E5 /* Share.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2E2E93AD540002C9E5 /* Share.plist */; }; + B5BEBD452E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2C2E93AD540002C9E5 /* Notification_Service_Extension.plist */; }; + B5BEBD462E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD282E93AD540002C9E5 /* File_Provider_Extension.plist */; }; + B5BEBD472E93AD540002C9E5 /* iOSClient.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2A2E93AD540002C9E5 /* iOSClient.plist */; }; + B5BEBD482E93AD540002C9E5 /* Share.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2E2E93AD540002C9E5 /* Share.plist */; }; + B5BEBD492E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2C2E93AD540002C9E5 /* Notification_Service_Extension.plist */; }; + B5BEBD4A2E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD282E93AD540002C9E5 /* File_Provider_Extension.plist */; }; + B5BEBD4B2E93AD540002C9E5 /* iOSClient.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2A2E93AD540002C9E5 /* iOSClient.plist */; }; + B5BEBD4C2E93AD540002C9E5 /* Share.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2E2E93AD540002C9E5 /* Share.plist */; }; + B5BEBD4D2E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD2C2E93AD540002C9E5 /* Notification_Service_Extension.plist */; }; + B5BEBD4E2E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD282E93AD540002C9E5 /* File_Provider_Extension.plist */; }; + B5BEBD522E93AE1C0002C9E5 /* TestConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD502E93AE1C0002C9E5 /* TestConstants.swift */; }; + B5BEBD532E93AE1C0002C9E5 /* BaseXCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD4F2E93AE1C0002C9E5 /* BaseXCTestCase.swift */; }; + B5BEBD542E93AE1C0002C9E5 /* TestConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD502E93AE1C0002C9E5 /* TestConstants.swift */; }; + B5BEBD552E93AE1C0002C9E5 /* BaseXCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD4F2E93AE1C0002C9E5 /* BaseXCTestCase.swift */; }; + B5BEBD562E93AE1C0002C9E5 /* TestConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD502E93AE1C0002C9E5 /* TestConstants.swift */; }; + B5BEBD572E93AE1C0002C9E5 /* BaseXCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD4F2E93AE1C0002C9E5 /* BaseXCTestCase.swift */; }; + B5BEBD5B2E93AE2F0002C9E5 /* LoginIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD5A2E93AE2F0002C9E5 /* LoginIntegrationTests.swift */; }; + B5BEBD5C2E93AE2F0002C9E5 /* BaseIntegrationXCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD582E93AE2F0002C9E5 /* BaseIntegrationXCTestCase.swift */; }; + B5BEBD5D2E93AE2F0002C9E5 /* FilesIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD592E93AE2F0002C9E5 /* FilesIntegrationTests.swift */; }; + B5BEBD6B2E93AE4B0002C9E5 /* SharingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD6A2E93AE4B0002C9E5 /* SharingTest.swift */; }; + B5BEBD6C2E93AE4B0002C9E5 /* AssetUploadTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD5E2E93AE4B0002C9E5 /* AssetUploadTest.swift */; }; + B5BEBD6D2E93AE4B0002C9E5 /* NCNotificationText.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD642E93AE4B0002C9E5 /* NCNotificationText.swift */; }; + B5BEBD6E2E93AE4B0002C9E5 /* SettingsTestCases.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD692E93AE4B0002C9E5 /* SettingsTestCases.swift */; }; + B5BEBD6F2E93AE4B0002C9E5 /* CollaboraTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD602E93AE4B0002C9E5 /* CollaboraTestCase.swift */; }; + B5BEBD702E93AE4B0002C9E5 /* MoveAndCopyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD632E93AE4B0002C9E5 /* MoveAndCopyTests.swift */; }; + B5BEBD712E93AE4B0002C9E5 /* MoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD622E93AE4B0002C9E5 /* MoreTests.swift */; }; + B5BEBD722E93AE4B0002C9E5 /* RenameFileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD672E93AE4B0002C9E5 /* RenameFileTests.swift */; }; + B5BEBD732E93AE4B0002C9E5 /* AudioUploadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD5F2E93AE4B0002C9E5 /* AudioUploadTests.swift */; }; + B5BEBD742E93AE4B0002C9E5 /* OnboardingTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD652E93AE4B0002C9E5 /* OnboardingTestCase.swift */; }; + B5BEBD752E93AE4B0002C9E5 /* E2EETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD612E93AE4B0002C9E5 /* E2EETests.swift */; }; + B5BEBD762E93AE4B0002C9E5 /* ScanTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD682E93AE4B0002C9E5 /* ScanTests.swift */; }; + B5BEBD772E93AE4B0002C9E5 /* PrivacyPolicyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD662E93AE4B0002C9E5 /* PrivacyPolicyTest.swift */; }; + B5BEBD7D2E93AEA30002C9E5 /* AnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7B2E93AEA30002C9E5 /* AnalyticsService.swift */; }; + B5BEBD7E2E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD782E93AEA30002C9E5 /* MoEngageAnalytics.swift */; }; + B5BEBD7F2E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7A2E93AEA30002C9E5 /* AnalyticsHelper.swift */; }; + B5BEBD802E93AEA30002C9E5 /* AnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7B2E93AEA30002C9E5 /* AnalyticsService.swift */; }; + B5BEBD812E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD782E93AEA30002C9E5 /* MoEngageAnalytics.swift */; }; + B5BEBD822E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7A2E93AEA30002C9E5 /* AnalyticsHelper.swift */; }; + B5BEBD832E93AEA30002C9E5 /* AnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7B2E93AEA30002C9E5 /* AnalyticsService.swift */; }; + B5BEBD842E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD782E93AEA30002C9E5 /* MoEngageAnalytics.swift */; }; + B5BEBD852E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7A2E93AEA30002C9E5 /* AnalyticsHelper.swift */; }; + B5BEBD862E93AEA30002C9E5 /* AnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7B2E93AEA30002C9E5 /* AnalyticsService.swift */; }; + B5BEBD872E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD782E93AEA30002C9E5 /* MoEngageAnalytics.swift */; }; + B5BEBD882E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7A2E93AEA30002C9E5 /* AnalyticsHelper.swift */; }; + B5BEBD892E93AEA30002C9E5 /* AnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7B2E93AEA30002C9E5 /* AnalyticsService.swift */; }; + B5BEBD8A2E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD782E93AEA30002C9E5 /* MoEngageAnalytics.swift */; }; + B5BEBD8B2E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7A2E93AEA30002C9E5 /* AnalyticsHelper.swift */; }; + B5BEBD8C2E93AEA30002C9E5 /* AnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7B2E93AEA30002C9E5 /* AnalyticsService.swift */; }; + B5BEBD8D2E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD782E93AEA30002C9E5 /* MoEngageAnalytics.swift */; }; + B5BEBD8E2E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7A2E93AEA30002C9E5 /* AnalyticsHelper.swift */; }; + B5BEBD8F2E93AEA30002C9E5 /* AnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7B2E93AEA30002C9E5 /* AnalyticsService.swift */; }; + B5BEBD902E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD782E93AEA30002C9E5 /* MoEngageAnalytics.swift */; }; + B5BEBD912E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD7A2E93AEA30002C9E5 /* AnalyticsHelper.swift */; }; + B5BEBD942E93AED80002C9E5 /* AppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD922E93AED80002C9E5 /* AppUpdater.swift */; }; + B5BEBD952E93AED80002C9E5 /* AppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD922E93AED80002C9E5 /* AppUpdater.swift */; }; + B5BEBD962E93AED80002C9E5 /* AppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD922E93AED80002C9E5 /* AppUpdater.swift */; }; + B5BEBD972E93AED80002C9E5 /* AppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD922E93AED80002C9E5 /* AppUpdater.swift */; }; + B5BEBD982E93AED80002C9E5 /* AppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD922E93AED80002C9E5 /* AppUpdater.swift */; }; + B5BEBD992E93AED80002C9E5 /* AppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD922E93AED80002C9E5 /* AppUpdater.swift */; }; + B5BEBD9A2E93AED80002C9E5 /* AppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD922E93AED80002C9E5 /* AppUpdater.swift */; }; + B5BEBDA32E93AF010002C9E5 /* AppUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9B2E93AF010002C9E5 /* AppUtility.swift */; }; + B5BEBDA42E93AF010002C9E5 /* AdjustHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA02E93AF010002C9E5 /* AdjustHelper.m */; }; + B5BEBDA52E93AF010002C9E5 /* TealiumHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA12E93AF010002C9E5 /* TealiumHelper.swift */; }; + B5BEBDA62E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9C2E93AF010002C9E5 /* NCEmptyDataSet.swift */; }; + B5BEBDA72E93AF010002C9E5 /* NCEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD9D2E93AF010002C9E5 /* NCEmptyView.xib */; }; + B5BEBDA82E93AF010002C9E5 /* NCEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD9D2E93AF010002C9E5 /* NCEmptyView.xib */; }; + B5BEBDA92E93AF010002C9E5 /* AppUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9B2E93AF010002C9E5 /* AppUtility.swift */; }; + B5BEBDAA2E93AF010002C9E5 /* AdjustHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA02E93AF010002C9E5 /* AdjustHelper.m */; }; + B5BEBDAB2E93AF010002C9E5 /* TealiumHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA12E93AF010002C9E5 /* TealiumHelper.swift */; }; + B5BEBDAC2E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9C2E93AF010002C9E5 /* NCEmptyDataSet.swift */; }; + B5BEBDAD2E93AF010002C9E5 /* AppUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9B2E93AF010002C9E5 /* AppUtility.swift */; }; + B5BEBDAE2E93AF010002C9E5 /* AdjustHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA02E93AF010002C9E5 /* AdjustHelper.m */; }; + B5BEBDAF2E93AF010002C9E5 /* TealiumHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA12E93AF010002C9E5 /* TealiumHelper.swift */; }; + B5BEBDB02E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9C2E93AF010002C9E5 /* NCEmptyDataSet.swift */; }; + B5BEBDB12E93AF010002C9E5 /* NCEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD9D2E93AF010002C9E5 /* NCEmptyView.xib */; }; + B5BEBDB22E93AF010002C9E5 /* AppUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9B2E93AF010002C9E5 /* AppUtility.swift */; }; + B5BEBDB32E93AF010002C9E5 /* AdjustHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA02E93AF010002C9E5 /* AdjustHelper.m */; }; + B5BEBDB42E93AF010002C9E5 /* TealiumHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA12E93AF010002C9E5 /* TealiumHelper.swift */; }; + B5BEBDB52E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9C2E93AF010002C9E5 /* NCEmptyDataSet.swift */; }; + B5BEBDB62E93AF010002C9E5 /* NCEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD9D2E93AF010002C9E5 /* NCEmptyView.xib */; }; + B5BEBDB72E93AF010002C9E5 /* AppUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9B2E93AF010002C9E5 /* AppUtility.swift */; }; + B5BEBDB82E93AF010002C9E5 /* AdjustHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA02E93AF010002C9E5 /* AdjustHelper.m */; }; + B5BEBDB92E93AF010002C9E5 /* TealiumHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA12E93AF010002C9E5 /* TealiumHelper.swift */; }; + B5BEBDBA2E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9C2E93AF010002C9E5 /* NCEmptyDataSet.swift */; }; + B5BEBDBB2E93AF010002C9E5 /* NCEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD9D2E93AF010002C9E5 /* NCEmptyView.xib */; }; + B5BEBDBC2E93AF010002C9E5 /* AppUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9B2E93AF010002C9E5 /* AppUtility.swift */; }; + B5BEBDBD2E93AF010002C9E5 /* AdjustHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA02E93AF010002C9E5 /* AdjustHelper.m */; }; + B5BEBDBE2E93AF010002C9E5 /* TealiumHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA12E93AF010002C9E5 /* TealiumHelper.swift */; }; + B5BEBDBF2E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9C2E93AF010002C9E5 /* NCEmptyDataSet.swift */; }; + B5BEBDC02E93AF010002C9E5 /* NCEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD9D2E93AF010002C9E5 /* NCEmptyView.xib */; }; + B5BEBDC12E93AF010002C9E5 /* NCEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBD9D2E93AF010002C9E5 /* NCEmptyView.xib */; }; + B5BEBDC22E93AF010002C9E5 /* AppUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9B2E93AF010002C9E5 /* AppUtility.swift */; }; + B5BEBDC32E93AF010002C9E5 /* AdjustHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA02E93AF010002C9E5 /* AdjustHelper.m */; }; + B5BEBDC42E93AF010002C9E5 /* TealiumHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDA12E93AF010002C9E5 /* TealiumHelper.swift */; }; + B5BEBDC52E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD9C2E93AF010002C9E5 /* NCEmptyDataSet.swift */; }; + B5BEBDC72E93AF7E0002C9E5 /* NCLoginWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDC62E93AF7E0002C9E5 /* NCLoginWeb.swift */; }; + B5BEBDC92E93AFF10002C9E5 /* NCSelectableNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDC82E93AFF10002C9E5 /* NCSelectableNavigationView.swift */; }; + B5BEBDCC2E93B0210002C9E5 /* NCSectionHeaderMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDCA2E93B0210002C9E5 /* NCSectionHeaderMenu.swift */; }; + B5BEBDCD2E93B0210002C9E5 /* NCSectionHeaderMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDCB2E93B0210002C9E5 /* NCSectionHeaderMenu.xib */; }; + B5BEBDCE2E93B0210002C9E5 /* NCSectionHeaderMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDCA2E93B0210002C9E5 /* NCSectionHeaderMenu.swift */; }; + B5BEBDCF2E93B0210002C9E5 /* NCSectionHeaderMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDCB2E93B0210002C9E5 /* NCSectionHeaderMenu.xib */; }; + B5BEBDD62E93B2450002C9E5 /* NCCreateFormUploadDocuments.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDD12E93B2450002C9E5 /* NCCreateFormUploadDocuments.swift */; }; + B5BEBDD72E93B2450002C9E5 /* TextTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDD42E93B2450002C9E5 /* TextTableViewCell.swift */; }; + B5BEBDD82E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDD32E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.swift */; }; + B5BEBDD92E93B2450002C9E5 /* TextTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDD52E93B2450002C9E5 /* TextTableViewCell.xib */; }; + B5BEBDDA2E93B2450002C9E5 /* NCCreateFormUploadDocuments.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDD02E93B2450002C9E5 /* NCCreateFormUploadDocuments.storyboard */; }; + B5BEBDDB2E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDD22E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.storyboard */; }; + B5BEBDDC2E93B2450002C9E5 /* NCCreateFormUploadDocuments.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDD12E93B2450002C9E5 /* NCCreateFormUploadDocuments.swift */; }; + B5BEBDDD2E93B2450002C9E5 /* TextTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDD42E93B2450002C9E5 /* TextTableViewCell.swift */; }; + B5BEBDDE2E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDD32E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.swift */; }; + B5BEBDDF2E93B2450002C9E5 /* TextTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDD52E93B2450002C9E5 /* TextTableViewCell.xib */; }; + B5BEBDE02E93B2450002C9E5 /* NCCreateFormUploadDocuments.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDD02E93B2450002C9E5 /* NCCreateFormUploadDocuments.storyboard */; }; + B5BEBDE12E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDD22E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.storyboard */; }; + B5BEBDE32E93BD6F0002C9E5 /* NCMediaCommandView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE22E93BD6F0002C9E5 /* NCMediaCommandView.xib */; }; + B5BEBDE92E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE42E93BDB40002C9E5 /* FolderPathCustomCell.swift */; }; + B5BEBDEA2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE62E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift */; }; + B5BEBDEB2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE72E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib */; }; + B5BEBDEC2E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE52E93BDB40002C9E5 /* FolderPathCustomCell.xib */; }; + B5BEBDED2E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE42E93BDB40002C9E5 /* FolderPathCustomCell.swift */; }; + B5BEBDEE2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE62E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift */; }; + B5BEBDEF2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE72E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib */; }; + B5BEBDF02E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE52E93BDB40002C9E5 /* FolderPathCustomCell.xib */; }; + B5BEBDF12E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE42E93BDB40002C9E5 /* FolderPathCustomCell.swift */; }; + B5BEBDF22E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE62E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift */; }; + B5BEBDF32E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE72E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib */; }; + B5BEBDF42E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE52E93BDB40002C9E5 /* FolderPathCustomCell.xib */; }; + B5BEBDF52E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE42E93BDB40002C9E5 /* FolderPathCustomCell.swift */; }; + B5BEBDF62E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE62E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift */; }; + B5BEBDF72E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE72E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib */; }; + B5BEBDF82E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE52E93BDB40002C9E5 /* FolderPathCustomCell.xib */; }; + B5BEBDF92E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE42E93BDB40002C9E5 /* FolderPathCustomCell.swift */; }; + B5BEBDFA2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE62E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift */; }; + B5BEBDFB2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE72E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib */; }; + B5BEBDFC2E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE52E93BDB40002C9E5 /* FolderPathCustomCell.xib */; }; + B5BEBDFD2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE72E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib */; }; + B5BEBDFE2E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE52E93BDB40002C9E5 /* FolderPathCustomCell.xib */; }; + B5BEBDFF2E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE42E93BDB40002C9E5 /* FolderPathCustomCell.swift */; }; + B5BEBE002E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE62E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift */; }; + B5BEBE012E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE72E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib */; }; + B5BEBE022E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBDE52E93BDB40002C9E5 /* FolderPathCustomCell.xib */; }; + B5BEBE032E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE42E93BDB40002C9E5 /* FolderPathCustomCell.swift */; }; + B5BEBE042E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBDE62E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift */; }; + B5BEBE062E93BE0C0002C9E5 /* NCCreateFormUploadScanDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBE052E93BE0C0002C9E5 /* NCCreateFormUploadScanDocument.swift */; }; + B5BEBE1A2E93BE200002C9E5 /* PNGImageSaveSwitchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBE112E93BE200002C9E5 /* PNGImageSaveSwitchView.swift */; }; + B5BEBE1B2E93BE200002C9E5 /* FileNameInputTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBE072E93BE200002C9E5 /* FileNameInputTextField.swift */; }; + B5BEBE1C2E93BE200002C9E5 /* PdfWithoutOcrSwitchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBE0F2E93BE200002C9E5 /* PdfWithoutOcrSwitchView.swift */; }; + B5BEBE1D2E93BE200002C9E5 /* TextFileWithOcrSwitchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBE172E93BE200002C9E5 /* TextFileWithOcrSwitchView.swift */; }; + B5BEBE1E2E93BE200002C9E5 /* ScanDocumentPathView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBE132E93BE200002C9E5 /* ScanDocumentPathView.swift */; }; + B5BEBE1F2E93BE200002C9E5 /* SetPDFPasswordSwitchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBE152E93BE200002C9E5 /* SetPDFPasswordSwitchView.swift */; }; + B5BEBE202E93BE200002C9E5 /* JPGImageSaveSwitchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBE092E93BE200002C9E5 /* JPGImageSaveSwitchView.swift */; }; + B5BEBE212E93BE200002C9E5 /* PasswordInputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBE0B2E93BE200002C9E5 /* PasswordInputField.swift */; }; + B5BEBE222E93BE200002C9E5 /* PdfWithOcrSwitchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBE0D2E93BE200002C9E5 /* PdfWithOcrSwitchView.swift */; }; + B5BEBE232E93BE200002C9E5 /* PasswordInputField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBE0C2E93BE200002C9E5 /* PasswordInputField.xib */; }; + B5BEBE242E93BE200002C9E5 /* ScanDocumentPathView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBE142E93BE200002C9E5 /* ScanDocumentPathView.xib */; }; + B5BEBE252E93BE200002C9E5 /* SetPDFPasswordSwitchView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBE162E93BE200002C9E5 /* SetPDFPasswordSwitchView.xib */; }; + B5BEBE262E93BE200002C9E5 /* PdfWithOcrSwitchView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBE0E2E93BE200002C9E5 /* PdfWithOcrSwitchView.xib */; }; + B5BEBE272E93BE200002C9E5 /* PNGImageSaveSwitchView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBE122E93BE200002C9E5 /* PNGImageSaveSwitchView.xib */; }; + B5BEBE282E93BE200002C9E5 /* FileNameInputTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBE082E93BE200002C9E5 /* FileNameInputTextField.xib */; }; + B5BEBE292E93BE200002C9E5 /* TextFileWithOcrSwitchView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBE182E93BE200002C9E5 /* TextFileWithOcrSwitchView.xib */; }; + B5BEBE2A2E93BE200002C9E5 /* PdfWithoutOcrSwitchView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBE102E93BE200002C9E5 /* PdfWithoutOcrSwitchView.xib */; }; + B5BEBE2B2E93BE200002C9E5 /* JPGImageSaveSwitchView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5BEBE0A2E93BE200002C9E5 /* JPGImageSaveSwitchView.xib */; }; + D575039F27146F93008DC9DC /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; }; D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */; }; F310B1EF2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = F310B1EE2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift */; }; F321DA8A2B71205A00DDA0E6 /* NCTrashSelectTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F321DA892B71205A00DDA0E6 /* NCTrashSelectTabBar.swift */; }; @@ -121,10 +314,18 @@ F359D8672A7D03420023F405 /* NCUtility+Exif.swift in Sources */ = {isa = PBXBuildFile; fileRef = F359D8662A7D03420023F405 /* NCUtility+Exif.swift */; }; F36C514F2E89393C0097E5F7 /* UIView+BlurVibrancy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36C514D2E89393C0097E5F7 /* UIView+BlurVibrancy.swift */; }; F36E64F72B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBarDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36E64F62B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBarDelegate.swift */; }; + F36E64F72B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36E64F62B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBar.swift */; }; F36E64FA2B96236C0085ABB5 /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E41315294A19B300839300 /* UIView+Extension.swift */; }; F372087D2BAB4C0F006B5430 /* TestConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37208742BAB4AB0006B5430 /* TestConstants.swift */; }; F372087E2BAB4C0F006B5430 /* TestConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37208742BAB4AB0006B5430 /* TestConstants.swift */; }; F37208812BAB5979006B5430 /* TestConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37208742BAB4AB0006B5430 /* TestConstants.swift */; }; + F36E64FB2B9733F10085ABB5 /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E41315294A19B300839300 /* UIView+Extension.swift */; }; + F36E64FC2B9733F20085ABB5 /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E41315294A19B300839300 /* UIView+Extension.swift */; }; + F36E64FD2B9735900085ABB5 /* NCCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370D26AE248A3D7A00121797 /* NCCellProtocol.swift */; }; + F36E64FE2B9735920085ABB5 /* NCCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370D26AE248A3D7A00121797 /* NCCellProtocol.swift */; }; + F372087D2BAB4C0F006B5430 /* TestConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37208742BAB4AB0006B5430 /* TestConstants.swift */; }; + F372087E2BAB4C0F006B5430 /* TestConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37208742BAB4AB0006B5430 /* TestConstants.swift */; }; + F37208812BAB5979006B5430 /* TestConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37208742BAB4AB0006B5430 /* TestConstants.swift */; }; F37208A42BAB63EE006B5430 /* QRCodeReader in Frameworks */ = {isa = PBXBuildFile; productRef = F37208A32BAB63EE006B5430 /* QRCodeReader */; }; F37208A62BAB63EE006B5430 /* SwiftRichString in Frameworks */ = {isa = PBXBuildFile; productRef = F37208A52BAB63EE006B5430 /* SwiftRichString */; }; F37208A82BAB63EE006B5430 /* FloatingPanel in Frameworks */ = {isa = PBXBuildFile; productRef = F37208A72BAB63EE006B5430 /* FloatingPanel */; }; @@ -145,7 +346,6 @@ F37208C62BAB63F0006B5430 /* LRUCache in Frameworks */ = {isa = PBXBuildFile; productRef = F37208C52BAB63F0006B5430 /* LRUCache */; }; F37208C82BAB63F1006B5430 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = F37208C72BAB63F1006B5430 /* KeychainAccess */; }; F3754A7D2CF87D600009312E /* SetupPasscodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3754A7C2CF87D600009312E /* SetupPasscodeView.swift */; }; - F376A3742E5CC6030067EE25 /* ContextMenuActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F376A3732E5CC5FF0067EE25 /* ContextMenuActions.swift */; }; F389C9F52CEE383300049762 /* SelectAlbumView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F389C9F42CEE383300049762 /* SelectAlbumView.swift */; }; F38F71252B6BBDC300473CDC /* NCCollectionViewCommonSelectTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F38F71242B6BBDC300473CDC /* NCCollectionViewCommonSelectTabBar.swift */; }; F39170AD2CB82024006127BC /* FileAutoRenamer+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39170A82CB8201B006127BC /* FileAutoRenamer+Extensions.swift */; }; @@ -224,7 +424,7 @@ F70D7C3725FFBF82002B9E34 /* NCCollectionViewCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70D7C3525FFBF81002B9E34 /* NCCollectionViewCommon.swift */; }; F70D8D8124A4A9BF000A5756 /* NCNetworkingProcess.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70D8D8024A4A9BF000A5756 /* NCNetworkingProcess.swift */; }; F710D1F52405770F00A6033D /* NCViewerPDF.swift in Sources */ = {isa = PBXBuildFile; fileRef = F710D1F42405770F00A6033D /* NCViewerPDF.swift */; }; - F710D2022405826100A6033D /* NCViewerContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F710D2012405826100A6033D /* NCViewerContextMenu.swift */; }; + F710D2022405826100A6033D /* NCViewer+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F710D2012405826100A6033D /* NCViewer+Menu.swift */; }; F710FC80277B7D2700AA9FBF /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F710FC7F277B7D2700AA9FBF /* RealmSwift */; }; F710FC84277B7D3500AA9FBF /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F710FC83277B7D3500AA9FBF /* RealmSwift */; }; F710FC88277B7D3F00AA9FBF /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F710FC87277B7D3F00AA9FBF /* RealmSwift */; }; @@ -279,6 +479,15 @@ F724377D2C10B92300C7C68D /* NCSharePermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F724377A2C10B83E00C7C68D /* NCSharePermissions.swift */; }; F72437802C10B92400C7C68D /* NCSharePermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F724377A2C10B83E00C7C68D /* NCSharePermissions.swift */; }; F72437812C10B92500C7C68D /* NCSharePermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F724377A2C10B83E00C7C68D /* NCSharePermissions.swift */; }; + F72429372AFE39980040AEF3 /* NCLivePhoto.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70968A324212C4E00ED60E5 /* NCLivePhoto.swift */; }; + F72429382AFE39A80040AEF3 /* NCLivePhoto.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70968A324212C4E00ED60E5 /* NCLivePhoto.swift */; }; + F724377B2C10B83E00C7C68D /* NCPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F724377A2C10B83E00C7C68D /* NCPermissions.swift */; }; + F724377C2C10B92200C7C68D /* NCPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F724377A2C10B83E00C7C68D /* NCPermissions.swift */; }; + F724377D2C10B92300C7C68D /* NCPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F724377A2C10B83E00C7C68D /* NCPermissions.swift */; }; + F724377E2C10B92300C7C68D /* NCPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F724377A2C10B83E00C7C68D /* NCPermissions.swift */; }; + F724377F2C10B92400C7C68D /* NCPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F724377A2C10B83E00C7C68D /* NCPermissions.swift */; }; + F72437802C10B92400C7C68D /* NCPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F724377A2C10B83E00C7C68D /* NCPermissions.swift */; }; + F72437812C10B92500C7C68D /* NCPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F724377A2C10B83E00C7C68D /* NCPermissions.swift */; }; F7245924289BB50C00474787 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; }; F7245925289BB59100474787 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; }; F7245926289BB59300474787 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; }; @@ -309,6 +518,11 @@ F72FD3BA297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72FD3B4297ED49A00075D28 /* NCManageDatabase+E2EE.swift */; }; F7327E202B73A42F00A462C7 /* NCNetworking+Download.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7327E1F2B73A42F00A462C7 /* NCNetworking+Download.swift */; }; F7327E232B73A42F00A462C7 /* NCNetworking+Download.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7327E1F2B73A42F00A462C7 /* NCNetworking+Download.swift */; }; + F7327E242B73A42F00A462C7 /* NCNetworking+Download.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7327E1F2B73A42F00A462C7 /* NCNetworking+Download.swift */; }; + F7327E282B73A53400A462C7 /* NCNetworking+Upload.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7327E272B73A53400A462C7 /* NCNetworking+Upload.swift */; }; + F7327E292B73A53400A462C7 /* NCNetworking+Upload.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7327E272B73A53400A462C7 /* NCNetworking+Upload.swift */; }; + F7327E2B2B73A53400A462C7 /* NCNetworking+Upload.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7327E272B73A53400A462C7 /* NCNetworking+Upload.swift */; }; + F7327E2C2B73A53400A462C7 /* NCNetworking+Upload.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7327E272B73A53400A462C7 /* NCNetworking+Upload.swift */; }; F7327E302B73A86700A462C7 /* NCNetworking+WebDAV.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7327E2F2B73A86700A462C7 /* NCNetworking+WebDAV.swift */; }; F7327E322B73A86700A462C7 /* NCNetworking+WebDAV.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7327E2F2B73A86700A462C7 /* NCNetworking+WebDAV.swift */; }; F7327E352B73AEDE00A462C7 /* NCNetworking+LivePhoto.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7327E342B73AEDE00A462C7 /* NCNetworking+LivePhoto.swift */; }; @@ -327,6 +541,10 @@ F7386E482DA90E0F009A00F6 /* NCAppVersionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7386E452DA90E02009A00F6 /* NCAppVersionManager.swift */; }; F73ADD1C265546890069EA0D /* SwiftEntryKit in Frameworks */ = {isa = PBXBuildFile; productRef = F73ADD1B265546890069EA0D /* SwiftEntryKit */; }; F73ADD2126554F8E0069EA0D /* SwiftEntryKit in Frameworks */ = {isa = PBXBuildFile; productRef = F73ADD2026554F8E0069EA0D /* SwiftEntryKit */; }; + F73ADD2226554FD10069EA0D /* NCContentPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F765608E23BF813500765969 /* NCContentPresenter.swift */; }; + F73ADD2426554FE20069EA0D /* SwiftEntryKit in Frameworks */ = {isa = PBXBuildFile; productRef = F73ADD2326554FE20069EA0D /* SwiftEntryKit */; }; + F73B422B2476764F00A30FD3 /* NCNotification.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F73B42292476764F00A30FD3 /* NCNotification.storyboard */; }; + F73B422C2476764F00A30FD3 /* NCNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73B422A2476764F00A30FD3 /* NCNotification.swift */; }; F73CB3B222E072A000AD728E /* NCShareHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F73CB3B122E072A000AD728E /* NCShareHeaderView.xib */; }; F73D11FA253C5F4800DF9BEC /* NCViewerNextcloudText.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F73D11F9253C5F4800DF9BEC /* NCViewerNextcloudText.storyboard */; }; F73EF7A72B0223900087E6E9 /* NCManageDatabase+Comments.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73EF7A62B0223900087E6E9 /* NCManageDatabase+Comments.swift */; }; @@ -361,7 +579,6 @@ F741C2242B6B9FD600E849BB /* NCMediaSelectTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F741C2232B6B9FD600E849BB /* NCMediaSelectTabBar.swift */; }; F74230F32C79B57200CA1ACA /* NCNetworking+Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74230F22C79B57200CA1ACA /* NCNetworking+Task.swift */; }; F7434B3820E2400600417916 /* NCBrand.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */; }; - F743C89E2E5B25A1000173A9 /* UIScene+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F743C89D2E5B2595000173A9 /* UIScene+Extension.swift */; }; F745B253222D88AE00346520 /* NCLoginQRCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = F745B252222D88AE00346520 /* NCLoginQRCode.swift */; }; F746EC51273906C40052598D /* NCViewCertificateDetails.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7BC287D26663F6C004D46C5 /* NCViewCertificateDetails.storyboard */; }; F746EC52273906C40052598D /* NCViewCertificateDetails.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7BC287D26663F6C004D46C5 /* NCViewCertificateDetails.storyboard */; }; @@ -403,6 +620,8 @@ F751247C2C42919C00E63DB8 /* NCPhotoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F751247A2C42919C00E63DB8 /* NCPhotoCell.swift */; }; F751247E2C42919C00E63DB8 /* NCPhotoCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F751247B2C42919C00E63DB8 /* NCPhotoCell.xib */; }; F752BA052E58C05200616A26 /* Maintenance.swift in Sources */ = {isa = PBXBuildFile; fileRef = F752BA042E58C05200616A26 /* Maintenance.swift */; }; + F75379202AE2AD9400C0250E /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = F753791F2AE2AD9400C0250E /* JGProgressHUD */; }; + F75379222AE2ADA100C0250E /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = F75379212AE2ADA100C0250E /* JGProgressHUD */; }; F753BA93281FD8020015BFB6 /* EasyTipView in Frameworks */ = {isa = PBXBuildFile; productRef = F753BA92281FD8020015BFB6 /* EasyTipView */; }; F755BD9B20594AC7008C5FBB /* NCService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F755BD9A20594AC7008C5FBB /* NCService.swift */; }; F755CB402B8CB13C00CE27E9 /* NCMediaLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = F755CB3F2B8CB13C00CE27E9 /* NCMediaLayout.swift */; }; @@ -486,7 +705,7 @@ F76882282C0DD1E7001CF441 /* NCEndToEndInitialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F768820F2C0DD1E7001CF441 /* NCEndToEndInitialize.swift */; }; F76882292C0DD1E7001CF441 /* NCManageE2EEModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882102C0DD1E7001CF441 /* NCManageE2EEModel.swift */; }; F768822A2C0DD1E7001CF441 /* NCSettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882112C0DD1E7001CF441 /* NCSettingsModel.swift */; }; - F768822C2C0DD1E7001CF441 /* NCPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCPreferences.swift */; }; + F768822C2C0DD1E7001CF441 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCKeychain.swift */; }; F768822D2C0DD1E7001CF441 /* Acknowledgements.rtf in Resources */ = {isa = PBXBuildFile; fileRef = F76882142C0DD1E7001CF441 /* Acknowledgements.rtf */; }; F768822E2C0DD1E7001CF441 /* NCSettingsBundleHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882152C0DD1E7001CF441 /* NCSettingsBundleHelper.swift */; }; F76882302C0DD1E7001CF441 /* NCFileNameModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882192C0DD1E7001CF441 /* NCFileNameModel.swift */; }; @@ -496,12 +715,12 @@ F76882342C0DD1E7001CF441 /* NCDisplayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F768821E2C0DD1E7001CF441 /* NCDisplayView.swift */; }; F76882352C0DD1E7001CF441 /* NCWebBrowserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882202C0DD1E7001CF441 /* NCWebBrowserView.swift */; }; F76882362C0DD1E7001CF441 /* NCAcknowledgementsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882212C0DD1E7001CF441 /* NCAcknowledgementsView.swift */; }; - F76882372C0DD22F001CF441 /* NCPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCPreferences.swift */; }; - F76882382C0DD22F001CF441 /* NCPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCPreferences.swift */; }; - F76882392C0DD230001CF441 /* NCPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCPreferences.swift */; }; - F768823A2C0DD230001CF441 /* NCPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCPreferences.swift */; }; - F768823B2C0DD231001CF441 /* NCPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCPreferences.swift */; }; - F768823C2C0DD231001CF441 /* NCPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCPreferences.swift */; }; + F76882372C0DD22F001CF441 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCKeychain.swift */; }; + F76882382C0DD22F001CF441 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCKeychain.swift */; }; + F76882392C0DD230001CF441 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCKeychain.swift */; }; + F768823A2C0DD230001CF441 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCKeychain.swift */; }; + F768823B2C0DD231001CF441 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCKeychain.swift */; }; + F768823C2C0DD231001CF441 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCKeychain.swift */; }; F768823E2C0DD305001CF441 /* LazyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F768823D2C0DD304001CF441 /* LazyView.swift */; }; F76882402C0DD30B001CF441 /* ViewOnAppear.swift in Sources */ = {isa = PBXBuildFile; fileRef = F768823F2C0DD30B001CF441 /* ViewOnAppear.swift */; }; F769453C22E9CFFF000A798A /* NCShareUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F769453B22E9CFFF000A798A /* NCShareUserCell.xib */; }; @@ -578,6 +797,9 @@ F7817CF829801A3500FFBC65 /* Data+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7817CF729801A3500FFBC65 /* Data+Extension.swift */; }; F7817CFB29801A3500FFBC65 /* Data+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7817CF729801A3500FFBC65 /* Data+Extension.swift */; }; F7817CFF29802D1A00FFBC65 /* NCPushNotificationEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = F72D1005210B6882009C96B7 /* NCPushNotificationEncryption.m */; }; + F7817D0029802D3D00FFBC65 /* NCViewCertificateDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BC287F26663F85004D46C5 /* NCViewCertificateDetails.swift */; }; + F7817D0129802D5F00FFBC65 /* NCViewCertificateDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BC287F26663F85004D46C5 /* NCViewCertificateDetails.swift */; }; + F7817D0229802D7700FFBC65 /* NCViewCertificateDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BC287F26663F85004D46C5 /* NCViewCertificateDetails.swift */; }; F78295311F962EFA00A572F5 /* NCEndToEndEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = F70CAE391F8CF31A008125FD /* NCEndToEndEncryption.m */; }; F782FDC424E6933900666099 /* NCUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70BFC7320E0FA7C00C67599 /* NCUtility.swift */; }; F78302F728B4C3C900B84583 /* NCManageDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */; }; @@ -638,7 +860,6 @@ F793E59D28B761E7005E4B02 /* NCNetworking.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75A9EE523796C6F0044CFCE /* NCNetworking.swift */; }; F794E13D2BBBFF2E003693D7 /* NCMainTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F794E13C2BBBFF2E003693D7 /* NCMainTabBarController.swift */; }; F794E13F2BBC0F70003693D7 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F794E13E2BBC0F70003693D7 /* SceneDelegate.swift */; }; - F79699E72E689F68000EC82A /* NCMediaNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79699E62E689F68000EC82A /* NCMediaNavigationController.swift */; }; F798F0E225880608000DAFFD /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */; }; F798F0EC2588060A000DAFFD /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */; }; F799DF822C4B7DCC003410B5 /* NCSectionFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F799DF812C4B7DCC003410B5 /* NCSectionFooter.swift */; }; @@ -752,20 +973,38 @@ F7C9B9202B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9B91C2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift */; }; F7C9B9232B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9B91C2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift */; }; F7CADEFD2EA159210057849E /* NCMetadataTranfersSuccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CADEFA2EA1591D0057849E /* NCMetadataTranfersSuccess.swift */; }; + F7CA212D25F1333300826ABB /* + ces */ = {isa = PBXBuildFile; fileRef = F7CA212B25F1333200826ABB /* NCAccountRequest.swift */; }; + F7CA212D25F1333300826ABB /* NCAccountRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CA212B25F1333200826ABB /* NCAccountRequest.swift */; }; + F7CA212E25F1333300826ABB /* NCAccountRequest.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CA212C25F1333200826ABB /* NCAccountRequest.storyboard */; }; F7CB689A2541676B0050EC94 /* NCMore.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CB68992541676B0050EC94 /* NCMore.storyboard */; }; F7CBC1232BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7CBC1212BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.xib */; }; F7CBC1242BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7CBC1212BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.xib */; }; F7CBC1252BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CBC1222BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.swift */; }; F7CBC1262BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CBC1222BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.swift */; }; F7CCAB512ECF316700F8E68B /* NCCollectionViewCommon+SyncMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CCAB502ECF315F00F8E68B /* NCCollectionViewCommon+SyncMetadata.swift */; }; + F7CBC31C24F78E79004D3812 /* NCSortMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CBC31B24F78E79004D3812 /* NCSortMenu.swift */; }; F7CEE6002BA9A5C9003EFD89 /* NCTrashGridCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7CEE5FE2BA9A5C9003EFD89 /* NCTrashGridCell.xib */; }; F7CEE6012BA9A5C9003EFD89 /* NCTrashGridCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CEE5FF2BA9A5C9003EFD89 /* NCTrashGridCell.swift */; }; + F7CF067B2E0FF3990063AD04 /* NCAppStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF067A2E0FF38F0063AD04 /* NCAppStateManager.swift */; }; + F7CF067C2E0FF3990063AD04 /* NCAppStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF067A2E0FF38F0063AD04 /* NCAppStateManager.swift */; }; + F7CF067D2E0FF3990063AD04 /* NCAppStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF067A2E0FF38F0063AD04 /* NCAppStateManager.swift */; }; + F7CF067E2E0FF3990063AD04 /* NCAppStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF067A2E0FF38F0063AD04 /* NCAppStateManager.swift */; }; + F7CF067F2E0FF3990063AD04 /* NCAppStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF067A2E0FF38F0063AD04 /* NCAppStateManager.swift */; }; F7CF06802E0FF3990063AD04 /* NCAppStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF067A2E0FF38F0063AD04 /* NCAppStateManager.swift */; }; F7CF06832E1127460063AD04 /* NCManageDatabase+CreateMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF06822E11273F0063AD04 /* NCManageDatabase+CreateMetadata.swift */; }; F7CF06852E1127460063AD04 /* NCManageDatabase+CreateMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF06822E11273F0063AD04 /* NCManageDatabase+CreateMetadata.swift */; }; F7CF06862E1127460063AD04 /* NCManageDatabase+CreateMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF06822E11273F0063AD04 /* NCManageDatabase+CreateMetadata.swift */; }; F7CF06872E1127460063AD04 /* NCManageDatabase+CreateMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF06822E11273F0063AD04 /* NCManageDatabase+CreateMetadata.swift */; }; F7CF06882E1127460063AD04 /* NCManageDatabase+CreateMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF06822E11273F0063AD04 /* NCManageDatabase+CreateMetadata.swift */; }; + F7CF06812E0FF3990063AD04 /* NCAppStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF067A2E0FF38F0063AD04 /* NCAppStateManager.swift */; }; + F7CF06832E1127460063AD04 /* NCManageDatabase+Metadata+Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF06822E11273F0063AD04 /* NCManageDatabase+Metadata+Create.swift */; }; + F7CF06842E1127460063AD04 /* NCManageDatabase+Metadata+Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF06822E11273F0063AD04 /* NCManageDatabase+Metadata+Create.swift */; }; + F7CF06852E1127460063AD04 /* NCManageDatabase+Metadata+Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF06822E11273F0063AD04 /* NCManageDatabase+Metadata+Create.swift */; }; + F7CF06862E1127460063AD04 /* NCManageDatabase+Metadata+Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF06822E11273F0063AD04 /* NCManageDatabase+Metadata+Create.swift */; }; + F7CF06872E1127460063AD04 /* NCManageDatabase+Metadata+Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF06822E11273F0063AD04 /* NCManageDatabase+Metadata+Create.swift */; }; + F7CF06882E1127460063AD04 /* NCManageDatabase+Metadata+Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF06822E11273F0063AD04 /* NCManageDatabase+Metadata+Create.swift */; }; + F7CF06892E1127460063AD04 /* NCManageDatabase+Metadata+Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CF06822E11273F0063AD04 /* NCManageDatabase+Metadata+Create.swift */; }; F7D1612023CF19E30039EBBF /* NCViewerRichWorkspace.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7D1611F23CF19E30039EBBF /* NCViewerRichWorkspace.storyboard */; }; F7D1C4AC2C9484FD00EC6D44 /* NCMedia+CollectionViewDataSourcePrefetching.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D1C4AB2C9484FD00EC6D44 /* NCMedia+CollectionViewDataSourcePrefetching.swift */; }; F7D368DF2DAFE19E0037E7C6 /* NCActivityNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D368DE2DAFE19E0037E7C6 /* NCActivityNavigationController.swift */; }; @@ -870,8 +1109,6 @@ F7EDE514262DC2CD00414FE6 /* NCSelectCommandViewSelect+CreateFolder.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7EDE513262DC2CD00414FE6 /* NCSelectCommandViewSelect+CreateFolder.xib */; }; F7EDE51B262DD0C400414FE6 /* NCSelectCommandViewCopyMove.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7EDE51A262DD0C400414FE6 /* NCSelectCommandViewCopyMove.xib */; }; F7EE66AD2A20B226009AE765 /* UILabel+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7EE66AC2A20B226009AE765 /* UILabel+Extension.swift */; }; - F7EF2AEB2E43157B0081B2C9 /* NCNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7EF2AE92E43157B0081B2C9 /* NCNotification.swift */; }; - F7EF2AEC2E43157B0081B2C9 /* NCNotification.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7EF2AE82E43157B0081B2C9 /* NCNotification.storyboard */; }; F7EFA47825ADBA500083159A /* NCViewerProviderContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7EFA47725ADBA500083159A /* NCViewerProviderContextMenu.swift */; }; F7F1FB9D2E27CE7200C79E20 /* NCNetworking.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75A9EE523796C6F0044CFCE /* NCNetworking.swift */; }; F7F1FB9E2E27CE7200C79E20 /* NCNetworking.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75A9EE523796C6F0044CFCE /* NCNetworking.swift */; }; @@ -879,6 +1116,10 @@ F7F1FBAA2E27D14000C79E20 /* SwiftEntryKit in Frameworks */ = {isa = PBXBuildFile; productRef = F7F1FBA92E27D14000C79E20 /* SwiftEntryKit */; }; F7F1FBAE2E27D3A400C79E20 /* SwiftEntryKit in Frameworks */ = {isa = PBXBuildFile; productRef = F7F1FBAD2E27D3A400C79E20 /* SwiftEntryKit */; }; F7F1FBB02E27D3A800C79E20 /* Queuer in Frameworks */ = {isa = PBXBuildFile; productRef = F7F1FBAF2E27D3A800C79E20 /* Queuer */; }; + F7EFC0CD256BF8DD00461AAD /* NCUserStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7EFC0CC256BF8DD00461AAD /* NCUserStatus.swift */; }; + F7F3E58B2D3BB65600A32B14 /* NCNetworking+Recommendations.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F3E58A2D3BB65000A32B14 /* NCNetworking+Recommendations.swift */; }; + F7F3E58C2D3BB65600A32B14 /* NCNetworking+Recommendations.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F3E58A2D3BB65000A32B14 /* NCNetworking+Recommendations.swift */; }; + F7F3E58D2D3BB65600A32B14 /* NCNetworking+Recommendations.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F3E58A2D3BB65000A32B14 /* NCNetworking+Recommendations.swift */; }; F7F3E58E2D3BB65600A32B14 /* NCNetworking+Recommendations.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F3E58A2D3BB65000A32B14 /* NCNetworking+Recommendations.swift */; }; F7F4F10527ECDBDB008676F9 /* Inconsolata-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F0FD27ECDBDB008676F9 /* Inconsolata-SemiBold.ttf */; }; F7F4F10627ECDBDB008676F9 /* Inconsolata-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F0FE27ECDBDB008676F9 /* Inconsolata-Medium.ttf */; }; @@ -889,6 +1130,7 @@ F7F4F10B27ECDBDB008676F9 /* Inconsolata-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F10327ECDBDB008676F9 /* Inconsolata-Light.ttf */; }; F7F4F10C27ECDBDB008676F9 /* Inconsolata-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F10427ECDBDB008676F9 /* Inconsolata-Regular.ttf */; }; F7F563042E15762B00631A11 /* MigrationMultiDomains.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F562FF2E15761500631A11 /* MigrationMultiDomains.swift */; }; + F7F4F11227ECDC52008676F9 /* UIFont+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F4F11127ECDC52008676F9 /* UIFont+Extension.swift */; }; F7F623B52A5EF4D30022D3D4 /* Gzip in Frameworks */ = {isa = PBXBuildFile; productRef = F7F623B42A5EF4D30022D3D4 /* Gzip */; }; F7F623B72A5EFA0C0022D3D4 /* Gzip in Frameworks */ = {isa = PBXBuildFile; productRef = F7F623B62A5EFA0C0022D3D4 /* Gzip */; }; F7F878AE1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */; }; @@ -898,15 +1140,6 @@ F7FA80002C0F4F3B0072FC60 /* NCUploadAssetsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7FA7FFE2C0F4F3B0072FC60 /* NCUploadAssetsModel.swift */; }; F7FA80012C0F4F3B0072FC60 /* NCUploadAssetsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7FA7FFF2C0F4F3B0072FC60 /* NCUploadAssetsView.swift */; }; F7FAFD3A28BFA948000777FE /* NCNotification+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7FAFD3928BFA947000777FE /* NCNotification+Menu.swift */; }; - F7FDFF692E437E55000D7688 /* NCAccountRequest.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7FDFF512E437E55000D7688 /* NCAccountRequest.storyboard */; }; - F7FDFF6A2E437E55000D7688 /* NCShareAccounts.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7FDFF532E437E55000D7688 /* NCShareAccounts.storyboard */; }; - F7FDFF6B2E437E55000D7688 /* NCAccountRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7FDFF522E437E55000D7688 /* NCAccountRequest.swift */; }; - F7FDFF6C2E437E55000D7688 /* NCShareAccounts.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7FDFF542E437E55000D7688 /* NCShareAccounts.swift */; }; - F7FDFF6D2E437E55000D7688 /* NCAccountSettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7FDFF562E437E55000D7688 /* NCAccountSettingsModel.swift */; }; - F7FDFF6E2E437E55000D7688 /* NCAccountSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7FDFF572E437E55000D7688 /* NCAccountSettingsView.swift */; }; - F7FDFF6F2E437E55000D7688 /* NCAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7FDFF592E437E55000D7688 /* NCAccount.swift */; }; - F7FDFF702E437E55000D7688 /* NCAccountRequest.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7FDFF512E437E55000D7688 /* NCAccountRequest.storyboard */; }; - F7FDFF722E437E55000D7688 /* NCAccountRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7FDFF522E437E55000D7688 /* NCAccountRequest.swift */; }; F7FF2CB12842159500EBB7A1 /* NCSectionHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7FF2CB02842159500EBB7A1 /* NCSectionHeader.xib */; }; /* End PBXBuildFile section */ @@ -1103,6 +1336,7 @@ 3704EB2923D5A58400455C5B /* NCMenu.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCMenu.storyboard; sourceTree = ""; }; 370D26AE248A3D7A00121797 /* NCCellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCellProtocol.swift; sourceTree = ""; }; 371B5A2D23D0B04500FAFAE9 /* NCMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMenu.swift; sourceTree = ""; }; + 3781B9AF23DB2B7E006B4B1D /* AppDelegate+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Menu.swift"; sourceTree = ""; }; 8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Menu.swift"; sourceTree = ""; }; AA3C85E72D36B08C00F74F12 /* UITestBackend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestBackend.swift; sourceTree = ""; }; AA3C85EA2D36BBF400F74F12 /* OCSResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OCSResponse.swift; sourceTree = ""; }; @@ -1180,7 +1414,6 @@ AAA7BC2F2D3E3B83008F1A22 /* CapabilityResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapabilityResponse.swift; sourceTree = ""; }; AABD0C862D5F58C400F009E6 /* Server.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = Server.sh; sourceTree = ""; }; AABD0C892D5F67A200F009E6 /* XCUIElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCUIElement.swift; sourceTree = ""; }; - AABD0C9A2D5F73FA00F009E6 /* Placeholder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Placeholder.swift; sourceTree = ""; }; AACCAB522CFE041F00DA1786 /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/Intent.strings; sourceTree = ""; }; AACCAB532CFE041F00DA1786 /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/Localizable.strings; sourceTree = ""; }; AACCAB542CFE041F00DA1786 /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -1221,6 +1454,83 @@ AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extension.swift"; sourceTree = ""; }; AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCells.swift; sourceTree = ""; }; AFCE353827E5DE0400FEA6C2 /* Shareable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shareable.swift; sourceTree = ""; }; + B560B9502EF5597A00E55904 /* NCAccountRequest.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCAccountRequest.storyboard; sourceTree = ""; }; + B560B9512EF5597A00E55904 /* NCAccountRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAccountRequest.swift; sourceTree = ""; }; + B560B9522EF5597A00E55904 /* NCShareAccounts.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCShareAccounts.storyboard; sourceTree = ""; }; + B560B9532EF5597A00E55904 /* NCShareAccounts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareAccounts.swift; sourceTree = ""; }; + B560B9552EF5597A00E55904 /* NCAccountSettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAccountSettingsModel.swift; sourceTree = ""; }; + B560B9562EF5597A00E55904 /* NCAccountSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAccountSettingsView.swift; sourceTree = ""; }; + B560B9582EF5597A00E55904 /* NCAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAccount.swift; sourceTree = ""; }; + B5BEBD272E93AD540002C9E5 /* File_Provider_Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = File_Provider_Extension.entitlements; sourceTree = ""; }; + B5BEBD282E93AD540002C9E5 /* File_Provider_Extension.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = File_Provider_Extension.plist; sourceTree = ""; }; + B5BEBD292E93AD540002C9E5 /* iOSClient.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = iOSClient.entitlements; sourceTree = ""; }; + B5BEBD2A2E93AD540002C9E5 /* iOSClient.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = iOSClient.plist; sourceTree = ""; }; + B5BEBD2B2E93AD540002C9E5 /* Notification_Service_Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Notification_Service_Extension.entitlements; sourceTree = ""; }; + B5BEBD2C2E93AD540002C9E5 /* Notification_Service_Extension.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Notification_Service_Extension.plist; sourceTree = ""; }; + B5BEBD2D2E93AD540002C9E5 /* Share.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Share.entitlements; sourceTree = ""; }; + B5BEBD2E2E93AD540002C9E5 /* Share.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Share.plist; sourceTree = ""; }; + B5BEBD4F2E93AE1C0002C9E5 /* BaseXCTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseXCTestCase.swift; sourceTree = ""; }; + B5BEBD502E93AE1C0002C9E5 /* TestConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestConstants.swift; sourceTree = ""; }; + B5BEBD582E93AE2F0002C9E5 /* BaseIntegrationXCTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseIntegrationXCTestCase.swift; sourceTree = ""; }; + B5BEBD592E93AE2F0002C9E5 /* FilesIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesIntegrationTests.swift; sourceTree = ""; }; + B5BEBD5A2E93AE2F0002C9E5 /* LoginIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginIntegrationTests.swift; sourceTree = ""; }; + B5BEBD5E2E93AE4B0002C9E5 /* AssetUploadTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetUploadTest.swift; sourceTree = ""; }; + B5BEBD5F2E93AE4B0002C9E5 /* AudioUploadTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioUploadTests.swift; sourceTree = ""; }; + B5BEBD602E93AE4B0002C9E5 /* CollaboraTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollaboraTestCase.swift; sourceTree = ""; }; + B5BEBD612E93AE4B0002C9E5 /* E2EETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = E2EETests.swift; sourceTree = ""; }; + B5BEBD622E93AE4B0002C9E5 /* MoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreTests.swift; sourceTree = ""; }; + B5BEBD632E93AE4B0002C9E5 /* MoveAndCopyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveAndCopyTests.swift; sourceTree = ""; }; + B5BEBD642E93AE4B0002C9E5 /* NCNotificationText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNotificationText.swift; sourceTree = ""; }; + B5BEBD652E93AE4B0002C9E5 /* OnboardingTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTestCase.swift; sourceTree = ""; }; + B5BEBD662E93AE4B0002C9E5 /* PrivacyPolicyTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyPolicyTest.swift; sourceTree = ""; }; + B5BEBD672E93AE4B0002C9E5 /* RenameFileTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenameFileTests.swift; sourceTree = ""; }; + B5BEBD682E93AE4B0002C9E5 /* ScanTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanTests.swift; sourceTree = ""; }; + B5BEBD692E93AE4B0002C9E5 /* SettingsTestCases.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTestCases.swift; sourceTree = ""; }; + B5BEBD6A2E93AE4B0002C9E5 /* SharingTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingTest.swift; sourceTree = ""; }; + B5BEBD782E93AEA30002C9E5 /* MoEngageAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoEngageAnalytics.swift; sourceTree = ""; }; + B5BEBD7A2E93AEA30002C9E5 /* AnalyticsHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsHelper.swift; sourceTree = ""; }; + B5BEBD7B2E93AEA30002C9E5 /* AnalyticsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsService.swift; sourceTree = ""; }; + B5BEBD922E93AED80002C9E5 /* AppUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdater.swift; sourceTree = ""; }; + B5BEBD9B2E93AF010002C9E5 /* AppUtility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUtility.swift; sourceTree = ""; }; + B5BEBD9C2E93AF010002C9E5 /* NCEmptyDataSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEmptyDataSet.swift; sourceTree = ""; }; + B5BEBD9D2E93AF010002C9E5 /* NCEmptyView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCEmptyView.xib; sourceTree = ""; }; + B5BEBD9F2E93AF010002C9E5 /* AdjustHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AdjustHelper.h; sourceTree = ""; }; + B5BEBDA02E93AF010002C9E5 /* AdjustHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AdjustHelper.m; sourceTree = ""; }; + B5BEBDA12E93AF010002C9E5 /* TealiumHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TealiumHelper.swift; sourceTree = ""; }; + B5BEBDC62E93AF7E0002C9E5 /* NCLoginWeb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCLoginWeb.swift; sourceTree = ""; }; + B5BEBDC82E93AFF10002C9E5 /* NCSelectableNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSelectableNavigationView.swift; sourceTree = ""; }; + B5BEBDCA2E93B0210002C9E5 /* NCSectionHeaderMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSectionHeaderMenu.swift; sourceTree = ""; }; + B5BEBDCB2E93B0210002C9E5 /* NCSectionHeaderMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCSectionHeaderMenu.xib; sourceTree = ""; }; + B5BEBDD02E93B2450002C9E5 /* NCCreateFormUploadDocuments.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCCreateFormUploadDocuments.storyboard; sourceTree = ""; }; + B5BEBDD12E93B2450002C9E5 /* NCCreateFormUploadDocuments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCreateFormUploadDocuments.swift; sourceTree = ""; }; + B5BEBDD22E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCCreateFormUploadVoiceNote.storyboard; sourceTree = ""; }; + B5BEBDD32E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCreateFormUploadVoiceNote.swift; sourceTree = ""; }; + B5BEBDD42E93B2450002C9E5 /* TextTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextTableViewCell.swift; sourceTree = ""; }; + B5BEBDD52E93B2450002C9E5 /* TextTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TextTableViewCell.xib; sourceTree = ""; }; + B5BEBDE22E93BD6F0002C9E5 /* NCMediaCommandView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCMediaCommandView.xib; sourceTree = ""; }; + B5BEBDE42E93BDB40002C9E5 /* FolderPathCustomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderPathCustomCell.swift; sourceTree = ""; }; + B5BEBDE52E93BDB40002C9E5 /* FolderPathCustomCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FolderPathCustomCell.xib; sourceTree = ""; }; + B5BEBDE62E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCreateDocumentCustomTextField.swift; sourceTree = ""; }; + B5BEBDE72E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCCreateDocumentCustomTextField.xib; sourceTree = ""; }; + B5BEBE052E93BE0C0002C9E5 /* NCCreateFormUploadScanDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCreateFormUploadScanDocument.swift; sourceTree = ""; }; + B5BEBE072E93BE200002C9E5 /* FileNameInputTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileNameInputTextField.swift; sourceTree = ""; }; + B5BEBE082E93BE200002C9E5 /* FileNameInputTextField.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FileNameInputTextField.xib; sourceTree = ""; }; + B5BEBE092E93BE200002C9E5 /* JPGImageSaveSwitchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JPGImageSaveSwitchView.swift; sourceTree = ""; }; + B5BEBE0A2E93BE200002C9E5 /* JPGImageSaveSwitchView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = JPGImageSaveSwitchView.xib; sourceTree = ""; }; + B5BEBE0B2E93BE200002C9E5 /* PasswordInputField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordInputField.swift; sourceTree = ""; }; + B5BEBE0C2E93BE200002C9E5 /* PasswordInputField.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PasswordInputField.xib; sourceTree = ""; }; + B5BEBE0D2E93BE200002C9E5 /* PdfWithOcrSwitchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PdfWithOcrSwitchView.swift; sourceTree = ""; }; + B5BEBE0E2E93BE200002C9E5 /* PdfWithOcrSwitchView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PdfWithOcrSwitchView.xib; sourceTree = ""; }; + B5BEBE0F2E93BE200002C9E5 /* PdfWithoutOcrSwitchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PdfWithoutOcrSwitchView.swift; sourceTree = ""; }; + B5BEBE102E93BE200002C9E5 /* PdfWithoutOcrSwitchView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PdfWithoutOcrSwitchView.xib; sourceTree = ""; }; + B5BEBE112E93BE200002C9E5 /* PNGImageSaveSwitchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNGImageSaveSwitchView.swift; sourceTree = ""; }; + B5BEBE122E93BE200002C9E5 /* PNGImageSaveSwitchView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PNGImageSaveSwitchView.xib; sourceTree = ""; }; + B5BEBE132E93BE200002C9E5 /* ScanDocumentPathView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanDocumentPathView.swift; sourceTree = ""; }; + B5BEBE142E93BE200002C9E5 /* ScanDocumentPathView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ScanDocumentPathView.xib; sourceTree = ""; }; + B5BEBE152E93BE200002C9E5 /* SetPDFPasswordSwitchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetPDFPasswordSwitchView.swift; sourceTree = ""; }; + B5BEBE162E93BE200002C9E5 /* SetPDFPasswordSwitchView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SetPDFPasswordSwitchView.xib; sourceTree = ""; }; + B5BEBE172E93BE200002C9E5 /* TextFileWithOcrSwitchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFileWithOcrSwitchView.swift; sourceTree = ""; }; + B5BEBE182E93BE200002C9E5 /* TextFileWithOcrSwitchView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TextFileWithOcrSwitchView.xib; sourceTree = ""; }; C0046CDA2A17B98400D87C9D /* NextcloudUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C04E2F202A17BB4D001BAD85 /* NextcloudIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityTableViewCell.swift; sourceTree = ""; }; @@ -1241,11 +1551,9 @@ F34E1ADA2ECC842200FA10C3 /* NCStatusMessageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCStatusMessageModel.swift; sourceTree = ""; }; F351D1A52D0AF24A00930F94 /* PHAssetCollection+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PHAssetCollection+Extension.swift"; sourceTree = ""; }; F359D8662A7D03420023F405 /* NCUtility+Exif.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCUtility+Exif.swift"; sourceTree = ""; }; - F36C514D2E89393C0097E5F7 /* UIView+BlurVibrancy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+BlurVibrancy.swift"; sourceTree = ""; }; - F36E64F62B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBarDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCCollectionViewCommon+SelectTabBarDelegate.swift"; sourceTree = ""; }; + F36E64F62B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCCollectionViewCommon+SelectTabBar.swift"; sourceTree = ""; }; F37208742BAB4AB0006B5430 /* TestConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestConstants.swift; sourceTree = ""; }; F3754A7C2CF87D600009312E /* SetupPasscodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupPasscodeView.swift; sourceTree = ""; }; - F376A3732E5CC5FF0067EE25 /* ContextMenuActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuActions.swift; sourceTree = ""; }; F389C9F42CEE383300049762 /* SelectAlbumView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectAlbumView.swift; sourceTree = ""; }; F38F71242B6BBDC300473CDC /* NCCollectionViewCommonSelectTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCollectionViewCommonSelectTabBar.swift; sourceTree = ""; }; F39170A82CB8201B006127BC /* FileAutoRenamer+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileAutoRenamer+Extensions.swift"; sourceTree = ""; }; @@ -1265,7 +1573,6 @@ F3CA337C2D0B2B6A00672333 /* AlbumModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumModel.swift; sourceTree = ""; }; F3E173AF2C9AF637006D177A /* ScreenAwakeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenAwakeManager.swift; sourceTree = ""; }; F3E173BF2C9B1067006D177A /* AwakeMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AwakeMode.swift; sourceTree = ""; }; - F3F442ED2DDE292600FD701F /* NCMetadataPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMetadataPermissions.swift; sourceTree = ""; }; F700222B1EC479840080073F /* Custom.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Custom.xcassets; sourceTree = ""; }; F700510022DF63AC003A3356 /* NCShare.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCShare.storyboard; sourceTree = ""; }; F700510422DF6A89003A3356 /* NCShare.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShare.swift; sourceTree = ""; }; @@ -1302,7 +1609,7 @@ F70D8D8024A4A9BF000A5756 /* NCNetworkingProcess.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNetworkingProcess.swift; sourceTree = ""; }; F70F96AF2874394B006C8379 /* Nextcloud-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Nextcloud-Bridging-Header.h"; sourceTree = ""; }; F710D1F42405770F00A6033D /* NCViewerPDF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCViewerPDF.swift; sourceTree = ""; }; - F710D2012405826100A6033D /* NCViewerContextMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCViewerContextMenu.swift; sourceTree = ""; }; + F710D2012405826100A6033D /* NCViewer+Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCViewer+Menu.swift"; sourceTree = ""; }; F711A4DB2AF92CAD00095DD8 /* NCUtility+Date.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCUtility+Date.swift"; sourceTree = ""; }; F7132C6B2D085AD200B42D6A /* NCTermOfServiceModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTermOfServiceModel.swift; sourceTree = ""; }; F7132C6C2D085AD200B42D6A /* NCTermOfServiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTermOfServiceView.swift; sourceTree = ""; }; @@ -1320,7 +1627,6 @@ F717402C24F699A5000C87D5 /* NCFavorite.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCFavorite.swift; sourceTree = ""; }; F718C24D254D507B00C5C256 /* NCViewerMediaDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCViewerMediaDetailView.swift; sourceTree = ""; }; F718E2572DF2D5C3004038AF /* NCBackgroundLocationUploadManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCBackgroundLocationUploadManager.swift; sourceTree = ""; }; - F71916102E2901E800E13E96 /* NCNetworking+Upload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCNetworking+Upload.swift"; sourceTree = ""; }; F719D9DF288D37A300762E33 /* NCColorPicker.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCColorPicker.storyboard; sourceTree = ""; }; F719D9E1288D396100762E33 /* NCColorPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCColorPicker.swift; sourceTree = ""; }; F71CD6C92930D7B1006C95C1 /* NCApplicationHandle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCApplicationHandle.swift; sourceTree = ""; }; @@ -1332,7 +1638,7 @@ F723985B253C95CE00257F49 /* NCViewerRichdocument.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCViewerRichdocument.storyboard; sourceTree = ""; }; F723B3DC22FC6D1C00301EFE /* NCShareCommentsCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareCommentsCell.xib; sourceTree = ""; }; F72408322B8A27C900F128E2 /* NCMedia+Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCMedia+Command.swift"; sourceTree = ""; }; - F724377A2C10B83E00C7C68D /* NCSharePermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSharePermissions.swift; sourceTree = ""; }; + F724377A2C10B83E00C7C68D /* NCPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCPermissions.swift; sourceTree = ""; }; F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreadSafeDictionary.swift; sourceTree = ""; }; F72685E827C78E490019EF5E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; F72944F12A84246400246839 /* NCEndToEndMetadataV20.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEndToEndMetadataV20.swift; sourceTree = ""; }; @@ -1350,6 +1656,7 @@ F7320934201B812F008A0888 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = ""; }; F732093B201B81E4008A0888 /* es-419 */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-419"; path = "es-419.lproj/Localizable.strings"; sourceTree = ""; }; F7327E1F2B73A42F00A462C7 /* NCNetworking+Download.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCNetworking+Download.swift"; sourceTree = ""; }; + F7327E272B73A53400A462C7 /* NCNetworking+Upload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCNetworking+Upload.swift"; sourceTree = ""; }; F7327E2F2B73A86700A462C7 /* NCNetworking+WebDAV.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCNetworking+WebDAV.swift"; sourceTree = ""; }; F7327E342B73AEDE00A462C7 /* NCNetworking+LivePhoto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCNetworking+LivePhoto.swift"; sourceTree = ""; }; F732D23227CF8AED000B0F1B /* NCPlayerToolBar.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCPlayerToolBar.xib; sourceTree = ""; }; @@ -1363,6 +1670,8 @@ F7381EDA218218C9000B1560 /* NCOffline.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCOffline.swift; sourceTree = ""; }; F7381EDE218218C9000B1560 /* NCOffline.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCOffline.storyboard; sourceTree = ""; }; F7386E452DA90E02009A00F6 /* NCAppVersionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAppVersionManager.swift; sourceTree = ""; }; + F73B42292476764F00A30FD3 /* NCNotification.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = NCNotification.storyboard; path = Notification/NCNotification.storyboard; sourceTree = ""; }; + F73B422A2476764F00A30FD3 /* NCNotification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NCNotification.swift; path = Notification/NCNotification.swift; sourceTree = ""; }; F73CB3B122E072A000AD728E /* NCShareHeaderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCShareHeaderView.xib; sourceTree = ""; }; F73CB5771ED46807005F2A5A /* NCBridgeSwift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NCBridgeSwift.h; sourceTree = ""; }; F73D11F9253C5F4800DF9BEC /* NCViewerNextcloudText.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCViewerNextcloudText.storyboard; sourceTree = ""; }; @@ -1376,7 +1685,6 @@ F7411C532D7B26C600F57358 /* NCNetworking+ServerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCNetworking+ServerError.swift"; sourceTree = ""; }; F741C2232B6B9FD600E849BB /* NCMediaSelectTabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCMediaSelectTabBar.swift; sourceTree = ""; }; F74230F22C79B57200CA1ACA /* NCNetworking+Task.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCNetworking+Task.swift"; sourceTree = ""; }; - F743C89D2E5B2595000173A9 /* UIScene+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScene+Extension.swift"; sourceTree = ""; }; F745B252222D88AE00346520 /* NCLoginQRCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCLoginQRCode.swift; sourceTree = ""; }; F747EB0C2C4AC1FF00F959A8 /* NCCollectionViewCommon+CollectionViewDelegateFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCCollectionViewCommon+CollectionViewDelegateFlowLayout.swift"; sourceTree = ""; }; F749B649297B0CBB00087535 /* NCManageDatabase+Share.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Share.swift"; sourceTree = ""; }; @@ -1390,7 +1698,6 @@ F7501C312212E57400FB1415 /* NCMedia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCMedia.swift; sourceTree = ""; }; F751247A2C42919C00E63DB8 /* NCPhotoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCPhotoCell.swift; sourceTree = ""; }; F751247B2C42919C00E63DB8 /* NCPhotoCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCPhotoCell.xib; sourceTree = ""; }; - F752BA042E58C05200616A26 /* Maintenance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Maintenance.swift; sourceTree = ""; }; F753701822723D620041C76C /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = gl; path = gl.lproj/Localizable.strings; sourceTree = ""; }; F753701922723E0D0041C76C /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = ""; }; F753701A22723EC80041C76C /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; @@ -1438,7 +1745,7 @@ F768820F2C0DD1E7001CF441 /* NCEndToEndInitialize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCEndToEndInitialize.swift; sourceTree = ""; }; F76882102C0DD1E7001CF441 /* NCManageE2EEModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCManageE2EEModel.swift; sourceTree = ""; }; F76882112C0DD1E7001CF441 /* NCSettingsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCSettingsModel.swift; sourceTree = ""; }; - F76882132C0DD1E7001CF441 /* NCPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCPreferences.swift; sourceTree = ""; }; + F76882132C0DD1E7001CF441 /* NCKeychain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCKeychain.swift; sourceTree = ""; }; F76882142C0DD1E7001CF441 /* Acknowledgements.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Acknowledgements.rtf; sourceTree = ""; }; F76882152C0DD1E7001CF441 /* NCSettingsBundleHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCSettingsBundleHelper.swift; sourceTree = ""; }; F76882192C0DD1E7001CF441 /* NCFileNameModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCFileNameModel.swift; sourceTree = ""; }; @@ -1506,7 +1813,6 @@ F77C3F5A2D9BF8B500F3C471 /* UITabBar+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITabBar+Extension.swift"; sourceTree = ""; }; F77C97382953131000FDDD09 /* NCCameraRoll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCameraRoll.swift; sourceTree = ""; }; F77DD6A72C5CC093009448FB /* NCSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSession.swift; sourceTree = ""; }; - F77E8C1E2E79717D00EAE68F /* NCManageDatabase+LivePhoto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+LivePhoto.swift"; sourceTree = ""; }; F77ED59028C9CE9D00E24ED0 /* ToolbarData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarData.swift; sourceTree = ""; }; F77ED59228C9CEA000E24ED0 /* ToolbarWidgetProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarWidgetProvider.swift; sourceTree = ""; }; F77ED59428C9CEA300E24ED0 /* ToolbarWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarWidgetView.swift; sourceTree = ""; }; @@ -1544,7 +1850,6 @@ F79131C728AFB86E00577277 /* eu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = eu; path = eu.lproj/InfoPlist.strings; sourceTree = ""; }; F794E13C2BBBFF2E003693D7 /* NCMainTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMainTabBarController.swift; sourceTree = ""; }; F794E13E2BBC0F70003693D7 /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - F79699E62E689F68000EC82A /* NCMediaNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMediaNavigationController.swift; sourceTree = ""; }; F799DF812C4B7DCC003410B5 /* NCSectionFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSectionFooter.swift; sourceTree = ""; }; F799DF842C4B7E56003410B5 /* NCSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSectionHeader.swift; sourceTree = ""; }; F799DF872C4B83CC003410B5 /* NCCollectionViewCommon+EasyTipView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCCollectionViewCommon+EasyTipView.swift"; sourceTree = ""; }; @@ -1686,6 +1991,8 @@ F7C9739428F17131002C43E2 /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; F7C9B91C2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+SecurityGuard.swift"; sourceTree = ""; }; F7CADEFA2EA1591D0057849E /* NCMetadataTranfersSuccess.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMetadataTranfersSuccess.swift; sourceTree = ""; }; + F7CA212B25F1333200826ABB /* NCAccountRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCAccountRequest.swift; sourceTree = ""; }; + F7CA212C25F1333200826ABB /* NCAccountRequest.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCAccountRequest.storyboard; sourceTree = ""; }; F7CB68992541676B0050EC94 /* NCMore.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCMore.storyboard; sourceTree = ""; }; F7CBC1212BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCSectionFirstHeaderEmptyData.xib; sourceTree = ""; }; F7CBC1222BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCSectionFirstHeaderEmptyData.swift; sourceTree = ""; }; @@ -1697,6 +2004,7 @@ F7CEE5FF2BA9A5C9003EFD89 /* NCTrashGridCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCTrashGridCell.swift; sourceTree = ""; }; F7CF067A2E0FF38F0063AD04 /* NCAppStateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAppStateManager.swift; sourceTree = ""; }; F7CF06822E11273F0063AD04 /* NCManageDatabase+CreateMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+CreateMetadata.swift"; sourceTree = ""; }; + F7CF06822E11273F0063AD04 /* NCManageDatabase+Metadata+Create.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Metadata+Create.swift"; sourceTree = ""; }; F7D1611F23CF19E30039EBBF /* NCViewerRichWorkspace.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCViewerRichWorkspace.storyboard; sourceTree = ""; }; F7D1C4AB2C9484FD00EC6D44 /* NCMedia+CollectionViewDataSourcePrefetching.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCMedia+CollectionViewDataSourcePrefetching.swift"; sourceTree = ""; }; F7D368DE2DAFE19E0037E7C6 /* NCActivityNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityNavigationController.swift; sourceTree = ""; }; @@ -1764,8 +2072,6 @@ F7EDE513262DC2CD00414FE6 /* NCSelectCommandViewSelect+CreateFolder.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "NCSelectCommandViewSelect+CreateFolder.xib"; sourceTree = ""; }; F7EDE51A262DD0C400414FE6 /* NCSelectCommandViewCopyMove.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCSelectCommandViewCopyMove.xib; sourceTree = ""; }; F7EE66AC2A20B226009AE765 /* UILabel+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Extension.swift"; sourceTree = ""; }; - F7EF2AE82E43157B0081B2C9 /* NCNotification.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCNotification.storyboard; sourceTree = ""; }; - F7EF2AE92E43157B0081B2C9 /* NCNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNotification.swift; sourceTree = ""; }; F7EFA47725ADBA500083159A /* NCViewerProviderContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCViewerProviderContextMenu.swift; sourceTree = ""; }; F7F3E58A2D3BB65000A32B14 /* NCNetworking+Recommendations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCNetworking+Recommendations.swift"; sourceTree = ""; }; F7F4F0FD27ECDBDB008676F9 /* Inconsolata-SemiBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Inconsolata-SemiBold.ttf"; sourceTree = ""; }; @@ -1777,6 +2083,7 @@ F7F4F10327ECDBDB008676F9 /* Inconsolata-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Inconsolata-Light.ttf"; sourceTree = ""; }; F7F4F10427ECDBDB008676F9 /* Inconsolata-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Inconsolata-Regular.ttf"; sourceTree = ""; }; F7F562FF2E15761500631A11 /* MigrationMultiDomains.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationMultiDomains.swift; sourceTree = ""; }; + F7F4F11127ECDC52008676F9 /* UIFont+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIFont+Extension.swift"; sourceTree = ""; }; F7F67BB81A24D27800EE80DA /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEndToEndMetadata.swift; sourceTree = ""; }; F7F9D1BA25397CE000D9BFF5 /* NCViewer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCViewer.swift; sourceTree = ""; }; @@ -1784,13 +2091,6 @@ F7FA7FFE2C0F4F3B0072FC60 /* NCUploadAssetsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCUploadAssetsModel.swift; sourceTree = ""; }; F7FA7FFF2C0F4F3B0072FC60 /* NCUploadAssetsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCUploadAssetsView.swift; sourceTree = ""; }; F7FAFD3928BFA947000777FE /* NCNotification+Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCNotification+Menu.swift"; sourceTree = ""; }; - F7FDFF512E437E55000D7688 /* NCAccountRequest.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCAccountRequest.storyboard; sourceTree = ""; }; - F7FDFF522E437E55000D7688 /* NCAccountRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAccountRequest.swift; sourceTree = ""; }; - F7FDFF532E437E55000D7688 /* NCShareAccounts.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCShareAccounts.storyboard; sourceTree = ""; }; - F7FDFF542E437E55000D7688 /* NCShareAccounts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareAccounts.swift; sourceTree = ""; }; - F7FDFF562E437E55000D7688 /* NCAccountSettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAccountSettingsModel.swift; sourceTree = ""; }; - F7FDFF572E437E55000D7688 /* NCAccountSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAccountSettingsView.swift; sourceTree = ""; }; - F7FDFF592E437E55000D7688 /* NCAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAccount.swift; sourceTree = ""; }; F7FF2CB02842159500EBB7A1 /* NCSectionHeader.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCSectionHeader.xib; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1804,9 +2104,7 @@ buildActionMask = 2147483647; files = ( F33EE6ED2BF4C03800CA1A51 /* NIOSSL in Frameworks */, - F7F1FBB02E27D3A800C79E20 /* Queuer in Frameworks */, F72AD71128C24BBB006CB92D /* NextcloudKit in Frameworks */, - F7F1FBAE2E27D3A400C79E20 /* SwiftEntryKit in Frameworks */, F710FC88277B7D3F00AA9FBF /* RealmSwift in Frameworks */, F760DE0F2AE66EE60027D78A /* KeychainAccess in Frameworks */, ); @@ -1864,6 +2162,8 @@ buildActionMask = 2147483647; files = ( F7490E8B29882CE4009DCE94 /* NextcloudKit in Frameworks */, + F7490E8929882CC8009DCE94 /* SwiftEntryKit in Frameworks */, + F33EE6EB2BF4C03200CA1A51 /* NIOSSL in Frameworks */, F7490E7229882BB4009DCE94 /* RealmSwift in Frameworks */, F760DE0D2AE66EDF0027D78A /* KeychainAccess in Frameworks */, ); @@ -1959,9 +2259,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - F7F1FBA82E27D13700C79E20 /* Queuer in Frameworks */, F7A8D72828F17728008BBE1C /* RealmSwift in Frameworks */, - F7F1FBAA2E27D14000C79E20 /* SwiftEntryKit in Frameworks */, F7A8D72428F1771B008BBE1C /* NextcloudKit in Frameworks */, F33EE6E52BF4C02000CA1A51 /* NIOSSL in Frameworks */, F760DE072AE66EC70027D78A /* KeychainAccess in Frameworks */, @@ -1983,18 +2281,19 @@ 371B5A2F23D0B04B00FAFAE9 /* Menu */ = { isa = PBXGroup; children = ( - F376A3732E5CC5FF0067EE25 /* ContextMenuActions.swift */, - F77A697C250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift */, - F78C6FDD296D677300C952C3 /* NCContextMenu.swift */, 3704EB2923D5A58400455C5B /* NCMenu.storyboard */, 371B5A2D23D0B04500FAFAE9 /* NCMenu.swift */, - AF935066276B84E700BD078F /* NCMenu+FloatingPanel.swift */, AF68326927BE65A90010BF0B /* NCMenuAction.swift */, F7FAFD3928BFA947000777FE /* NCNotification+Menu.swift */, - AF93471127E2341B002537EE /* NCShare+Menu.swift */, - F75D19E225EFE09000D74598 /* NCTrash+Menu.swift */, - F710D2012405826100A6033D /* NCViewerContextMenu.swift */, + AF935066276B84E700BD078F /* NCMenu+FloatingPanel.swift */, + 3781B9AF23DB2B7E006B4B1D /* AppDelegate+Menu.swift */, 8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */, + F77A697C250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift */, + F75D19E225EFE09000D74598 /* NCTrash+Menu.swift */, + AF93471127E2341B002537EE /* NCShare+Menu.swift */, + F710D2012405826100A6033D /* NCViewer+Menu.swift */, + F78C6FDD296D677300C952C3 /* NCContextMenu.swift */, + F7A560412AE1593700BE8FD6 /* NCOperationSaveLivePhoto.swift */, ); path = Menu; sourceTree = ""; @@ -2023,6 +2322,19 @@ AA52EB442D42AC500089C348 /* NextcloudUnitTests */ = { isa = PBXGroup; children = ( + B5BEBD5E2E93AE4B0002C9E5 /* AssetUploadTest.swift */, + B5BEBD5F2E93AE4B0002C9E5 /* AudioUploadTests.swift */, + B5BEBD602E93AE4B0002C9E5 /* CollaboraTestCase.swift */, + B5BEBD612E93AE4B0002C9E5 /* E2EETests.swift */, + B5BEBD622E93AE4B0002C9E5 /* MoreTests.swift */, + B5BEBD632E93AE4B0002C9E5 /* MoveAndCopyTests.swift */, + B5BEBD642E93AE4B0002C9E5 /* NCNotificationText.swift */, + B5BEBD652E93AE4B0002C9E5 /* OnboardingTestCase.swift */, + B5BEBD662E93AE4B0002C9E5 /* PrivacyPolicyTest.swift */, + B5BEBD672E93AE4B0002C9E5 /* RenameFileTests.swift */, + B5BEBD682E93AE4B0002C9E5 /* ScanTests.swift */, + B5BEBD692E93AE4B0002C9E5 /* SettingsTestCases.swift */, + B5BEBD6A2E93AE4B0002C9E5 /* SharingTest.swift */, AA52EB452D42AC5A0089C348 /* Placeholder.swift */, ); path = NextcloudUnitTests; @@ -2062,6 +2374,126 @@ path = Advanced; sourceTree = ""; }; + B560B9542EF5597A00E55904 /* Account Request */ = { + isa = PBXGroup; + children = ( + B560B9502EF5597A00E55904 /* NCAccountRequest.storyboard */, + B560B9512EF5597A00E55904 /* NCAccountRequest.swift */, + B560B9522EF5597A00E55904 /* NCShareAccounts.storyboard */, + B560B9532EF5597A00E55904 /* NCShareAccounts.swift */, + ); + path = "Account Request"; + sourceTree = ""; + }; + B560B9572EF5597A00E55904 /* Account Settings */ = { + isa = PBXGroup; + children = ( + B560B9552EF5597A00E55904 /* NCAccountSettingsModel.swift */, + B560B9562EF5597A00E55904 /* NCAccountSettingsView.swift */, + ); + path = "Account Settings"; + sourceTree = ""; + }; + B560B9592EF5597A00E55904 /* Account */ = { + isa = PBXGroup; + children = ( + B560B9542EF5597A00E55904 /* Account Request */, + B560B9572EF5597A00E55904 /* Account Settings */, + B560B9582EF5597A00E55904 /* NCAccount.swift */, + ); + path = Account; + sourceTree = ""; + }; + B5BEBD512E93AE1C0002C9E5 /* Common */ = { + isa = PBXGroup; + children = ( + B5BEBD4F2E93AE1C0002C9E5 /* BaseXCTestCase.swift */, + B5BEBD502E93AE1C0002C9E5 /* TestConstants.swift */, + ); + path = Common; + sourceTree = ""; + }; + B5BEBD792E93AEA30002C9E5 /* MoEngage */ = { + isa = PBXGroup; + children = ( + B5BEBD782E93AEA30002C9E5 /* MoEngageAnalytics.swift */, + ); + path = MoEngage; + sourceTree = ""; + }; + B5BEBD7C2E93AEA30002C9E5 /* Analytics */ = { + isa = PBXGroup; + children = ( + B5BEBD792E93AEA30002C9E5 /* MoEngage */, + B5BEBD7A2E93AEA30002C9E5 /* AnalyticsHelper.swift */, + B5BEBD7B2E93AEA30002C9E5 /* AnalyticsService.swift */, + ); + path = Analytics; + sourceTree = ""; + }; + B5BEBD932E93AED80002C9E5 /* AppUpdate */ = { + isa = PBXGroup; + children = ( + B5BEBD922E93AED80002C9E5 /* AppUpdater.swift */, + ); + path = AppUpdate; + sourceTree = ""; + }; + B5BEBD9E2E93AF010002C9E5 /* EmptyView */ = { + isa = PBXGroup; + children = ( + B5BEBD9C2E93AF010002C9E5 /* NCEmptyDataSet.swift */, + B5BEBD9D2E93AF010002C9E5 /* NCEmptyView.xib */, + ); + path = EmptyView; + sourceTree = ""; + }; + B5BEBDA22E93AF010002C9E5 /* Helper */ = { + isa = PBXGroup; + children = ( + B5BEBD9F2E93AF010002C9E5 /* AdjustHelper.h */, + B5BEBDA02E93AF010002C9E5 /* AdjustHelper.m */, + B5BEBDA12E93AF010002C9E5 /* TealiumHelper.swift */, + ); + path = Helper; + sourceTree = ""; + }; + B5BEBDE82E93BDB40002C9E5 /* NMC Custom Views */ = { + isa = PBXGroup; + children = ( + B5BEBDE42E93BDB40002C9E5 /* FolderPathCustomCell.swift */, + B5BEBDE52E93BDB40002C9E5 /* FolderPathCustomCell.xib */, + B5BEBDE62E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift */, + B5BEBDE72E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib */, + ); + path = "NMC Custom Views"; + sourceTree = ""; + }; + B5BEBE192E93BE200002C9E5 /* NMC Views */ = { + isa = PBXGroup; + children = ( + B5BEBE072E93BE200002C9E5 /* FileNameInputTextField.swift */, + B5BEBE082E93BE200002C9E5 /* FileNameInputTextField.xib */, + B5BEBE092E93BE200002C9E5 /* JPGImageSaveSwitchView.swift */, + B5BEBE0A2E93BE200002C9E5 /* JPGImageSaveSwitchView.xib */, + B5BEBE0B2E93BE200002C9E5 /* PasswordInputField.swift */, + B5BEBE0C2E93BE200002C9E5 /* PasswordInputField.xib */, + B5BEBE0D2E93BE200002C9E5 /* PdfWithOcrSwitchView.swift */, + B5BEBE0E2E93BE200002C9E5 /* PdfWithOcrSwitchView.xib */, + B5BEBE0F2E93BE200002C9E5 /* PdfWithoutOcrSwitchView.swift */, + B5BEBE102E93BE200002C9E5 /* PdfWithoutOcrSwitchView.xib */, + B5BEBE112E93BE200002C9E5 /* PNGImageSaveSwitchView.swift */, + B5BEBE122E93BE200002C9E5 /* PNGImageSaveSwitchView.xib */, + B5BEBE132E93BE200002C9E5 /* ScanDocumentPathView.swift */, + B5BEBE142E93BE200002C9E5 /* ScanDocumentPathView.xib */, + B5BEBE152E93BE200002C9E5 /* SetPDFPasswordSwitchView.swift */, + B5BEBE162E93BE200002C9E5 /* SetPDFPasswordSwitchView.xib */, + B5BEBE172E93BE200002C9E5 /* TextFileWithOcrSwitchView.swift */, + B5BEBE182E93BE200002C9E5 /* TextFileWithOcrSwitchView.xib */, + ); + path = "NMC Views"; + sourceTree = ""; + }; C0046CDB2A17B98400D87C9D /* NextcloudUITests */ = { isa = PBXGroup; children = ( @@ -2079,7 +2511,9 @@ C04E2F212A17BB4D001BAD85 /* NextcloudIntegrationTests */ = { isa = PBXGroup; children = ( - AABD0C9A2D5F73FA00F009E6 /* Placeholder.swift */, + B5BEBD582E93AE2F0002C9E5 /* BaseIntegrationXCTestCase.swift */, + B5BEBD592E93AE2F0002C9E5 /* FilesIntegrationTests.swift */, + B5BEBD5A2E93AE2F0002C9E5 /* LoginIntegrationTests.swift */, ); path = NextcloudIntegrationTests; sourceTree = ""; @@ -2087,6 +2521,7 @@ F30A962A2A27A9C800D7BCFE /* Tests */ = { isa = PBXGroup; children = ( + B5BEBD512E93AE1C0002C9E5 /* Common */, C04E2F212A17BB4D001BAD85 /* NextcloudIntegrationTests */, AA52EB442D42AC500089C348 /* NextcloudUnitTests */, C0046CDB2A17B98400D87C9D /* NextcloudUITests */, @@ -2302,8 +2737,7 @@ isa = PBXGroup; children = ( AF93471327E235EB002537EE /* Advanced */, - F724377A2C10B83E00C7C68D /* NCSharePermissions.swift */, - F3F442ED2DDE292600FD701F /* NCMetadataPermissions.swift */, + F724377A2C10B83E00C7C68D /* NCPermissions.swift */, F700510022DF63AC003A3356 /* NCShare.storyboard */, F700510422DF6A89003A3356 /* NCShare.swift */, AF730AF727834B1400B7520E /* NCShare+NCCellDelegate.swift */, @@ -2406,7 +2840,7 @@ F7411C532D7B26C600F57358 /* NCNetworking+ServerError.swift */, F74230F22C79B57200CA1ACA /* NCNetworking+Task.swift */, F785129A2D79899E0087DDD0 /* NCNetworking+TermsOfService.swift */, - F71916102E2901E800E13E96 /* NCNetworking+Upload.swift */, + F7327E272B73A53400A462C7 /* NCNetworking+Upload.swift */, F7327E2F2B73A86700A462C7 /* NCNetworking+WebDAV.swift */, F70D8D8024A4A9BF000A5756 /* NCNetworkingProcess.swift */, F755BD9A20594AC7008C5FBB /* NCService.swift */, @@ -2426,6 +2860,8 @@ F758B41E212C516300515F55 /* Scan document */ = { isa = PBXGroup; children = ( + B5BEBE192E93BE200002C9E5 /* NMC Views */, + B5BEBE052E93BE0C0002C9E5 /* NCCreateFormUploadScanDocument.swift */, F758B457212C564000515F55 /* NCScan.storyboard */, F758B45D212C569C00515F55 /* NCScanCell.swift */, F758B45F212C56A400515F55 /* NCScan.swift */, @@ -2456,7 +2892,6 @@ F751247B2C42919C00E63DB8 /* NCPhotoCell.xib */, F75D901E2D2BE12E003E740B /* NCRecommendationsCell.xib */, F75D90202D2BE26C003E740B /* NCRecommendationsCell.swift */, - F36C514D2E89393C0097E5F7 /* UIView+BlurVibrancy.swift */, ); path = Cell; sourceTree = ""; @@ -2464,6 +2899,7 @@ F7603298252F0E550015A421 /* Collection Common */ = { isa = PBXGroup; children = ( + B5BEBDC82E93AFF10002C9E5 /* NCSelectableNavigationView.swift */, F75FE06B2BB01D0D00A0EFEF /* Cell */, F78ACD50219046AC0088454D /* Section Header Footer */, F70D7C3525FFBF81002B9E34 /* NCCollectionViewCommon.swift */, @@ -2476,7 +2912,7 @@ F799DF8A2C4B84EB003410B5 /* NCCollectionViewCommon+EndToEndInitialize.swift */, F7CCAB502ECF315F00F8E68B /* NCCollectionViewCommon+SyncMetadata.swift */, F778231D2C42C07C001BB94F /* NCCollectionViewCommon+MediaLayout.swift */, - F36E64F62B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBarDelegate.swift */, + F36E64F62B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBar.swift */, F7D4BF002CA1831600A5E746 /* NCCollectionViewCommonPinchGesture.swift */, F38F71242B6BBDC300473CDC /* NCCollectionViewCommonSelectTabBar.swift */, F7C1EEA425053A9C00866ACC /* NCCollectionViewDataSource.swift */, @@ -2525,7 +2961,7 @@ F76882052C0DD1E7001CF441 /* Advanced */, F768821F2C0DD1E7001CF441 /* Helpers */, F76882142C0DD1E7001CF441 /* Acknowledgements.rtf */, - F76882132C0DD1E7001CF441 /* NCPreferences.swift */, + F76882132C0DD1E7001CF441 /* NCKeychain.swift */, F76882152C0DD1E7001CF441 /* NCSettingsBundleHelper.swift */, F768820D2C0DD1E7001CF441 /* E2EE */, ); @@ -2694,6 +3130,8 @@ F78ACD50219046AC0088454D /* Section Header Footer */ = { isa = PBXGroup; children = ( + B5BEBDCA2E93B0210002C9E5 /* NCSectionHeaderMenu.swift */, + B5BEBDCB2E93B0210002C9E5 /* NCSectionHeaderMenu.xib */, F78ACD51219046DC0088454D /* NCSectionFirstHeader.swift */, F7B398412A6A91D5007538D6 /* NCSectionFirstHeader.xib */, F7CBC1222BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.swift */, @@ -2723,11 +3161,11 @@ F79018B1240962C7007C9B6D /* NCViewerMedia */ = { isa = PBXGroup; children = ( - F70753EA2542A99800972D44 /* NCViewerMediaPage.swift */, F718C24D254D507B00C5C256 /* NCViewerMediaDetailView.swift */, + F70753F62542A9C000972D44 /* NCViewerMediaPage.storyboard */, + F70753EA2542A99800972D44 /* NCViewerMediaPage.swift */, F70753F02542A9A200972D44 /* NCViewerMedia.swift */, F310B1EE2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift */, - F70753F62542A9C000972D44 /* NCViewerMediaPage.storyboard */, F79EDA9E26B004980007D134 /* NCPlayer */, ); path = NCViewerMedia; @@ -2802,6 +3240,7 @@ F7EE66AC2A20B226009AE765 /* UILabel+Extension.swift */, F77BB7492899857B0090FC19 /* UINavigationController+Extension.swift */, F743C89D2E5B2595000173A9 /* UIScene+Extension.swift */, + F77BB747289985270090FC19 /* UITabBarController+Extension.swift */, F77C3F5A2D9BF8B500F3C471 /* UITabBar+Extension.swift */, F77BB747289985270090FC19 /* UITabBarController+Extension.swift */, AFCE353227E4ED1900FEA6C2 /* UIToolbar+Extension.swift */, @@ -2873,7 +3312,6 @@ F73EF7BE2B02250B0087E6E9 /* NCManageDatabase+GPS.swift */, F757CC8129E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift */, F7BF9D812934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift */, - F77E8C1E2E79717D00EAE68F /* NCManageDatabase+LivePhoto.swift */, F7864ACB2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift */, AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */, F7CF06822E11273F0063AD04 /* NCManageDatabase+CreateMetadata.swift */, @@ -2893,6 +3331,7 @@ F7BFFA621A24D7300044ED85 /* Login */ = { isa = PBXGroup; children = ( + B5BEBDC62E93AF7E0002C9E5 /* NCLoginWeb.swift */, F702F2F025EE5CDA008F8E80 /* NCLogin.storyboard */, F702F2F625EE5CEC008F8E80 /* NCLogin.swift */, F745B252222D88AE00346520 /* NCLoginQRCode.swift */, @@ -2912,12 +3351,17 @@ F7F562FF2E15761500631A11 /* MigrationMultiDomains.swift */, F76D364528A4F8BF00214537 /* NCActivityIndicator.swift */, F7386E452DA90E02009A00F6 /* NCAppVersionManager.swift */, + F3E173BE2C9B1057006D177A /* ScreenAwakeManager */, + F702F2FC25EE5D2C008F8E80 /* NYMnemonic */, + F7D4BF2B2CA2E8D800A5E746 /* TOPasscodeViewController */, + F76D364528A4F8BF00214537 /* NCActivityIndicator.swift */, F733598025C1C188002ABA72 /* NCAskAuthorization.swift */, F77C97382953131000FDDD09 /* NCCameraRoll.swift */, F765608E23BF813500765969 /* NCContentPresenter.swift */, F7A3DB8F2DDE238C008F7EC8 /* NCDebouncer.swift */, F70968A324212C4E00ED60E5 /* NCLivePhoto.swift */, F7A560412AE1593700BE8FD6 /* NCOperationSaveLivePhoto.swift */, + F7386E452DA90E02009A00F6 /* NCAppVersionManager.swift */, F702F30725EE5D47008F8E80 /* NCPopupViewController.swift */, F707C26421A2DC5200F6181E /* NCStoreReview.swift */, F70BFC7320E0FA7C00C67599 /* NCUtility.swift */, @@ -2953,6 +3397,14 @@ F7C1CDD91E6DFC6F005D92BE /* Brand */ = { isa = PBXGroup; children = ( + B5BEBD272E93AD540002C9E5 /* File_Provider_Extension.entitlements */, + B5BEBD282E93AD540002C9E5 /* File_Provider_Extension.plist */, + B5BEBD292E93AD540002C9E5 /* iOSClient.entitlements */, + B5BEBD2A2E93AD540002C9E5 /* iOSClient.plist */, + B5BEBD2B2E93AD540002C9E5 /* Notification_Service_Extension.entitlements */, + B5BEBD2C2E93AD540002C9E5 /* Notification_Service_Extension.plist */, + B5BEBD2D2E93AD540002C9E5 /* Share.entitlements */, + B5BEBD2E2E93AD540002C9E5 /* Share.plist */, F761856529E98543006EB3B0 /* Intro */, F700222B1EC479840080073F /* Custom.xcassets */, F7362A1E220C853A005101B5 /* LaunchScreen.storyboard */, @@ -2980,6 +3432,15 @@ path = E2EE; sourceTree = ""; }; + F7C5259A1E3B441D00FFE02C /* Notification */ = { + isa = PBXGroup; + children = ( + F73B42292476764F00A30FD3 /* NCNotification.storyboard */, + F73B422A2476764F00A30FD3 /* NCNotification.swift */, + ); + name = Notification; + sourceTree = ""; + }; F7C9739328F17131002C43E2 /* WidgetDashboardIntentHandler */ = { isa = PBXGroup; children = ( @@ -3103,8 +3564,15 @@ F7DFB7E9219C5A0500680748 /* Create */ = { isa = PBXGroup; children = ( + B5BEBDD02E93B2450002C9E5 /* NCCreateFormUploadDocuments.storyboard */, + B5BEBDD12E93B2450002C9E5 /* NCCreateFormUploadDocuments.swift */, + B5BEBDD22E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.storyboard */, + B5BEBDD32E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.swift */, + B5BEBDD42E93B2450002C9E5 /* TextTableViewCell.swift */, + B5BEBDD52E93B2450002C9E5 /* TextTableViewCell.xib */, F7FA7FFD2C0F4F3B0072FC60 /* Upload Assets */, F7A509242C26BD5D00326106 /* NCCreate.swift */, + F7A509242C26BD5D00326106 /* NCCreateDocument.swift */, F704B5E22430AA6F00632F5F /* NCCreateFormUploadConflict.storyboard */, F704B5E42430AA8000632F5F /* NCCreateFormUploadConflict.swift */, F704B5E82430C0B800632F5F /* NCCreateFormUploadConflictCell.swift */, @@ -3125,6 +3593,7 @@ F7EC9CB921185F2000F1C5CE /* Media */ = { isa = PBXGroup; children = ( + B5BEBDE22E93BD6F0002C9E5 /* NCMediaCommandView.xib */, F720B5B72507B9A5008C94E5 /* Cell */, F7501C302212E57400FB1415 /* NCMedia.storyboard */, F7501C312212E57400FB1415 /* NCMedia.swift */, @@ -3136,7 +3605,6 @@ F7BD0A032C4689E9003A4A6D /* NCMedia+MediaLayout.swift */, F7E2B64E2DDCC5C30075B4D0 /* NCMedia+TransferDelegate.swift */, F78B87E62B62527100C65ADC /* NCMediaDataSource.swift */, - F79699E62E689F68000EC82A /* NCMediaNavigationController.swift */, F7D60CAE2C941ACB008FBFDD /* NCMediaPinchGesture.swift */, F78B87E82B62550800C65ADC /* NCMediaDownloadThumbnail.swift */, F755CB3F2B8CB13C00CE27E9 /* NCMediaLayout.swift */, @@ -3145,15 +3613,6 @@ path = Media; sourceTree = ""; }; - F7EF2AEA2E43157B0081B2C9 /* Notification */ = { - isa = PBXGroup; - children = ( - F7EF2AE82E43157B0081B2C9 /* NCNotification.storyboard */, - F7EF2AE92E43157B0081B2C9 /* NCNotification.swift */, - ); - path = Notification; - sourceTree = ""; - }; F7EFC0CB256BF89300461AAD /* UserStatus */ = { isa = PBXGroup; children = ( @@ -3163,13 +3622,6 @@ path = UserStatus; sourceTree = ""; }; - F7F1FBA62E27D13700C79E20 /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; F7F4F0FB27ECDBDA008676F9 /* Font */ = { isa = PBXGroup; children = ( @@ -3218,13 +3670,19 @@ F70716E32987F81500E72C1D /* File Provider Extension UI.appex */, C04E2F202A17BB4D001BAD85 /* NextcloudIntegrationTests.xctest */, C0046CDA2A17B98400D87C9D /* NextcloudUITests.xctest */, - F7F1FBA62E27D13700C79E20 /* Frameworks */, ); sourceTree = ""; }; F7F67BAA1A24D27800EE80DA /* iOSClient */ = { isa = PBXGroup; children = ( + B560B9592EF5597A00E55904 /* Account */, + B5BEBDE82E93BDB40002C9E5 /* NMC Custom Views */, + B5BEBD9B2E93AF010002C9E5 /* AppUtility.swift */, + B5BEBD9E2E93AF010002C9E5 /* EmptyView */, + B5BEBDA22E93AF010002C9E5 /* Helper */, + B5BEBD932E93AED80002C9E5 /* AppUpdate */, + B5BEBD7C2E93AEA30002C9E5 /* Analytics */, AA517BB42D66149900F8D37C /* .tx */, F702F2CC25EE5B4F008F8E80 /* AppDelegate.swift */, F794E13E2BBC0F70003693D7 /* SceneDelegate.swift */, @@ -3239,7 +3697,6 @@ F7F67BB81A24D27800EE80DA /* Images.xcassets */, F769CA1B2966EF4F00039397 /* GUI */, F70211F31BAC56E9003FC03E /* Main */, - F7FDFF5A2E437E55000D7688 /* Account */, F7A321621E9E37960069AD1B /* Activity */, F76687042B7D067400779E3F /* AudioRecorder */, F3A0478E2BD2668800658E7B /* Assistant */, @@ -3256,7 +3713,7 @@ 371B5A2F23D0B04B00FAFAE9 /* Menu */, F7CB68942541670D0050EC94 /* More */, F74D3DB81BAC1941000BAE4B /* Networking */, - F7EF2AEA2E43157B0081B2C9 /* Notification */, + F7C5259A1E3B441D00FFE02C /* Notification */, F7381ED9218218A4000B1560 /* Offline */, F713418B2597513800768D21 /* PushNotification */, F765F72E25237E3F00391DBE /* Recent */, @@ -3307,36 +3764,6 @@ name = Products; sourceTree = ""; }; - F7FDFF552E437E55000D7688 /* Account Request */ = { - isa = PBXGroup; - children = ( - F7FDFF512E437E55000D7688 /* NCAccountRequest.storyboard */, - F7FDFF522E437E55000D7688 /* NCAccountRequest.swift */, - F7FDFF532E437E55000D7688 /* NCShareAccounts.storyboard */, - F7FDFF542E437E55000D7688 /* NCShareAccounts.swift */, - ); - path = "Account Request"; - sourceTree = ""; - }; - F7FDFF582E437E55000D7688 /* Account Settings */ = { - isa = PBXGroup; - children = ( - F7FDFF562E437E55000D7688 /* NCAccountSettingsModel.swift */, - F7FDFF572E437E55000D7688 /* NCAccountSettingsView.swift */, - ); - path = "Account Settings"; - sourceTree = ""; - }; - F7FDFF5A2E437E55000D7688 /* Account */ = { - isa = PBXGroup; - children = ( - F7FDFF552E437E55000D7688 /* Account Request */, - F7FDFF582E437E55000D7688 /* Account Settings */, - F7FDFF592E437E55000D7688 /* NCAccount.swift */, - ); - path = Account; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -3359,8 +3786,6 @@ F72AD71028C24BBB006CB92D /* NextcloudKit */, F760DE0E2AE66EE60027D78A /* KeychainAccess */, F33EE6EC2BF4C03800CA1A51 /* NIOSSL */, - F7F1FBAD2E27D3A400C79E20 /* SwiftEntryKit */, - F7F1FBAF2E27D3A800C79E20 /* Queuer */, ); productName = "Notification Service Extension"; productReference = 2C33C47F23E2C475005F963B /* Notification Service Extension.appex */; @@ -3473,6 +3898,7 @@ F7490E7129882BB4009DCE94 /* RealmSwift */, F7490E8A29882CE4009DCE94 /* NextcloudKit */, F760DE0C2AE66EDF0027D78A /* KeychainAccess */, + F33EE6EA2BF4C03200CA1A51 /* NIOSSL */, ); productName = "File Provider Extension UI"; productReference = F70716E32987F81500E72C1D /* File Provider Extension UI.appex */; @@ -3619,6 +4045,17 @@ F3374AF72D78B01B002A38F9 /* HeapModule */, F7B8F6132EAB64AD006A70D6 /* JDStatusBarNotification */, F70557B62ED44E2700135623 /* LucidBanner */, + 56A32E692CE4B69B0020EFF5 /* MoEngage-iOS-SDK */, + F327FA422B8CC0B900E5B743 /* SwipeCellKit */, + 56A32E692CE4B69B0020EFF5 /* MoEngage-iOS-SDK */, + 56AB28932B833E2D0089D373 /* Adjust */, + 56AB28962B8351720089D373 /* TealiumAutotracking */, + 56AB28982B8351720089D373 /* TealiumCore */, + 56AB289A2B8351720089D373 /* TealiumLifecycle */, + 56AB289C2B8351730089D373 /* TealiumLocation */, + 56AB289E2B8351730089D373 /* TealiumRemoteCommands */, + 56AB28A02B8351730089D373 /* TealiumTagManagement */, + 56AB28A22B8351740089D373 /* TealiumVisitorService */, ); productName = "Crypto Cloud"; productReference = F7CE8AFA1DC1F8D8009CAE48 /* Nextcloud.app */; @@ -3643,8 +4080,6 @@ F7A8D72728F17728008BBE1C /* RealmSwift */, F760DE062AE66EC70027D78A /* KeychainAccess */, F33EE6E42BF4C02000CA1A51 /* NIOSSL */, - F7F1FBA72E27D13700C79E20 /* Queuer */, - F7F1FBA92E27D14000C79E20 /* SwiftEntryKit */, ); productName = WidgetDashboardIntentHandler; productReference = F7C9739028F17131002C43E2 /* WidgetDashboardIntentHandler.appex */; @@ -3658,7 +4093,7 @@ attributes = { BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1430; - LastUpgradeCheck = 1630; + LastUpgradeCheck = 1620; ORGANIZATIONNAME = "Marino Faggiana"; TargetAttributes = { 2C33C47E23E2C475005F963B = { @@ -3803,6 +4238,11 @@ F3374AEE2D78B01B002A38F9 /* XCRemoteSwiftPackageReference "swift-collections" */, F7B8F6122EAB64AD006A70D6 /* XCRemoteSwiftPackageReference "JDStatusBarNotification" */, F70557B52ED44E2700135623 /* XCRemoteSwiftPackageReference "LucidBanner" */, + 56A32E682CE4B66A0020EFF5 /* XCRemoteSwiftPackageReference "MoEngage-iOS-SDK" */, + F327FA412B8CC0B900E5B743 /* XCRemoteSwiftPackageReference "SwipeCellKit" */, + 56A32E682CE4B66A0020EFF5 /* XCRemoteSwiftPackageReference "MoEngage-iOS-SDK" */, + 566FCF5C2B3ED58900168DEA /* XCRemoteSwiftPackageReference "tealium-swift" */, + 566FCF5D2B3ED64900168DEA /* XCRemoteSwiftPackageReference "ios_sdk" */, ); productRefGroup = F7F67B9F1A24D27800EE80DA; projectDirPath = ""; @@ -3827,6 +4267,13 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + B5BEBDBB2E93AF010002C9E5 /* NCEmptyView.xib in Resources */, + B5BEBDF72E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */, + B5BEBDF82E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */, + B5BEBD3F2E93AD540002C9E5 /* iOSClient.plist in Resources */, + B5BEBD402E93AD540002C9E5 /* Share.plist in Resources */, + B5BEBD412E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */, + B5BEBD422E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */, F7E4022F2BA85D1D007E5609 /* PrivacyInfo.xcprivacy in Resources */, F746EC53273906C50052598D /* NCViewCertificateDetails.storyboard in Resources */, ); @@ -3836,6 +4283,10 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + B5BEBD472E93AD540002C9E5 /* iOSClient.plist in Resources */, + B5BEBD482E93AD540002C9E5 /* Share.plist in Resources */, + B5BEBD492E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */, + B5BEBD4A2E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3858,8 +4309,15 @@ buildActionMask = 2147483647; files = ( F7490E8D29882F5B009DCE94 /* Custom.xcassets in Resources */, + B5BEBDEF2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */, + B5BEBDF02E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */, + B5BEBDB12E93AF010002C9E5 /* NCEmptyView.xib in Resources */, F7490E8E2988334A009DCE94 /* Localizable.strings in Resources */, F7E4022E2BA85D1D007E5609 /* PrivacyInfo.xcprivacy in Resources */, + B5BEBD432E93AD540002C9E5 /* iOSClient.plist in Resources */, + B5BEBD442E93AD540002C9E5 /* Share.plist in Resources */, + B5BEBD452E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */, + B5BEBD462E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */, AA517B812D660EFE00F8D37C /* Localizable.stringsdict in Resources */, F722F0112CFF569500065FB5 /* MainInterface.storyboard in Resources */, ); @@ -3877,12 +4335,23 @@ F7B398432A6A91D5007538D6 /* NCSectionFirstHeader.xib in Resources */, AF22B207277B4E4C00DAB0CC /* NCCreateFormUploadConflict.storyboard in Resources */, AA517B822D660EFE00F8D37C /* Localizable.stringsdict in Resources */, + B5BEBD2F2E93AD540002C9E5 /* iOSClient.plist in Resources */, + B5BEBDD92E93B2450002C9E5 /* TextTableViewCell.xib in Resources */, + B5BEBDDA2E93B2450002C9E5 /* NCCreateFormUploadDocuments.storyboard in Resources */, + B5BEBDDB2E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.storyboard in Resources */, + B5BEBD302E93AD540002C9E5 /* Share.plist in Resources */, + B5BEBDB62E93AF010002C9E5 /* NCEmptyView.xib in Resources */, + B5BEBD312E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */, + B5BEBD322E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */, + B5BEBDCD2E93B0210002C9E5 /* NCSectionHeaderMenu.xib in Resources */, F7145A231D12E3B700CAFEEC /* Localizable.strings in Resources */, F746EC51273906C40052598D /* NCViewCertificateDetails.storyboard in Resources */, + B560B9622EF559C100E55904 /* NCAccountRequest.storyboard in Resources */, F76C26A62850D3A500E42BDF /* Images.xcassets in Resources */, F714805E262ED52900693E51 /* NCSectionFooter.xib in Resources */, + B5BEBDFB2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */, + B5BEBDFC2E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */, F700222D1EC479840080073F /* Custom.xcassets in Resources */, - F7FDFF702E437E55000D7688 /* NCAccountRequest.storyboard in Resources */, F79ED0F22D2FCA6A00A389D9 /* NCRecommendationsCell.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3892,8 +4361,15 @@ buildActionMask = 2147483647; files = ( F7C7B25128B8B0C400E7115D /* Images.xcassets in Resources */, + B5BEBDFD2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */, + B5BEBDFE2E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */, + B5BEBDA82E93AF010002C9E5 /* NCEmptyView.xib in Resources */, F7C7B25028B8AD4500E7115D /* Localizable.strings in Resources */, F7E4022A2BA85D1D007E5609 /* PrivacyInfo.xcprivacy in Resources */, + B5BEBD372E93AD540002C9E5 /* iOSClient.plist in Resources */, + B5BEBD382E93AD540002C9E5 /* Share.plist in Resources */, + B5BEBD392E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */, + B5BEBD3A2E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */, AA517B832D660EFE00F8D37C /* Localizable.stringsdict in Resources */, F7346E2328B0FEBA006CE2D2 /* Assets.xcassets in Resources */, ); @@ -3903,6 +4379,13 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + B5BEBDC12E93AF010002C9E5 /* NCEmptyView.xib in Resources */, + B5BEBE012E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */, + B5BEBE022E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */, + B5BEBD4B2E93AD540002C9E5 /* iOSClient.plist in Resources */, + B5BEBD4C2E93AD540002C9E5 /* Share.plist in Resources */, + B5BEBD4D2E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */, + B5BEBD4E2E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */, F7E4022D2BA85D1D007E5609 /* PrivacyInfo.xcprivacy in Resources */, F746EC52273906C40052598D /* NCViewCertificateDetails.storyboard in Resources */, ); @@ -3916,6 +4399,7 @@ F77444F622281649000D5EB0 /* NCMediaCell.xib in Resources */, F78ACD4421903CF20088454D /* NCListCell.xib in Resources */, F3BB464D2A39ADCC00461F6E /* NCMoreAppSuggestionsCell.xib in Resources */, + B5BEBDE32E93BD6F0002C9E5 /* NCMediaCommandView.xib in Resources */, F7F4F10727ECDBDB008676F9 /* Inconsolata-Black.ttf in Resources */, F761856D29E98543006EB3B0 /* NCIntroCollectionViewCell.xib in Resources */, F78ACD4621903D010088454D /* NCGridCell.xib in Resources */, @@ -3926,6 +4410,8 @@ F76D3CF52428D0C1005DFA87 /* NCViewerPDF.storyboard in Resources */, F700222C1EC479840080073F /* Custom.xcassets in Resources */, F702F2F125EE5CDB008F8E80 /* NCLogin.storyboard in Resources */, + B5BEBDF32E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */, + B5BEBDF42E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */, F723985C253C95CE00257F49 /* NCViewerRichdocument.storyboard in Resources */, F758B45A212C564000515F55 /* NCScan.storyboard in Resources */, F765F73225237E3F00391DBE /* NCRecent.storyboard in Resources */, @@ -3936,11 +4422,13 @@ F7226EDC1EE4089300EBECB1 /* Main.storyboard in Resources */, AF56C1DC2784856200D8BAE2 /* NCActivityCommentView.xib in Resources */, F7F4F10B27ECDBDB008676F9 /* Inconsolata-Light.ttf in Resources */, - F7EF2AEC2E43157B0081B2C9 /* NCNotification.storyboard in Resources */, F7CEE6002BA9A5C9003EFD89 /* NCTrashGridCell.xib in Resources */, 3704EB2A23D5A58400455C5B /* NCMenu.storyboard in Resources */, AF93471C27E2361E002537EE /* NCShareHeader.xib in Resources */, F75D901F2D2BE12E003E740B /* NCRecommendationsCell.xib in Resources */, + F76032A0252F0F8E0015A421 /* NCTransferCell.xib in Resources */, + B560B95F2EF5597A00E55904 /* NCShareAccounts.storyboard in Resources */, + B560B9602EF5597A00E55904 /* NCAccountRequest.storyboard in Resources */, F7F4F10527ECDBDB008676F9 /* Inconsolata-SemiBold.ttf in Resources */, F7A48415297028FC00BD1B49 /* Nextcloud Hub.png in Resources */, F74C0437253F1CDC009762AB /* NCShares.storyboard in Resources */, @@ -3949,6 +4437,7 @@ F7381EE5218218C9000B1560 /* NCOffline.storyboard in Resources */, F768822D2C0DD1E7001CF441 /* Acknowledgements.rtf in Resources */, F76D3CF32428B94E005DFA87 /* NCViewerPDFSearchCell.xib in Resources */, + B5BEBDCF2E93B0210002C9E5 /* NCSectionHeaderMenu.xib in Resources */, F717402D24F699A5000C87D5 /* NCFavorite.storyboard in Resources */, F723B3DD22FC6D1D00301EFE /* NCShareCommentsCell.xib in Resources */, F78ACD4B21903F850088454D /* NCTrashListCell.xib in Resources */, @@ -3963,8 +4452,21 @@ F761856A29E98543006EB3B0 /* NCIntro.storyboard in Resources */, F719D9E0288D37A300762E33 /* NCColorPicker.storyboard in Resources */, AA517B802D660EFE00F8D37C /* Localizable.stringsdict in Resources */, + B5BEBE232E93BE200002C9E5 /* PasswordInputField.xib in Resources */, + B5BEBE242E93BE200002C9E5 /* ScanDocumentPathView.xib in Resources */, + B5BEBE252E93BE200002C9E5 /* SetPDFPasswordSwitchView.xib in Resources */, + B5BEBE262E93BE200002C9E5 /* PdfWithOcrSwitchView.xib in Resources */, + B5BEBE272E93BE200002C9E5 /* PNGImageSaveSwitchView.xib in Resources */, + B5BEBE282E93BE200002C9E5 /* FileNameInputTextField.xib in Resources */, + B5BEBE292E93BE200002C9E5 /* TextFileWithOcrSwitchView.xib in Resources */, + B5BEBE2A2E93BE200002C9E5 /* PdfWithoutOcrSwitchView.xib in Resources */, + B5BEBE2B2E93BE200002C9E5 /* JPGImageSaveSwitchView.xib in Resources */, F7F4F10A27ECDBDB008676F9 /* Inconsolata-ExtraBold.ttf in Resources */, F704B5E72430C06700632F5F /* NCCreateFormUploadConflictCell.xib in Resources */, + B5BEBDDF2E93B2450002C9E5 /* TextTableViewCell.xib in Resources */, + B5BEBDE02E93B2450002C9E5 /* NCCreateFormUploadDocuments.storyboard in Resources */, + B5BEBDE12E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.storyboard in Resources */, + B5BEBDA72E93AF010002C9E5 /* NCEmptyView.xib in Resources */, F7E402292BA85D1D007E5609 /* PrivacyInfo.xcprivacy in Resources */, F7C9555321F0C4CA0024296E /* NCActivity.storyboard in Resources */, F7BC287E26663F6C004D46C5 /* NCViewCertificateDetails.storyboard in Resources */, @@ -3975,11 +4477,14 @@ F732D23327CF8AED000B0F1B /* NCPlayerToolBar.xib in Resources */, F73D11FA253C5F4800DF9BEC /* NCViewerNextcloudText.storyboard in Resources */, F7EDE51B262DD0C400414FE6 /* NCSelectCommandViewCopyMove.xib in Resources */, + F73B422B2476764F00A30FD3 /* NCNotification.storyboard in Resources */, F7FF2CB12842159500EBB7A1 /* NCSectionHeader.xib in Resources */, F7D1612023CF19E30039EBBF /* NCViewerRichWorkspace.storyboard in Resources */, + B5BEBD332E93AD540002C9E5 /* iOSClient.plist in Resources */, + B5BEBD342E93AD540002C9E5 /* Share.plist in Resources */, + B5BEBD352E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */, + B5BEBD362E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */, F77B0F631D118A16002130FE /* Localizable.strings in Resources */, - F7FDFF692E437E55000D7688 /* NCAccountRequest.storyboard in Resources */, - F7FDFF6A2E437E55000D7688 /* NCShareAccounts.storyboard in Resources */, F774264A22EB4D0000B23912 /* NCSearchUserDropDownCell.xib in Resources */, F7CB689A2541676B0050EC94 /* NCMore.storyboard in Resources */, F77B0F7D1D118A16002130FE /* Images.xcassets in Resources */, @@ -3988,6 +4493,7 @@ F7EDE514262DC2CD00414FE6 /* NCSelectCommandViewSelect+CreateFolder.xib in Resources */, F7B398422A6A91D5007538D6 /* NCSectionFirstHeader.xib in Resources */, F7501C322212E57500FB1415 /* NCMedia.storyboard in Resources */, + F74DE14425135B6800917068 /* NCTransfers.storyboard in Resources */, F76687082B7D067400779E3F /* NCAudioRecorderViewController.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3997,6 +4503,13 @@ buildActionMask = 2147483647; files = ( F7E4022B2BA85D1D007E5609 /* PrivacyInfo.xcprivacy in Resources */, + B5BEBDEB2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.xib in Resources */, + B5BEBDEC2E93BDB40002C9E5 /* FolderPathCustomCell.xib in Resources */, + B5BEBDC02E93AF010002C9E5 /* NCEmptyView.xib in Resources */, + B5BEBD3B2E93AD540002C9E5 /* iOSClient.plist in Resources */, + B5BEBD3C2E93AD540002C9E5 /* Share.plist in Resources */, + B5BEBD3D2E93AD540002C9E5 /* Notification_Service_Extension.plist in Resources */, + B5BEBD3E2E93AD540002C9E5 /* File_Provider_Extension.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4033,6 +4546,14 @@ 2C1D5D7923E2DE9100334ABB /* NCBrand.swift in Sources */, F770768A263A8A2500A1BA94 /* NCUtilityFileSystem.swift in Sources */, F77E8C1F2E79717D00EAE68F /* NCManageDatabase+LivePhoto.swift in Sources */, + F7CF067B2E0FF3990063AD04 /* NCAppStateManager.swift in Sources */, + F71433E72C778FFB00E20B5A /* NotificationCenter+MainThread.swift in Sources */, + F39170AA2CB82024006127BC /* FileAutoRenamer+Extensions.swift in Sources */, + F73EF7C52B02250B0087E6E9 /* NCManageDatabase+GPS.swift in Sources */, + 2C1D5D7923E2DE9100334ABB /* NCBrand.swift in Sources */, + F770768A263A8A2500A1BA94 /* NCUtilityFileSystem.swift in Sources */, + F76D364928A4F8BF00214537 /* NCActivityIndicator.swift in Sources */, + F7817CFD29801A3500FFBC65 /* Data+Extension.swift in Sources */, F7D7A7712DCDD437003D2007 /* NCManageDatabase+AutoUpload.swift in Sources */, AF4BF62127562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */, F702F2D225EE5B5C008F8E80 /* NCGlobal.swift in Sources */, @@ -4045,9 +4566,14 @@ F7D61EC02EBF1878007F865B /* NCManageDatabase+Tag.swift in Sources */, F7864AD22A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */, F724377D2C10B92300C7C68D /* NCSharePermissions.swift in Sources */, + F314F1142A30E2DE00BC7FAB /* View+Extension.swift in Sources */, + F724377D2C10B92300C7C68D /* NCPermissions.swift in Sources */, F7D68FD028CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */, F7245927289BB59300474787 /* ThreadSafeDictionary.swift in Sources */, 2C33C48223E2C475005F963B /* NotificationService.swift in Sources */, + F73EF7A52B021FAE0087E6E9 /* NCLivePhoto.swift in Sources */, + F33EE6F82BF4C9B200CA1A51 /* PKCS12.swift in Sources */, + B5BEBD952E93AED80002C9E5 /* AppUpdater.swift in Sources */, AF4BF617275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */, F7BF9D872934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */, AA8D31592D41052900FE2775 /* NCManageDatabase+DownloadLimit.swift in Sources */, @@ -4058,8 +4584,18 @@ F7CF06832E1127460063AD04 /* NCManageDatabase+CreateMetadata.swift in Sources */, F7D61EA62EBF1694007F865B /* NCManageDatabase+TableCapabilities.swift in Sources */, F757CC8829E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */, + F7386E462DA90E0F009A00F6 /* NCAppVersionManager.swift in Sources */, + B5BEBDF52E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */, + B5BEBDF62E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */, + F33918CA2C7CD8F2002D9AA1 /* FileNameValidator+Extensions.swift in Sources */, + D575039F27146F93008DC9DC /* String+Extension.swift in Sources */, + F7CF06832E1127460063AD04 /* NCManageDatabase+Metadata+Create.swift in Sources */, + F757CC8829E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */, + B5BEBD8C2E93AEA30002C9E5 /* AnalyticsService.swift in Sources */, + B5BEBD8D2E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */, + B5BEBD8E2E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */, + F79B646326CA661600838ACA /* UIControl+Extension.swift in Sources */, F7C687EF2D22BDE5004757BC /* NCManageDatabase+RecommendedFiles.swift in Sources */, - F3F442F42DDE2A7700FD701F /* NCMetadataPermissions.swift in Sources */, F77DD6AE2C5CC093009448FB /* NCSession.swift in Sources */, F78A10C429322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */, F7B769AE2B7A0B2000C1AAEB /* NCManageDatabase+Metadata+Session.swift in Sources */, @@ -4069,10 +4605,18 @@ F798F0EC2588060A000DAFFD /* UIColor+Extension.swift in Sources */, F76882372C0DD22F001CF441 /* NCPreferences.swift in Sources */, F73EF7E52B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */, + F343A4B92A1E084400DDA874 /* PHAsset+Extension.swift in Sources */, + F76882372C0DD22F001CF441 /* NCKeychain.swift in Sources */, + F73EF7E52B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */, + F73EF7D52B0225BA0087E6E9 /* NCManageDatabase+Tag.swift in Sources */, F71F6D0D2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */, F763D2A32A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */, F749B656297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */, F782FDC424E6933900666099 /* NCUtility.swift in Sources */, + B5BEBDB72E93AF010002C9E5 /* AppUtility.swift in Sources */, + B5BEBDB82E93AF010002C9E5 /* AdjustHelper.m in Sources */, + B5BEBDB92E93AF010002C9E5 /* TealiumHelper.swift in Sources */, + B5BEBDBA2E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */, F74B6D9B2A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4082,8 +4626,24 @@ buildActionMask = 2147483647; files = ( AA52EB472D42AC9E0089C348 /* Placeholder.swift in Sources */, + B5BEBD542E93AE1C0002C9E5 /* TestConstants.swift in Sources */, + B5BEBD552E93AE1C0002C9E5 /* BaseXCTestCase.swift in Sources */, F372087D2BAB4C0F006B5430 /* TestConstants.swift in Sources */, F78E2D6C29AF02DB0024D4F3 /* Database.swift in Sources */, + B5BEBD6B2E93AE4B0002C9E5 /* SharingTest.swift in Sources */, + B5BEBD6C2E93AE4B0002C9E5 /* AssetUploadTest.swift in Sources */, + B5BEBD6D2E93AE4B0002C9E5 /* NCNotificationText.swift in Sources */, + B5BEBD6E2E93AE4B0002C9E5 /* SettingsTestCases.swift in Sources */, + B5BEBD6F2E93AE4B0002C9E5 /* CollaboraTestCase.swift in Sources */, + B5BEBD702E93AE4B0002C9E5 /* MoveAndCopyTests.swift in Sources */, + B5BEBD712E93AE4B0002C9E5 /* MoreTests.swift in Sources */, + B5BEBD722E93AE4B0002C9E5 /* RenameFileTests.swift in Sources */, + B5BEBD732E93AE4B0002C9E5 /* AudioUploadTests.swift in Sources */, + B5BEBD742E93AE4B0002C9E5 /* OnboardingTestCase.swift in Sources */, + B5BEBD752E93AE4B0002C9E5 /* E2EETests.swift in Sources */, + B5BEBD762E93AE4B0002C9E5 /* ScanTests.swift in Sources */, + B5BEBD772E93AE4B0002C9E5 /* PrivacyPolicyTest.swift in Sources */, + F7817CFE29801A3500FFBC65 /* Data+Extension.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4097,6 +4657,11 @@ AA74AA972D3172D100BE3458 /* UITestError.swift in Sources */, AA3C85E82D36B08C00F74F12 /* UITestBackend.swift in Sources */, AA8E03DC2D2FBAC200E7E89C /* DownloadLimitUITests.swift in Sources */, + B5BEBD562E93AE1C0002C9E5 /* TestConstants.swift in Sources */, + B5BEBD572E93AE1C0002C9E5 /* BaseXCTestCase.swift in Sources */, + B5BEBD5B2E93AE2F0002C9E5 /* LoginIntegrationTests.swift in Sources */, + B5BEBD5C2E93AE2F0002C9E5 /* BaseIntegrationXCTestCase.swift in Sources */, + B5BEBD5D2E93AE2F0002C9E5 /* FilesIntegrationTests.swift in Sources */, AABD0C8A2D5F67A400F009E6 /* XCUIElement.swift in Sources */, AA3C85EE2D36BCCE00F74F12 /* SharesResponse.swift in Sources */, AAA7BC2E2D3E39F1008F1A22 /* CapabilitiesResponse.swift in Sources */, @@ -4104,7 +4669,6 @@ F3374A962D6744A4002A38F9 /* BaseUIXCTestCase.swift in Sources */, F37208812BAB5979006B5430 /* TestConstants.swift in Sources */, F33D303E2D8B129600531D64 /* AutoUploadUITests.swift in Sources */, - AABD0C9B2D5F73FC00F009E6 /* Placeholder.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4112,6 +4676,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + B5BEBD522E93AE1C0002C9E5 /* TestConstants.swift in Sources */, + B5BEBD532E93AE1C0002C9E5 /* BaseXCTestCase.swift in Sources */, F372087E2BAB4C0F006B5430 /* TestConstants.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4121,6 +4687,16 @@ buildActionMask = 2147483647; files = ( F78E2D6A29AF02DB0024D4F3 /* Database.swift in Sources */, + F74B6D9A2A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */, + F7490E8329882C84009DCE94 /* NCManageDatabase+LayoutForView.swift in Sources */, + AA8D31582D41052300FE2775 /* NCManageDatabase+DownloadLimit.swift in Sources */, + F73EF7DC2B0226080087E6E9 /* NCManageDatabase+Tip.swift in Sources */, + F7490E8029882C76009DCE94 /* NCManageDatabase+Avatar.swift in Sources */, + F343A4B82A1E084300DDA874 /* PHAsset+Extension.swift in Sources */, + F78E2D6A29AF02DB0024D4F3 /* Database.swift in Sources */, + F7C687EE2D22BDE5004757BC /* NCManageDatabase+RecommendedFiles.swift in Sources */, + F7490E7429882BCC009DCE94 /* NCManageDatabase.swift in Sources */, + F7CF067E2E0FF3990063AD04 /* NCAppStateManager.swift in Sources */, F7490E6E29882B56009DCE94 /* NCBrand.swift in Sources */, F7D61E942EBF1366007F865B /* UIColor+Extension.swift in Sources */, F71F6D0C2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */, @@ -4134,6 +4710,30 @@ F70716E62987F81500E72C1D /* DocumentActionViewController.swift in Sources */, F763412A2EBE10F00056F538 /* NCUtilityFileSystem.swift in Sources */, F7F1FB9E2E27CE7200C79E20 /* NCNetworking.swift in Sources */, + F7490E8629882C99009DCE94 /* NCUtilityFileSystem.swift in Sources */, + F763D2A22A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */, + B5BEBDAD2E93AF010002C9E5 /* AppUtility.swift in Sources */, + B5BEBDAE2E93AF010002C9E5 /* AdjustHelper.m in Sources */, + B5BEBDAF2E93AF010002C9E5 /* TealiumHelper.swift in Sources */, + B5BEBDB02E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */, + F73EF7E42B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */, + F343A4C02A1E734600DDA874 /* Optional+Extension.swift in Sources */, + F7D7A76D2DCDD437003D2007 /* NCManageDatabase+AutoUpload.swift in Sources */, + F711A4E12AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */, + F76882382C0DD22F001CF441 /* NCKeychain.swift in Sources */, + F7C9B9222B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */, + F7490E8529882C8C009DCE94 /* NCManageDatabase+Video.swift in Sources */, + F7CF06892E1127460063AD04 /* NCManageDatabase+Metadata+Create.swift in Sources */, + F7386E4A2DA90E0F009A00F6 /* NCAppVersionManager.swift in Sources */, + F7490E7729882C10009DCE94 /* UIColor+Extension.swift in Sources */, + F70716E62987F81500E72C1D /* DocumentActionViewController.swift in Sources */, + F359D86C2A7D03420023F405 /* NCUtility+Exif.swift in Sources */, + F7490E8429882C89009DCE94 /* NCManageDatabase+Share.swift in Sources */, + F7490E6F29882B67009DCE94 /* UIImage+Extension.swift in Sources */, + F7490E7E29882C6E009DCE94 /* NCManageDatabase+Account.swift in Sources */, + F7490E7029882B9B009DCE94 /* NCManageDatabase+Metadata.swift in Sources */, + F73EF7AC2B0223900087E6E9 /* NCManageDatabase+Comments.swift in Sources */, + F73EF7C42B02250B0087E6E9 /* NCManageDatabase+GPS.swift in Sources */, F77DD6AD2C5CC093009448FB /* NCSession.swift in Sources */, F76340F92EBDE9760056F538 /* NCManageDatabaseCore.swift in Sources */, F7E742F42EC0A10C00E2362A /* NCManageDatabase+Account.swift in Sources */, @@ -4150,6 +4750,25 @@ F763413F2EBE5DC40056F538 /* FileProviderUtility.swift in Sources */, F763413A2EBE5DAB0056F538 /* FileProviderEnumerator.swift in Sources */, F763412F2EBE255B0056F538 /* NCNetworking+NextcloudKitDelegate.swift in Sources */, + F73EF7A42B021FAD0087E6E9 /* NCLivePhoto.swift in Sources */, + F757CC8729E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */, + F33EE6F72BF4C9B200CA1A51 /* PKCS12.swift in Sources */, + B5BEBDED2E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */, + B5BEBDEE2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */, + F7B769AD2B7A0B2000C1AAEB /* NCManageDatabase+Metadata+Session.swift in Sources */, + F39170AC2CB82024006127BC /* FileAutoRenamer+Extensions.swift in Sources */, + F73EF7BC2B0224AB0087E6E9 /* NCManageDatabase+ExternalSites.swift in Sources */, + F724377E2C10B92300C7C68D /* NCPermissions.swift in Sources */, + F7490E8229882C80009DCE94 /* NCManageDatabase+E2EE.swift in Sources */, + F7490E7829882C28009DCE94 /* NCUtility.swift in Sources */, + F3E173C52C9B1067006D177A /* AwakeMode.swift in Sources */, + F71433E62C778FFB00E20B5A /* NotificationCenter+MainThread.swift in Sources */, + F33918C92C7CD8F2002D9AA1 /* FileNameValidator+Extensions.swift in Sources */, + F7490E7F29882C73009DCE94 /* NCManageDatabase+Activity.swift in Sources */, + B5BEBD962E93AED80002C9E5 /* AppUpdater.swift in Sources */, + B5BEBD832E93AEA30002C9E5 /* AnalyticsService.swift in Sources */, + B5BEBD842E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */, + B5BEBD852E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4165,6 +4784,8 @@ F7C30DFB291BCF790017149B /* NCNetworkingE2EECreateFolder.swift in Sources */, F73EF7DA2B0226080087E6E9 /* NCManageDatabase+Tip.swift in Sources */, F70557BF2ED44F1800135623 /* UploadBannerView.swift in Sources */, + B5E2E7342DAE896200AB2EDD /* NCSectionHeaderMenu.swift in Sources */, + F79ED0F32D2FCA7100A389D9 /* NCRecommendationsCell.swift in Sources */, F7817CFB29801A3500FFBC65 /* Data+Extension.swift in Sources */, F72429362AFE39860040AEF3 /* NCLivePhoto.swift in Sources */, AF4BF61F27562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */, @@ -4174,6 +4795,11 @@ F74B6D982A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */, F7CF06872E1127460063AD04 /* NCManageDatabase+CreateMetadata.swift in Sources */, F7FDFF722E437E55000D7688 /* NCAccountRequest.swift in Sources */, + F7327E372B73AEDE00A462C7 /* NCNetworking+LivePhoto.swift in Sources */, + F7F3E58D2D3BB65600A32B14 /* NCNetworking+Recommendations.swift in Sources */, + F73EF7D22B0225BA0087E6E9 /* NCManageDatabase+Tag.swift in Sources */, + F74B6D982A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */, + F7CF06872E1127460063AD04 /* NCManageDatabase+Metadata+Create.swift in Sources */, F7707687263A853700A1BA94 /* NCContentPresenter.swift in Sources */, F343A4B62A1E084200DDA874 /* PHAsset+Extension.swift in Sources */, F70460532499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */, @@ -4185,12 +4811,18 @@ F79ED0F12D2FCA5B00A389D9 /* NCSectionFirstHeader.swift in Sources */, F79B646126CA661600838ACA /* UIControl+Extension.swift in Sources */, F77C973A2953143A00FDDD09 /* NCCameraRoll.swift in Sources */, + B5BEBDD62E93B2450002C9E5 /* NCCreateFormUploadDocuments.swift in Sources */, + B5BEBDD72E93B2450002C9E5 /* TextTableViewCell.swift in Sources */, + B5BEBDD82E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.swift in Sources */, F740BEF02A35C2AD00E9B6D5 /* UILabel+Extension.swift in Sources */, F7C30E01291BD2610017149B /* NCNetworkingE2EERename.swift in Sources */, AF4BF61A27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */, AF4BF615275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */, F798F0E225880608000DAFFD /* UIColor+Extension.swift in Sources */, + F7327E3F2B73B92800A462C7 /* NCNetworking+Synchronization.swift in Sources */, + F7CF067F2E0FF3990063AD04 /* NCAppStateManager.swift in Sources */, F7C9B9202B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */, + B5BEBD942E93AED80002C9E5 /* AppUpdater.swift in Sources */, F78E2D6829AF02DB0024D4F3 /* Database.swift in Sources */, AA8D31562D41052300FE2775 /* NCManageDatabase+DownloadLimit.swift in Sources */, F711A4DF2AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */, @@ -4203,10 +4835,8 @@ F7D4BF2F2CA2E8D800A5E746 /* TOPasscodeButtonLabel.m in Sources */, F7D4BF302CA2E8D800A5E746 /* TOPasscodeViewControllerAnimatedTransitioning.m in Sources */, F7D4BF312CA2E8D800A5E746 /* TOPasscodeSettingsViewController.m in Sources */, - F71916122E2901FB00E13E96 /* NCNetworking+Upload.swift in Sources */, F7D4BF322CA2E8D800A5E746 /* TOPasscodeCircleImage.m in Sources */, F7D4BF332CA2E8D800A5E746 /* TOPasscodeView.m in Sources */, - F77E8C252E79717D00EAE68F /* NCManageDatabase+LivePhoto.swift in Sources */, F7D4BF342CA2E8D800A5E746 /* TOPasscodeCircleButton.m in Sources */, F7D4BF352CA2E8D800A5E746 /* TOPasscodeInputField.m in Sources */, F7D4BF362CA2E8D800A5E746 /* TOSettingsKeypadImage.m in Sources */, @@ -4222,6 +4852,9 @@ AF22B206277B4E4C00DAB0CC /* NCCreateFormUploadConflict.swift in Sources */, F74D50362C9856D300BBBF4C /* NCCollectionViewDataSource.swift in Sources */, F7A573692E190387009C9257 /* NCShareExtensionData.swift in Sources */, + B5BEBD862E93AEA30002C9E5 /* AnalyticsService.swift in Sources */, + B5BEBD872E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */, + B5BEBD882E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */, F7BD71E62636EAFC00643C34 /* NCNetworkingE2EE.swift in Sources */, F7F878AF1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */, F7327E3B2B73B8D600A462C7 /* Array+Extension.swift in Sources */, @@ -4233,6 +4866,8 @@ F799DF862C4B7E56003410B5 /* NCSectionHeader.swift in Sources */, F702F2D025EE5B5C008F8E80 /* NCGlobal.swift in Sources */, F72437802C10B92400C7C68D /* NCSharePermissions.swift in Sources */, + F343A4BE2A1E734600DDA874 /* Optional+Extension.swift in Sources */, + F72437802C10B92400C7C68D /* NCPermissions.swift in Sources */, F7EDE4DB262D7BA200414FE6 /* NCCellProtocol.swift in Sources */, F72944F62A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */, F73EF7BA2B0224AB0087E6E9 /* NCManageDatabase+ExternalSites.swift in Sources */, @@ -4245,6 +4880,7 @@ F749B64D297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */, F763412D2EBE255B0056F538 /* NCNetworking+NextcloudKitDelegate.swift in Sources */, F72FD3B8297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */, + B5BEBDCC2E93B0210002C9E5 /* NCSectionHeaderMenu.swift in Sources */, F7A76DC8256A71CD00119AB3 /* UIImage+Extension.swift in Sources */, F3E173C32C9B1067006D177A /* AwakeMode.swift in Sources */, F711A4E52AF9310500095DD8 /* NCUtility+Image.swift in Sources */, @@ -4252,25 +4888,36 @@ F763D2A02A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */, F757CC8529E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */, F768823A2C0DD230001CF441 /* NCPreferences.swift in Sources */, + F768823A2C0DD230001CF441 /* NCKeychain.swift in Sources */, + B5BEBDF92E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */, + B5BEBDFA2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */, + F7386E472DA90E0F009A00F6 /* NCAppVersionManager.swift in Sources */, F737DA9E2B7B893C0063BAFC /* NCPasscode.swift in Sources */, + F7817D0129802D5F00FFBC65 /* NCViewCertificateDetails.swift in Sources */, F7C30DF7291BC0D30017149B /* NCNetworkingE2EEUpload.swift in Sources */, F7C687EC2D22BDE5004757BC /* NCManageDatabase+RecommendedFiles.swift in Sources */, F33918C72C7CD8F2002D9AA1 /* FileNameValidator+Extensions.swift in Sources */, F78A10C229322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */, F79FFB272A97C24A0055EEA4 /* NCNetworkingE2EEMarkFolder.swift in Sources */, F7D68FCE28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */, - F3F442F12DDE2A7700FD701F /* NCMetadataPermissions.swift in Sources */, AF22B217277D196700DAB0CC /* NCShareExtension+DataSource.swift in Sources */, F73EF7E22B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */, F77DD6AB2C5CC093009448FB /* NCSession.swift in Sources */, F76D364728A4F8BF00214537 /* NCActivityIndicator.swift in Sources */, + B560B9612EF559C100E55904 /* NCAccountRequest.swift in Sources */, + F7BFFD2A2C8854200029A201 /* NCHud.swift in Sources */, F749B654297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */, AF22B208277B4E4C00DAB0CC /* NCCreateFormUploadConflictCell.swift in Sources */, F73EF7C22B02250B0087E6E9 /* NCManageDatabase+GPS.swift in Sources */, + F7327E2B2B73A53400A462C7 /* NCNetworking+Upload.swift in Sources */, F7148041262EBE4000693E51 /* NCShareExtension.swift in Sources */, F76B3CCF1EAE01BD00921AC9 /* NCBrand.swift in Sources */, F72944F32A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */, F7BAADCC1ED5A87C00B7EAD4 /* NCManageDatabase.swift in Sources */, + B5BEBDB22E93AF010002C9E5 /* AppUtility.swift in Sources */, + B5BEBDB32E93AF010002C9E5 /* AdjustHelper.m in Sources */, + B5BEBDB42E93AF010002C9E5 /* TealiumHelper.swift in Sources */, + B5BEBDB52E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */, F7327E322B73A86700A462C7 /* NCNetworking+WebDAV.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4279,7 +4926,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F793E5A128B76541005E4B02 /* NotificationCenter+MainThread.swift in Sources */, + B5BEBDFF2E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */, + B5BEBE002E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */, F76DEE9928F808AF0041B1C9 /* LockscreenWidgetView.swift in Sources */, + F7817D0029802D3D00FFBC65 /* NCViewCertificateDetails.swift in Sources */, F78302F928B4C3E600B84583 /* NCManageDatabase+Account.swift in Sources */, F7E0710128B13BB00001B882 /* DashboardData.swift in Sources */, F783030328B4C4DD00B84583 /* ThreadSafeDictionary.swift in Sources */, @@ -4294,15 +4945,22 @@ F711D63128F44801003F43C8 /* IntentHandler.swift in Sources */, F76DEE9728F808AF0041B1C9 /* LockscreenData.swift in Sources */, F72EA95A28B7BD0D00C88F0C /* FilesWidgetView.swift in Sources */, - F768823C2C0DD231001CF441 /* NCPreferences.swift in Sources */, + F7CF067C2E0FF3990063AD04 /* NCAppStateManager.swift in Sources */, + F768823C2C0DD231001CF441 /* NCKeychain.swift in Sources */, F71F6D082B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */, F78302FE28B4C44700B84583 /* NCBrand.swift in Sources */, F749B64B297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */, AA8D31572D41052300FE2775 /* NCManageDatabase+DownloadLimit.swift in Sources */, F7864ACD2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */, + F343A4B42A1E084100DDA874 /* PHAsset+Extension.swift in Sources */, + F793E59F28B764F6005E4B02 /* NCContentPresenter.swift in Sources */, F76DEE9828F808AF0041B1C9 /* LockscreenWidgetProvider.swift in Sources */, F78A10C029322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */, F78302FA28B4C3EA00B84583 /* NCManageDatabase+Metadata.swift in Sources */, + B5BEBDA92E93AF010002C9E5 /* AppUtility.swift in Sources */, + B5BEBDAA2E93AF010002C9E5 /* AdjustHelper.m in Sources */, + B5BEBDAB2E93AF010002C9E5 /* TealiumHelper.swift in Sources */, + B5BEBDAC2E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */, F7B769A92B7A0B2000C1AAEB /* NCManageDatabase+Metadata+Session.swift in Sources */, F78E2D6629AF02DB0024D4F3 /* Database.swift in Sources */, F77DD6A92C5CC093009448FB /* NCSession.swift in Sources */, @@ -4312,12 +4970,21 @@ F7BF9D832934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */, F757CC8329E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */, F73EF7A82B0223900087E6E9 /* NCManageDatabase+Comments.swift in Sources */, + F7327E212B73A42F00A462C7 /* NCNetworking+Download.swift in Sources */, + B5BEBD7D2E93AEA30002C9E5 /* AnalyticsService.swift in Sources */, + B5BEBD7E2E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */, + B5BEBD7F2E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */, + F7BFFD2B2C8854430029A201 /* NCHud.swift in Sources */, + F7386E492DA90E0F009A00F6 /* NCAppVersionManager.swift in Sources */, + F7327E3A2B73B8D500A462C7 /* Array+Extension.swift in Sources */, F74B6D962A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */, F711A4E32AF9310400095DD8 /* NCUtility+Image.swift in Sources */, F749B652297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */, F763D29E2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */, F711A4DD2AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */, F724377C2C10B92200C7C68D /* NCSharePermissions.swift in Sources */, + F724377C2C10B92200C7C68D /* NCPermissions.swift in Sources */, + F36E64FB2B9733F10085ABB5 /* UIView+Extension.swift in Sources */, F77ED59328C9CEA000E24ED0 /* ToolbarWidgetProvider.swift in Sources */, F72A17D828B221E300F3F159 /* DashboardWidgetView.swift in Sources */, F77ED59528C9CEA400E24ED0 /* ToolbarWidgetView.swift in Sources */, @@ -4328,12 +4995,13 @@ F77E8C242E79717D00EAE68F /* NCManageDatabase+LivePhoto.swift in Sources */, F76340F72EBDE9760056F538 /* NCManageDatabaseCore.swift in Sources */, F7D496FD2EBFA6D9004F9823 /* String+Extension.swift in Sources */, + F33918C52C7CD8F2002D9AA1 /* FileNameValidator+Extensions.swift in Sources */, + F7327E292B73A53400A462C7 /* NCNetworking+Upload.swift in Sources */, F7D7A7702DCDD437003D2007 /* NCManageDatabase+AutoUpload.swift in Sources */, F72EA95828B7BC4F00C88F0C /* FilesData.swift in Sources */, F78302FF28B4C45000B84583 /* NCUtilityFileSystem.swift in Sources */, F73EF7B82B0224AB0087E6E9 /* NCManageDatabase+ExternalSites.swift in Sources */, F73EF7C02B02250B0087E6E9 /* NCManageDatabase+GPS.swift in Sources */, - F3F442EF2DDE2A7700FD701F /* NCMetadataPermissions.swift in Sources */, F3E173C12C9B1067006D177A /* AwakeMode.swift in Sources */, F75DD766290ABB25002EB562 /* Intent.intentdefinition in Sources */, F7D68FCD28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */, @@ -4343,6 +5011,7 @@ F72FD3B6297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */, F783030128B4C49700B84583 /* UIImage+Extension.swift in Sources */, F72EA95428B7BABA00C88F0C /* FilesWidgetProvider.swift in Sources */, + B5BEBD992E93AED80002C9E5 /* AppUpdater.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4357,6 +5026,16 @@ F702F2D125EE5B5C008F8E80 /* NCGlobal.swift in Sources */, F76341012EBDF6710056F538 /* NCManageDatabase+Tag.swift in Sources */, F7434B3820E2400600417916 /* NCBrand.swift in Sources */, + F711A4E02AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */, + F76D364828A4F8BF00214537 /* NCActivityIndicator.swift in Sources */, + F7327E242B73A42F00A462C7 /* NCNetworking+Download.swift in Sources */, + F7C687ED2D22BDE5004757BC /* NCManageDatabase+RecommendedFiles.swift in Sources */, + F7817D0229802D7700FFBC65 /* NCViewCertificateDetails.swift in Sources */, + F7CF06842E1127460063AD04 /* NCManageDatabase+Metadata+Create.swift in Sources */, + F7434B3820E2400600417916 /* NCBrand.swift in Sources */, + F7327E332B73A86700A462C7 /* NCNetworking+WebDAV.swift in Sources */, + F7411C572D7B26D700F57358 /* NCNetworking+ServerError.swift in Sources */, + F724377F2C10B92400C7C68D /* NCPermissions.swift in Sources */, F785EE9E2461A09900B3F945 /* NCNetworking.swift in Sources */, F771E3D320E2392D00AFB62D /* FileProviderExtension.swift in Sources */, F7D61EAB2EBF16B6007F865B /* NCManageDatabase+TableCapabilities.swift in Sources */, @@ -4370,6 +5049,43 @@ F7E742F52EC0A3DD00E2362A /* NCManageDatabase+Directory.swift in Sources */, F7E742F92EC0A5BC00E2362A /* NCManageDatabase+Metadata.swift in Sources */, F763412E2EBE255B0056F538 /* NCNetworking+NextcloudKitDelegate.swift in Sources */, + F7D7A76F2DCDD437003D2007 /* NCManageDatabase+AutoUpload.swift in Sources */, + AF4BF616275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */, + F343A4B72A1E084300DDA874 /* PHAsset+Extension.swift in Sources */, + B5BEBD972E93AED80002C9E5 /* AppUpdater.swift in Sources */, + F7434B3620E23FE000417916 /* NCManageDatabase.swift in Sources */, + F798F0E725880609000DAFFD /* UIColor+Extension.swift in Sources */, + F74B6D992A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */, + F7327E2C2B73A53400A462C7 /* NCNetworking+Upload.swift in Sources */, + B5BEBE032E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */, + B5BEBE042E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */, + F7D68FCF28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */, + F33EE6F62BF4C9B200CA1A51 /* PKCS12.swift in Sources */, + F7A3DB922DDE23B5008F7EC8 /* NCDebouncer.swift in Sources */, + F7F3E58B2D3BB65600A32B14 /* NCNetworking+Recommendations.swift in Sources */, + F73EF7C32B02250B0087E6E9 /* NCManageDatabase+GPS.swift in Sources */, + F7C9B9212B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */, + F359D86B2A7D03420023F405 /* NCUtility+Exif.swift in Sources */, + F7864AD02A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */, + F7327E402B73B92800A462C7 /* NCNetworking+Synchronization.swift in Sources */, + AF4BF61B27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */, + F70460542499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */, + F78A10C329322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */, + F36E64FE2B9735920085ABB5 /* NCCellProtocol.swift in Sources */, + F7BF9D862934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */, + F7E98C1827E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */, + F785EEA42461A4A600B3F945 /* NCUtility.swift in Sources */, + F79B646226CA661600838ACA /* UIControl+Extension.swift in Sources */, + F7C1DAEF2C3D1DF4000BDC69 /* FileProviderDomain.swift in Sources */, + B5BEBDC22E93AF010002C9E5 /* AppUtility.swift in Sources */, + B5BEBDC32E93AF010002C9E5 /* AdjustHelper.m in Sources */, + B5BEBDC42E93AF010002C9E5 /* TealiumHelper.swift in Sources */, + B5BEBDC52E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */, + B5BEBD8F2E93AEA30002C9E5 /* AnalyticsService.swift in Sources */, + B5BEBD902E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */, + B5BEBD912E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */, + F73EF7AB2B0223900087E6E9 /* NCManageDatabase+Comments.swift in Sources */, + F7327E392B73B8D400A462C7 /* Array+Extension.swift in Sources */, F78E2D6929AF02DB0024D4F3 /* Database.swift in Sources */, F771E3F320E239A600AFB62D /* FileProviderData.swift in Sources */, F7E742F32EC0A10C00E2362A /* NCManageDatabase+Account.swift in Sources */, @@ -4378,6 +5094,12 @@ F71F6D0B2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */, F771E3F820E239B500AFB62D /* FileProviderExtension+Thumbnail.swift in Sources */, F76882392C0DD230001CF441 /* NCPreferences.swift in Sources */, + F76882392C0DD230001CF441 /* NCKeychain.swift in Sources */, + F39170AB2CB82024006127BC /* FileAutoRenamer+Extensions.swift in Sources */, + F7CF067D2E0FF3990063AD04 /* NCAppStateManager.swift in Sources */, + F343A4BF2A1E734600DDA874 /* Optional+Extension.swift in Sources */, + AF4BF62027562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */, + F73ADD2226554FD10069EA0D /* NCContentPresenter.swift in Sources */, F77DD6AC2C5CC093009448FB /* NCSession.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4398,10 +5120,15 @@ F77DD6A82C5CC093009448FB /* NCSession.swift in Sources */, F702F30825EE5D47008F8E80 /* NCPopupViewController.swift in Sources */, F76340FC2EBDF64D0056F538 /* NCManageDatabase+Tag.swift in Sources */, + F3CA33842D10726E00672333 /* NCLoginPollModel.swift in Sources */, + B5E2E7282DAE880700AB2EDD /* NCCreateFormUploadVoiceNote.swift in Sources */, + B5E2E7292DAE880700AB2EDD /* NCCreateFormUploadDocuments.swift in Sources */, + 566EB8032B3D7B5F00FB7CAD /* PasswordInputField.swift in Sources */, F733598125C1C188002ABA72 /* NCAskAuthorization.swift in Sources */, 370D26AF248A3D7A00121797 /* NCCellProtocol.swift in Sources */, F32FADA92D1176E3007035E2 /* UIButton+Extension.swift in Sources */, - F768822C2C0DD1E7001CF441 /* NCPreferences.swift in Sources */, + F768822C2C0DD1E7001CF441 /* NCKeychain.swift in Sources */, + F7BFFD282C8846020029A201 /* NCHud.swift in Sources */, F71CD6CA2930D7B1006C95C1 /* NCApplicationHandle.swift in Sources */, F3754A7D2CF87D600009312E /* SetupPasscodeView.swift in Sources */, F73EF7D72B0226080087E6E9 /* NCManageDatabase+Tip.swift in Sources */, @@ -4429,6 +5156,15 @@ F76D3CF12428B40E005DFA87 /* NCViewerPDFSearch.swift in Sources */, F7245924289BB50C00474787 /* ThreadSafeDictionary.swift in Sources */, F73F537F1E929C8500F8678D /* NCMore.swift in Sources */, + B5BEBE1A2E93BE200002C9E5 /* PNGImageSaveSwitchView.swift in Sources */, + B5BEBE1B2E93BE200002C9E5 /* FileNameInputTextField.swift in Sources */, + B5BEBE1C2E93BE200002C9E5 /* PdfWithoutOcrSwitchView.swift in Sources */, + B5BEBE1D2E93BE200002C9E5 /* TextFileWithOcrSwitchView.swift in Sources */, + B5BEBE1E2E93BE200002C9E5 /* ScanDocumentPathView.swift in Sources */, + B5BEBE1F2E93BE200002C9E5 /* SetPDFPasswordSwitchView.swift in Sources */, + B5BEBE202E93BE200002C9E5 /* JPGImageSaveSwitchView.swift in Sources */, + B5BEBE212E93BE200002C9E5 /* PasswordInputField.swift in Sources */, + B5BEBE222E93BE200002C9E5 /* PdfWithOcrSwitchView.swift in Sources */, F702F2CF25EE5B5C008F8E80 /* NCGlobal.swift in Sources */, F794E13F2BBC0F70003693D7 /* SceneDelegate.swift in Sources */, F714A1472ED84AF90050A43B /* HudBannerView.swift in Sources */, @@ -4436,6 +5172,7 @@ F72CD63A25C19EBF00F46F9A /* NCAutoUpload.swift in Sources */, AF93471D27E2361E002537EE /* NCShareAdvancePermissionFooter.swift in Sources */, AF1A9B6427D0CA1E00F17A9E /* UIAlertController+Extension.swift in Sources */, + F73B422C2476764F00A30FD3 /* NCNotification.swift in Sources */, F7FA80012C0F4F3B0072FC60 /* NCUploadAssetsView.swift in Sources */, 371B5A2E23D0B04500FAFAE9 /* NCMenu.swift in Sources */, F74230F32C79B57200CA1ACA /* NCNetworking+Task.swift in Sources */, @@ -4446,7 +5183,9 @@ F77444F8222816D5000D5EB0 /* NCPickerViewController.swift in Sources */, F77BB74A2899857B0090FC19 /* UINavigationController+Extension.swift in Sources */, F70898672EDDB39B00EF85BD /* NCNetworking+TransferDelegate.swift in Sources */, + F7327E282B73A53400A462C7 /* NCNetworking+Upload.swift in Sources */, F769454622E9F1B0000A798A /* NCShareCommon.swift in Sources */, + B5BEBDC92E93AFF10002C9E5 /* NCSelectableNavigationView.swift in Sources */, F70753F12542A9A200972D44 /* NCViewerMedia.swift in Sources */, F799DF822C4B7DCC003410B5 /* NCSectionFooter.swift in Sources */, F76B649C2ADFFAED00014640 /* NCImageCache.swift in Sources */, @@ -4456,6 +5195,7 @@ F768822E2C0DD1E7001CF441 /* NCSettingsBundleHelper.swift in Sources */, F72408332B8A27C900F128E2 /* NCMedia+Command.swift in Sources */, F755CB402B8CB13C00CE27E9 /* NCMediaLayout.swift in Sources */, + B5BEBDCE2E93B0210002C9E5 /* NCSectionHeaderMenu.swift in Sources */, F73EF7B72B0224AB0087E6E9 /* NCManageDatabase+ExternalSites.swift in Sources */, AF4BF61927562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */, F78A18B623CDD07D00F681F3 /* NCViewerRichWorkspaceWebView.swift in Sources */, @@ -4466,15 +5206,13 @@ F758B460212C56A400515F55 /* NCScan.swift in Sources */, F76882262C0DD1E7001CF441 /* NCSettingsView.swift in Sources */, F78ACD52219046DC0088454D /* NCSectionFirstHeader.swift in Sources */, - F743C89E2E5B25A1000173A9 /* UIScene+Extension.swift in Sources */, F72944F52A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */, - F710D2022405826100A6033D /* NCViewerContextMenu.swift in Sources */, + F710D2022405826100A6033D /* NCViewer+Menu.swift in Sources */, F765E9CD295C585800A09ED8 /* NCUploadScanDocument.swift in Sources */, F741C2242B6B9FD600E849BB /* NCMediaSelectTabBar.swift in Sources */, F77A697D250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift in Sources */, F7BF9D822934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */, AA8D31662D411FA100FE2775 /* NCShareDateCell.swift in Sources */, - F3F442EE2DDE292D00FD701F /* NCMetadataPermissions.swift in Sources */, F3374A812D64AB9F002A38F9 /* StatusInfo.swift in Sources */, AF7E504E27A2D8FF00B5E4AF /* UIBarButton+Extension.swift in Sources */, AA8D31682D41224800FE2775 /* NCShareToggleCell.swift in Sources */, @@ -4483,7 +5221,6 @@ F78A10BF29322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */, F7743A122C33F0A20034F670 /* NCCollectionViewCommon+CollectionViewDelegate.swift in Sources */, F7D60CAF2C941ACB008FBFDD /* NCMediaPinchGesture.swift in Sources */, - F71916142E2901FB00E13E96 /* NCNetworking+Upload.swift in Sources */, F704B5E92430C0B800632F5F /* NCCreateFormUploadConflictCell.swift in Sources */, F72D404923D2082500A97FD0 /* NCViewerNextcloudText.swift in Sources */, AFCE353927E5DE0500FEA6C2 /* Shareable.swift in Sources */, @@ -4492,7 +5229,7 @@ F72D1007210B6882009C96B7 /* NCPushNotificationEncryption.m in Sources */, F76882362C0DD1E7001CF441 /* NCAcknowledgementsView.swift in Sources */, F785EE9D246196DF00B3F945 /* NCNetworkingE2EE.swift in Sources */, - F724377B2C10B83E00C7C68D /* NCSharePermissions.swift in Sources */, + F724377B2C10B83E00C7C68D /* NCPermissions.swift in Sources */, F794E13D2BBBFF2E003693D7 /* NCMainTabBarController.swift in Sources */, F7CBC1252BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.swift in Sources */, F7D4BF3D2CA2E8D800A5E746 /* TOPasscodeKeypadView.m in Sources */, @@ -4532,9 +5269,18 @@ F7CEE6012BA9A5C9003EFD89 /* NCTrashGridCell.swift in Sources */, F70557BD2ED44F1800135623 /* UploadBannerView.swift in Sources */, F70557BE2ED44F1800135623 /* ErrorBannerView.swift in Sources */, + 566EB8062B3D7B5F00FB7CAD /* PdfWithOcrSwitchView.swift in Sources */, + F77B0E5F1D118A16002130FE /* NCSettings.m in Sources */, + 566EB8062B3D7B5F00FB7CAD /* PdfWithOcrSwitchView.swift in Sources */, F7F9D1BB25397CE000D9BFF5 /* NCViewer.swift in Sources */, F7E7AEA52BA32C6500512E52 /* NCCollectionViewDownloadThumbnail.swift in Sources */, AF730AF827834B1400B7520E /* NCShare+NCCellDelegate.swift in Sources */, + B560B95A2EF5597A00E55904 /* NCAccount.swift in Sources */, + B560B95B2EF5597A00E55904 /* NCShareAccounts.swift in Sources */, + B560B95C2EF5597A00E55904 /* NCAccountSettingsModel.swift in Sources */, + B560B95D2EF5597A00E55904 /* NCAccountSettingsView.swift in Sources */, + B560B95E2EF5597A00E55904 /* NCAccountRequest.swift in Sources */, + B5BEBE062E93BE0C0002C9E5 /* NCCreateFormUploadScanDocument.swift in Sources */, F70460522499061800BB98A7 /* NotificationCenter+MainThread.swift in Sources */, F3C587AE2D47E4FE004532DB /* PHAssetCollectionThumbnailLoader.swift in Sources */, F78F74362163781100C2ADAD /* NCTrash.swift in Sources */, @@ -4563,6 +5309,7 @@ F7F878AE1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */, F7A7FDDD2C2DBD6200E9A93A /* NCDeepLinkHandler.swift in Sources */, F778231E2C42C07C001BB94F /* NCCollectionViewCommon+MediaLayout.swift in Sources */, + 3781B9B023DB2B7E006B4B1D /* AppDelegate+Menu.swift in Sources */, F710D1F52405770F00A6033D /* NCViewerPDF.swift in Sources */, F389C9F52CEE383300049762 /* SelectAlbumView.swift in Sources */, F7B6B70427C4E7FA00A7F6EB /* NCScan+CollectionView.swift in Sources */, @@ -4597,6 +5344,7 @@ F765F73125237E3F00391DBE /* NCRecent.swift in Sources */, F76B3CCE1EAE01BD00921AC9 /* NCBrand.swift in Sources */, F7FA7FFC2C0F4EE40072FC60 /* NCViewerQuickLookView.swift in Sources */, + B5BEBDC72E93AF7E0002C9E5 /* NCLoginWeb.swift in Sources */, F3A0479B2BD2668800658E7B /* NCAssistant.swift in Sources */, F359D8672A7D03420023F405 /* NCUtility+Exif.swift in Sources */, F7A03E352D427312007AA677 /* NCMainNavigationController.swift in Sources */, @@ -4606,7 +5354,6 @@ F702F30125EE5D2C008F8E80 /* NYMnemonic.m in Sources */, AF93474E27E3F212002537EE /* NCShareNewUserAddComment.swift in Sources */, F7C30DFD291BD0B80017149B /* NCNetworkingE2EEDelete.swift in Sources */, - F77E8C232E79717D00EAE68F /* NCManageDatabase+LivePhoto.swift in Sources */, F76882302C0DD1E7001CF441 /* NCFileNameModel.swift in Sources */, F7CF06882E1127460063AD04 /* NCManageDatabase+CreateMetadata.swift in Sources */, F72FD3B5297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */, @@ -4615,7 +5362,6 @@ AF93471227E2341B002537EE /* NCShare+Menu.swift in Sources */, F7EFA47825ADBA500083159A /* NCViewerProviderContextMenu.swift in Sources */, F755BD9B20594AC7008C5FBB /* NCService.swift in Sources */, - F376A3742E5CC6030067EE25 /* ContextMenuActions.swift in Sources */, F7E8A391295DC5E0006CB2D0 /* View+Extension.swift in Sources */, F79B869B265E19D40085C0E0 /* NSMutableAttributedString+Extension.swift in Sources */, F7B7504B2397D38F004E13EC /* UIImage+Extension.swift in Sources */, @@ -4624,13 +5370,12 @@ F76D364628A4F8BF00214537 /* NCActivityIndicator.swift in Sources */, F3A047992BD2668800658E7B /* NCAssistantModel.swift in Sources */, F76882322C0DD1E7001CF441 /* NCAutoUploadView.swift in Sources */, - F36E64F72B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBarDelegate.swift in Sources */, + F36E64F72B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBar.swift in Sources */, F79A65C62191D95E00FF6DCC /* NCSelect.swift in Sources */, F75D19E325EFE09000D74598 /* NCTrash+Menu.swift in Sources */, F34E1ADB2ECC842B00FA10C3 /* NCStatusMessageModel.swift in Sources */, F70CAE3A1F8CF31A008125FD /* NCEndToEndEncryption.m in Sources */, AA8D316E2D4123B200FE2775 /* NCShareDownloadLimitTableViewControllerDelegate.swift in Sources */, - F36C514F2E89393C0097E5F7 /* UIView+BlurVibrancy.swift in Sources */, AA8D316F2D4123B200FE2775 /* NCShareDownloadLimitTableViewController.swift in Sources */, AA8D31702D4123B200FE2775 /* DownloadLimitViewModel.swift in Sources */, AA8D31712D4123B200FE2775 /* NCShareDownloadLimitViewController.swift in Sources */, @@ -4646,7 +5391,6 @@ F749B651297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */, F7FAFD3A28BFA948000777FE /* NCNotification+Menu.swift in Sources */, F74C0436253F1CDC009762AB /* NCShares.swift in Sources */, - F79699E72E689F68000EC82A /* NCMediaNavigationController.swift in Sources */, F7AC1CB028AB94490032D99F /* Array+Extension.swift in Sources */, F7AE00F5230D5F9E007ACF8A /* NCLoginProvider.swift in Sources */, F707C26521A2DC5200F6181E /* NCStoreReview.swift in Sources */, @@ -4659,19 +5403,21 @@ F343A4B32A1E01FF00DDA874 /* PHAsset+Extension.swift in Sources */, F70968A424212C4E00ED60E5 /* NCLivePhoto.swift in Sources */, F7C30DFA291BCF790017149B /* NCNetworkingE2EECreateFolder.swift in Sources */, + B5BEBDDC2E93B2450002C9E5 /* NCCreateFormUploadDocuments.swift in Sources */, + B5BEBDDD2E93B2450002C9E5 /* TextTableViewCell.swift in Sources */, + B5BEBDDE2E93B2450002C9E5 /* NCCreateFormUploadVoiceNote.swift in Sources */, F722133B2D40EF9D002F7438 /* NCFilesNavigationController.swift in Sources */, F7BC288026663F85004D46C5 /* NCViewCertificateDetails.swift in Sources */, F78B87E92B62550800C65ADC /* NCMediaDownloadThumbnail.swift in Sources */, D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */, F745B253222D88AE00346520 /* NCLoginQRCode.swift in Sources */, - F7FDFF6B2E437E55000D7688 /* NCAccountRequest.swift in Sources */, - F7FDFF6C2E437E55000D7688 /* NCShareAccounts.swift in Sources */, - F7FDFF6D2E437E55000D7688 /* NCAccountSettingsModel.swift in Sources */, - F7FDFF6E2E437E55000D7688 /* NCAccountSettingsView.swift in Sources */, - F7FDFF6F2E437E55000D7688 /* NCAccount.swift in Sources */, F769454822E9F20D000A798A /* NCShareNetworking.swift in Sources */, F749B64A297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */, F7C9555521F0C5470024296E /* NCActivity.swift in Sources */, + B5BEBDA32E93AF010002C9E5 /* AppUtility.swift in Sources */, + B5BEBDA42E93AF010002C9E5 /* AdjustHelper.m in Sources */, + B5BEBDA52E93AF010002C9E5 /* TealiumHelper.swift in Sources */, + B5BEBDA62E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */, F7725A60251F33BB00D125E0 /* NCFiles.swift in Sources */, F3BB46522A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift in Sources */, F704B5E52430AA8000632F5F /* NCCreateFormUploadConflict.swift in Sources */, @@ -4692,15 +5438,19 @@ F70CEF5623E9C7E50007035B /* UIColor+Extension.swift in Sources */, F76882242C0DD1E7001CF441 /* NCSettingsAdvancedView.swift in Sources */, F785129C2D7989B30087DDD0 /* NCNetworking+TermsOfService.swift in Sources */, + B5BEBDF12E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */, + B5BEBDF22E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */, F77C3F5B2D9BF8CD00F3C471 /* UITabBar+Extension.swift in Sources */, F7D7A76E2DCDD437003D2007 /* NCManageDatabase+AutoUpload.swift in Sources */, - F7F563042E15762B00631A11 /* MigrationMultiDomains.swift in Sources */, F75CA1472962F13700B01130 /* NCHUDView.swift in Sources */, F77BB748289985270090FC19 /* UITabBarController+Extension.swift in Sources */, - F752BA052E58C05200616A26 /* Maintenance.swift in Sources */, + B5BEBD982E93AED80002C9E5 /* AppUpdater.swift in Sources */, F763D29D2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */, F76882252C0DD1E7001CF441 /* NCSettingsAdvancedModel.swift in Sources */, F7C7B489245EBA4100D93E60 /* NCViewerQuickLook.swift in Sources */, + B5BEBD892E93AEA30002C9E5 /* AnalyticsService.swift in Sources */, + B5BEBD8A2E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */, + B5BEBD8B2E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */, F758B45E212C569D00515F55 /* NCScanCell.swift in Sources */, F78B87E72B62527100C65ADC /* NCMediaDataSource.swift in Sources */, F76882272C0DD1E7001CF441 /* NCManageE2EEView.swift in Sources */, @@ -4736,14 +5486,21 @@ F7F1FB9D2E27CE7200C79E20 /* NCNetworking.swift in Sources */, F7A8D73528F17E16008BBE1C /* NCManageDatabase.swift in Sources */, F3F442F02DDE2A7700FD701F /* NCMetadataPermissions.swift in Sources */, + F343A4BD2A1E734600DDA874 /* Optional+Extension.swift in Sources */, + F7A8D73528F17E16008BBE1C /* NCManageDatabase.swift in Sources */, F7A8D74428F1827B008BBE1C /* ThreadSafeDictionary.swift in Sources */, F7C9739528F17131002C43E2 /* IntentHandler.swift in Sources */, F7A8D73D28F181D3008BBE1C /* NCUtilityFileSystem.swift in Sources */, + B5BEBD802E93AEA30002C9E5 /* AnalyticsService.swift in Sources */, + B5BEBD812E93AEA30002C9E5 /* MoEngageAnalytics.swift in Sources */, + B5BEBD822E93AEA30002C9E5 /* AnalyticsHelper.swift in Sources */, F73EF7E12B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */, F7C9B91F2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */, F75DD767290ABB25002EB562 /* Intent.intentdefinition in Sources */, F72437812C10B92500C7C68D /* NCSharePermissions.swift in Sources */, F7D61EBE2EBF1878007F865B /* NCManageDatabase+Tag.swift in Sources */, + F72437812C10B92500C7C68D /* NCPermissions.swift in Sources */, + F39170A92CB82024006127BC /* FileAutoRenamer+Extensions.swift in Sources */, F749B64C297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */, F7A8D73F28F181EF008BBE1C /* NCGlobal.swift in Sources */, F74B6D972A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */, @@ -4752,11 +5509,19 @@ F763D29F2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */, F7A8D73728F17E1E008BBE1C /* NCManageDatabase+Account.swift in Sources */, F77E8C202E79717D00EAE68F /* NCManageDatabase+LivePhoto.swift in Sources */, + F7A8D74328F1826F008BBE1C /* String+Extension.swift in Sources */, + F73EF7A32B021FAC0087E6E9 /* NCLivePhoto.swift in Sources */, + B5BEBD9A2E93AED80002C9E5 /* AppUpdater.swift in Sources */, + F7A8D73728F17E1E008BBE1C /* NCManageDatabase+Account.swift in Sources */, + F7817CFA29801A3500FFBC65 /* Data+Extension.swift in Sources */, F7BF9D842934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */, F73EF7A92B0223900087E6E9 /* NCManageDatabase+Comments.swift in Sources */, + F7CF06812E0FF3990063AD04 /* NCAppStateManager.swift in Sources */, F7A8D73C28F181BC008BBE1C /* NCBrand.swift in Sources */, F711A4DE2AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */, - F768823B2C0DD231001CF441 /* NCPreferences.swift in Sources */, + F768823B2C0DD231001CF441 /* NCKeychain.swift in Sources */, + B5BEBDE92E93BDB40002C9E5 /* FolderPathCustomCell.swift in Sources */, + B5BEBDEA2E93BDB40002C9E5 /* NCCreateDocumentCustomTextField.swift in Sources */, AA8D31532D41052300FE2775 /* NCManageDatabase+DownloadLimit.swift in Sources */, F7A8D74228F18261008BBE1C /* NCUtility.swift in Sources */, F7A8D73A28F17E28008BBE1C /* NCManageDatabase+Video.swift in Sources */, @@ -4774,6 +5539,10 @@ F7B769AA2B7A0B2000C1AAEB /* NCManageDatabase+Metadata+Session.swift in Sources */, F7A8D74028F18212008BBE1C /* UIImage+Extension.swift in Sources */, F73EF7B92B0224AB0087E6E9 /* NCManageDatabase+ExternalSites.swift in Sources */, + B5BEBDBC2E93AF010002C9E5 /* AppUtility.swift in Sources */, + B5BEBDBD2E93AF010002C9E5 /* AdjustHelper.m in Sources */, + B5BEBDBE2E93AF010002C9E5 /* TealiumHelper.swift in Sources */, + B5BEBDBF2E93AF010002C9E5 /* NCEmptyDataSet.swift in Sources */, F71F6D092B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */, F757CC8429E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */, F78E2D6729AF02DB0024D4F3 /* Database.swift in Sources */, @@ -5074,7 +5843,6 @@ EXTENSION_NOTIFICATION_SERVICE, ); INFOPLIST_FILE = "$(SRCROOT)/Brand/Notification_Service_Extension.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "it.twsweb.Nextcloud.Notification-Service-Extension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5099,7 +5867,6 @@ EXTENSION_NOTIFICATION_SERVICE, ); INFOPLIST_FILE = "$(SRCROOT)/Brand/Notification_Service_Extension.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "it.twsweb.Nextcloud.Notification-Service-Extension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5360,7 +6127,6 @@ ); INFOPLIST_FILE = "$(SRCROOT)/Brand/File_Provider_Extension_UI.plist"; INFOPLIST_KEY_CFBundleDisplayName = "File Provider Extension UI"; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ""; @@ -5388,7 +6154,6 @@ ); INFOPLIST_FILE = "$(SRCROOT)/Brand/File_Provider_Extension_UI.plist"; INFOPLIST_KEY_CFBundleDisplayName = "File Provider Extension UI"; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ""; @@ -5414,7 +6179,6 @@ EXTENSION_SHARE, ); INFOPLIST_FILE = "$(SRCROOT)/Brand/Share.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = it.twsweb.Nextcloud.Share; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5439,7 +6203,6 @@ EXTENSION_SHARE, ); INFOPLIST_FILE = "$(SRCROOT)/Brand/Share.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = it.twsweb.Nextcloud.Share; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5471,7 +6234,6 @@ GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "$(SRCROOT)/Brand/Widget.plist"; INFOPLIST_KEY_CFBundleDisplayName = Nextcloud; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ""; @@ -5506,7 +6268,6 @@ GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "$(SRCROOT)/Brand/Widget.plist"; INFOPLIST_KEY_CFBundleDisplayName = Nextcloud; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ""; @@ -5535,7 +6296,6 @@ EXTENSION_FILE_PROVIDER_EXTENSION, ); INFOPLIST_FILE = "$(SRCROOT)/Brand/File_Provider_Extension.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "it.twsweb.Nextcloud.File-Provider-Extension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5559,7 +6319,6 @@ EXTENSION_FILE_PROVIDER_EXTENSION, ); INFOPLIST_FILE = "$(SRCROOT)/Brand/File_Provider_Extension.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "it.twsweb.Nextcloud.File-Provider-Extension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5581,7 +6340,7 @@ DEVELOPMENT_TEAM = NKUJUXUJ3B; GCC_SYMBOLS_PRIVATE_EXTERN = YES; INFOPLIST_FILE = "$(SRCROOT)/Brand/iOSClient.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 15; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "it.twsweb.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5604,7 +6363,7 @@ DEVELOPMENT_TEAM = NKUJUXUJ3B; GCC_SYMBOLS_PRIVATE_EXTERN = YES; INFOPLIST_FILE = "$(SRCROOT)/Brand/iOSClient.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 15; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "it.twsweb.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5642,7 +6401,6 @@ GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "$(SRCROOT)/Brand/WidgetDashboardIntentHandler.plist"; INFOPLIST_KEY_CFBundleDisplayName = WidgetDashboardIntentHandler; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ""; @@ -5683,7 +6441,6 @@ GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "$(SRCROOT)/Brand/WidgetDashboardIntentHandler.plist"; INFOPLIST_KEY_CFBundleDisplayName = WidgetDashboardIntentHandler; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ""; @@ -5703,7 +6460,6 @@ F7F67BC91A24D27800EE80DA /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ENABLE_MODULES = YES; @@ -5749,7 +6505,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Nextcloud. All rights reserved."; - IPHONEOS_DEPLOYMENT_TARGET = 17.6; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -5759,6 +6515,7 @@ ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "-v"; OTHER_LDFLAGS = ""; + SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) NC DEBUG"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -5769,7 +6526,6 @@ F7F67BCA1A24D27800EE80DA /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ENABLE_MODULES = YES; @@ -5812,7 +6568,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Nextcloud. All rights reserved."; - IPHONEOS_DEPLOYMENT_TARGET = 17.6; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -5822,6 +6578,7 @@ ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "-v"; OTHER_LDFLAGS = ""; + SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) NC"; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; @@ -5980,7 +6737,7 @@ repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 12.0.0; + minimumVersion = 8.9.0; }; }; F710FC78277B7CFF00AA9FBF /* XCRemoteSwiftPackageReference "realm-swift" */ = { @@ -6001,10 +6758,10 @@ }; F734B06428E75C0100E180D5 /* XCRemoteSwiftPackageReference "TLPhotoPicker" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/tilltue/TLPhotoPicker"; + repositoryURL = "https://github.com/marinofaggiana/TLPhotoPicker"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.0.0; + branch = master; + kind = branch; }; }; F73ADD1A265546880069EA0D /* XCRemoteSwiftPackageReference "SwiftEntryKit" */ = { @@ -6012,7 +6769,7 @@ repositoryURL = "https://github.com/huri000/SwiftEntryKit"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 2.0.0; + minimumVersion = 1.2.7; }; }; F753BA91281FD8010015BFB6 /* XCRemoteSwiftPackageReference "EasyTipView" */ = { @@ -6052,7 +6809,7 @@ repositoryURL = "https://github.com/nicklockwood/LRUCache"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 1.0.7; + minimumVersion = 1.0.4; }; }; F76DA961277B760E0082465B /* XCRemoteSwiftPackageReference "Queuer" */ = { @@ -6075,8 +6832,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/scenee/FloatingPanel"; requirement = { - kind = upToNextMinorVersion; - minimumVersion = 3.0.0; + kind = exactVersion; + version = 2.8.6; }; }; F77333862927A72100466E35 /* XCRemoteSwiftPackageReference "OpenSSL" */ = { @@ -6099,7 +6856,7 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/nextcloud/NextcloudKit"; requirement = { - branch = main; + branch = 7.0.2; kind = branch; }; }; diff --git a/Tests/Common/BaseXCTestCase.swift b/Tests/Common/BaseXCTestCase.swift new file mode 100644 index 0000000000..5c03bc5384 --- /dev/null +++ b/Tests/Common/BaseXCTestCase.swift @@ -0,0 +1,38 @@ +// +// BaseXCTestCase.swift +// Nextcloud +// +// Created by Milen on 20.03.24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// + +import XCTest +import Foundation +import UIKit +import Alamofire +import NextcloudKit +@testable import Nextcloud + +class BaseXCTestCase: XCTestCase { + var appToken = "" + + func setupAppToken() { + let expectation = expectation(description: "Should get app token") + + NextcloudKit.shared.getAppPassword(url: TestConstants.server, user: TestConstants.username, password: TestConstants.password) { token, _, error in + XCTAssertEqual(error.errorCode, 0) + XCTAssertNotNil(token) + + guard let token else { return XCTFail() } + + self.appToken = token + expectation.fulfill() + } + + waitForExpectations(timeout: TestConstants.timeoutLong) + } + + override func setUpWithError() throws { + setupAppToken() + } +} diff --git a/Tests/Common/TestConstants.swift b/Tests/Common/TestConstants.swift new file mode 100644 index 0000000000..5022e70803 --- /dev/null +++ b/Tests/Common/TestConstants.swift @@ -0,0 +1,53 @@ +// +// Copyright (c) 2023 Marcel Müller +// +// Author Marcel Müller +// +// GNU GPL version 3 or any later version +// +// 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 . +// + +import Foundation +import UIKit + +/// +/// Immutable test configuration. +/// +enum TestConstants { + /// + /// The default number of seconds to wait for the appearance of user interface controls during user interface tests. + /// + static let controlExistenceTimeout: Double = 10 + + /// + /// The full base URL for the server to run against. + /// + static let server = "http://localhost:8080" + + /// + /// Default user name to sign in with. + /// + static let username = "admin" + + /// + /// Password of the default user name to sign in with. + /// + static let password = "admin" + + /// + /// Account identifier of the default user to test with. + /// + static let account = "\(username) \(server)" +} diff --git a/Tests/NextcloudIntegrationTests/BaseIntegrationXCTestCase.swift b/Tests/NextcloudIntegrationTests/BaseIntegrationXCTestCase.swift new file mode 100644 index 0000000000..703aa37f07 --- /dev/null +++ b/Tests/NextcloudIntegrationTests/BaseIntegrationXCTestCase.swift @@ -0,0 +1,29 @@ +// +// BaseIntegrationXCTestCase.swift +// +// +// Created by Milen Pivchev on 20.06.23. +// Copyright © 2023 Milen Pivchev. All rights reserved. +// +// Author: Milen Pivchev +// 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 . +// + +class BaseIntegrationXCTestCase: BaseXCTestCase { + var randomInt: Int { + get { + return Int.random(in: 1000...Int.max) + } + } +} diff --git a/Tests/NextcloudIntegrationTests/FilesIntegrationTests.swift b/Tests/NextcloudIntegrationTests/FilesIntegrationTests.swift new file mode 100644 index 0000000000..c1bcbca235 --- /dev/null +++ b/Tests/NextcloudIntegrationTests/FilesIntegrationTests.swift @@ -0,0 +1,94 @@ +// +// NextcloudIntegrationTests.swift +// NextcloudIntegrationTests +// +// Created by Milen Pivchev on 5/19/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// +// 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 . +// + +import XCTest +import NextcloudKit +@testable import Nextcloud + +final class FilesIntegrationTests: BaseIntegrationXCTestCase { + + override func setUp() { + NCAccount().deleteAllAccounts() + } + +// func test_createReadDeleteFolder_withProperParams_shouldCreateReadDeleteFolder() throws { +// let expectation = expectation(description: "Should finish last callback") +// +// let folderName = "TestFolder\(randomInt)" +// let serverUrl = "\(TestConstants.server)/remote.php/dav/files/\(TestConstants.username)" +// let serverUrlFileName = "\(serverUrl)/\(folderName)" +// +// NCSession.shared.appendSession(account: TestConstants.account, urlBase: TestConstants.server, user: TestConstants.username, userId: TestConstants.username) +// let session = NCSession.shared.getSession(account: TestConstants.account) +// +// NextcloudKit.shared.setup(delegate: NCNetworking.shared) +// NextcloudKit.shared.appendSession(account: TestConstants.account, urlBase: TestConstants.server, user: TestConstants.username, userId: TestConstants.username, password: appToken, userAgent: userAgent, nextcloudVersion: 0, groupIdentifier: NCBrandOptions.shared.capabilitiesGroup) +// +// // Test creating folder +// NCNetworking.shared.createFolder(fileName: folderName, serverUrl: serverUrl, overwrite: true, withPush: true, metadata: nil, sceneIdentifier: nil, session: session ) { error in +// +// XCTAssertEqual(NKError.success.errorCode, error.errorCode) +// XCTAssertEqual(NKError.success.errorDescription, error.errorDescription) +// +// Thread.sleep(forTimeInterval: 1) +// +// // Test reading folder, should exist +// NCNetworking.shared.readFolder(serverUrl: serverUrlFileName, account: TestConstants.username, checkResponseDataChanged: false, queue: .main) { account, metadataFolder, _, _, _ in +// +// XCTAssertEqual(TestConstants.account, account) +// XCTAssertEqual(NKError.success.errorCode, error.errorCode) +// XCTAssertEqual(NKError.success.errorDescription, error.errorDescription) +// XCTAssertEqual(metadataFolder?.fileName, folderName) +// +// // Check Realm directory, should exist +// let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "serverUrl == %@", serverUrlFileName)) +// XCTAssertNotNil(directory) +// +// Thread.sleep(forTimeInterval: 1) +// +// Task { +// // Test deleting folder +// await _ = NCNetworking.shared.deleteFileOrFolder(serverUrlFileName: serverUrlFileName, account: TestConstants.account) +// +// XCTAssertEqual(NKError.success.errorCode, error.errorCode) +// XCTAssertEqual(NKError.success.errorDescription, error.errorDescription) +// +// try await Task.sleep(for: .seconds(1)) +// +// // Test reading folder, should NOT exist +// NCNetworking.shared.readFolder(serverUrl: serverUrlFileName, account: TestConstants.username, checkResponseDataChanged: false, queue: .main) { account, metadataFolder, _, _, _ in +// +// defer { expectation.fulfill() } +// +// XCTAssertEqual(0, error.errorCode) +// XCTAssertNil(metadataFolder?.fileName) +// +// // Check Realm directory, should NOT exist +// let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "serverUrl == %@", serverUrlFileName)) +// XCTAssertNil(directory) +// } +// } +// } +// } +// +// waitForExpectations(timeout: TestConstants.timeoutLong) +// } +} diff --git a/Tests/NextcloudIntegrationTests/Placeholder.swift b/Tests/NextcloudIntegrationTests/Placeholder.swift deleted file mode 100644 index 6cc0aa6c4b..0000000000 --- a/Tests/NextcloudIntegrationTests/Placeholder.swift +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-FileCopyrightText: Nextcloud GmbH -// SPDX-FileCopyrightText: 2025 Iva Horn -// SPDX-License-Identifier: GPL-3.0-or-later - -// There are no unit tests yet. -// This is an empty placeholder file. -// The compiler requires at least an empty file for every target. diff --git a/Tests/NextcloudUnitTests/AssetUploadTest.swift b/Tests/NextcloudUnitTests/AssetUploadTest.swift new file mode 100644 index 0000000000..72f541042b --- /dev/null +++ b/Tests/NextcloudUnitTests/AssetUploadTest.swift @@ -0,0 +1,36 @@ +// +// AssetUploadTest.swift +// NextcloudTests +// +// Created by A200020526 on 12/06/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import XCTest + +final class AssetUploadTest: 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. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/Tests/NextcloudUnitTests/AudioUploadTests.swift b/Tests/NextcloudUnitTests/AudioUploadTests.swift new file mode 100644 index 0000000000..2ea01a8085 --- /dev/null +++ b/Tests/NextcloudUnitTests/AudioUploadTests.swift @@ -0,0 +1,52 @@ +// +// AudioUploadTests.swift +// NextcloudTests +// +// Created by A200020526 on 13/06/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import XCTest +@testable import Nextcloud + +final class AudioUploadTests: XCTestCase { + var viewController:NCAudioRecorderViewController? + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + // Step 1. Create an instance of UIStoryboard + let viewController = UIStoryboard(name: "NCAudioRecorderViewController", bundle: nil).instantiateInitialViewController() as? NCAudioRecorderViewController + // Step 3. Make the viewDidLoad() execute. + viewController?.loadViewIfNeeded() + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + viewController = nil + } + + 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. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + + func testAudioMeterUpdateAfterDb(){ + viewController?.audioMeterDidUpdate(0.5) + XCTAssertNotNil(!(viewController?.durationLabel.text?.isEmpty ?? false)) + } + + func testStartRecorder(){ + viewController?.startStop() + XCTAssertEqual(viewController?.recording.state, nil, "Test start audio recorder") + } +} diff --git a/Tests/NextcloudUnitTests/CollaboraTestCase.swift b/Tests/NextcloudUnitTests/CollaboraTestCase.swift new file mode 100644 index 0000000000..51b3ecce1f --- /dev/null +++ b/Tests/NextcloudUnitTests/CollaboraTestCase.swift @@ -0,0 +1,142 @@ +// +// CollaboraTestCase.swift +// NextcloudTests +// +// Created by A200073704 on 06/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest +import NextcloudKit + +class CollaboraTestCase: 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 testCollaboraDocumentIsPresent() { + + var viewForDocument: NCMenuAction? + + if let image = UIImage(named: "create_file_document") { + viewForDocument = NCMenuAction(title: NSLocalizedString("_create_new_document_", comment: ""), icon: image, action: { _ in + guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController() as? UINavigationController else { + return + } + + let viewController = navigationController.topViewController as? NCCreateFormUploadDocuments + viewController?.titleForm = NSLocalizedString("_create_new_document_", comment: "") + }) + } + + XCTAssertNotNil(viewForDocument) + + } + + func testCollaboraPresentationIsPresent() { + + var viewForPresentation: NCMenuAction? + + if let image = UIImage(named: "create_file_ppt") { + viewForPresentation = NCMenuAction(title: NSLocalizedString("_create_new_presentation_", comment: ""), icon: image, action: { _ in + guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController() as? UINavigationController else { + return + } + + let viewController = navigationController.topViewController as? NCCreateFormUploadDocuments + viewController?.titleForm = NSLocalizedString("_create_new_presentation_", comment: "") + }) + } + + XCTAssertNotNil(viewForPresentation) + + } + + func testCollaboraSpreadsheetIsPresent() { + + var viewForSpreadsheet: NCMenuAction? + + if let image = UIImage(named: "create_file_xls") { + viewForSpreadsheet = NCMenuAction(title: NSLocalizedString("_create_new_spreadsheet_", comment: ""), icon: image, action: { _ in + guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController() as? UINavigationController else { + return + } + + let viewController = navigationController.topViewController as? NCCreateFormUploadDocuments + viewController?.titleForm = NSLocalizedString("_create_new_spreadsheet_", comment: "") + }) + } + + XCTAssertNotNil(viewForSpreadsheet) + + } + + func testTextDocumentIsPresent() { + + var textMenu: NCMenuAction? + + if let image = UIImage(named: "file_txt_menu") { + textMenu = NCMenuAction(title: NSLocalizedString("_create_nextcloudtext_document_", comment: ""), icon: image, action: { _ in + guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController() as? UINavigationController else { + return + } + + let viewController = navigationController.topViewController as? NCCreateFormUploadDocuments + viewController?.titleForm = NSLocalizedString("_create_nextcloudtext_document_", comment: "") + }) + } + + XCTAssertNotNil(textMenu) + + } + + func testTextDocumentAction() { + + let text = NCGlobal.shared.actionTextDocument + XCTAssertNotNil(text, "Text Editor Should be opened") + } + + func testTextFieldIsPresent() { + + let storyboard = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil) + guard let viewController = storyboard.instantiateInitialViewController() as? NCCreateFormUploadDocuments else { + return + } + + // Verify that a text field is present in the view controller + let textFields = viewController.view.subviews.filter { $0 is UITextField } + XCTAssertFalse(textFields.isEmpty, "No text field found in NCCreateFormUploadDocuments") + } + + func testSavePathFolder() { + + let viewController = NCCreateFormUploadDocuments() + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var row : XLFormRowDescriptor + + // the section with the title "Folder Destination" + + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: "kNMCFolderCustomCellType", title: "") + row.action.formSelector = #selector(viewController.changeDestinationFolder(_:)) + + // Verify that section was found + XCTAssertNotNil(row, "Expected save path section to exist in form.") + + } + + + + + + +} diff --git a/Tests/NextcloudUnitTests/E2EETests.swift b/Tests/NextcloudUnitTests/E2EETests.swift new file mode 100644 index 0000000000..bee1c1aa3f --- /dev/null +++ b/Tests/NextcloudUnitTests/E2EETests.swift @@ -0,0 +1,90 @@ +// +// E2EETests.swift +// NextcloudTests +// +// Created by A200020526 on 26/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest +import TOPasscodeViewController + +final class E2EETests: XCTestCase { + + var manageE2EE: NCManageE2EE! + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + manageE2EE = NCManageE2EE() + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + manageE2EE = nil + } + + 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. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + + // MARK: - Initialization + + func testInitialization() { + XCTAssertTrue(manageE2EE.endToEndInitialize.delegate === manageE2EE) + XCTAssertFalse(manageE2EE.isEndToEndEnabled) + XCTAssertEqual(manageE2EE.statusOfService, NSLocalizedString("_status_in_progress_", comment: "")) + } + + // MARK: - Delegate + + func testEndToEndInitializeSuccess() { + manageE2EE.endToEndInitializeSuccess() + XCTAssertTrue(manageE2EE.isEndToEndEnabled) + } + + // MARK: - Passcode + + func testRequestPasscodeType() { + // TODO: Implement this test case + } + + func testCorrectPasscode_startE2E() { + manageE2EE.passcodeType = "startE2E" + manageE2EE.correctPasscode() + // TODO: Add assertions for the expected behavior after entering the correct passcode for starting E2E + } + + func testCorrectPasscode_readPassphrase() { + manageE2EE.passcodeType = "readPassphrase" + // TODO: Simulate entering the correct passcode and verify the expected behavior + } + + func testCorrectPasscode_removeLocallyEncryption() { + manageE2EE.passcodeType = "removeLocallyEncryption" + // TODO: Simulate entering the correct passcode and verify the expected behavior + } + + func testDidPerformBiometricValidationRequest() { + let passcodeViewController = TOPasscodeViewController(passcodeType: .sixDigits, allowCancel: true) + manageE2EE.didPerformBiometricValidationRequest(in: passcodeViewController) + // TODO: Add assertions for the expected behavior after performing biometric validation + } + + func testDidTapCancel() { + let passcodeViewController = TOPasscodeViewController(passcodeType: .sixDigits, allowCancel: true) + manageE2EE.didTapCancel(in: passcodeViewController) + // TODO: Add assertions for the expected behavior after tapping cancel + } +} diff --git a/Tests/NextcloudUnitTests/MoreTests.swift b/Tests/NextcloudUnitTests/MoreTests.swift new file mode 100644 index 0000000000..0a96912994 --- /dev/null +++ b/Tests/NextcloudUnitTests/MoreTests.swift @@ -0,0 +1,37 @@ +// +// MoreTests.swift +// NextcloudTests +// +// Created by A200020526 on 09/06/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest + +final class MoreTests: 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. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/Tests/NextcloudUnitTests/MoveAndCopyTests.swift b/Tests/NextcloudUnitTests/MoveAndCopyTests.swift new file mode 100644 index 0000000000..bd674a472f --- /dev/null +++ b/Tests/NextcloudUnitTests/MoveAndCopyTests.swift @@ -0,0 +1,106 @@ +// +// MoveAndCopyTests.swift +// NextcloudTests +// +// Created by A200073704 on 05/06/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest +import NextcloudKit + + + class MoveAndCopyTests: XCTestCase { + + var view : NCSelectCommandView? + var viewController : NCSelect? + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + + let storyboard = UIStoryboard(name: "NCSelect", bundle: nil) + if let navigationController = storyboard.instantiateInitialViewController() as? UINavigationController { + let viewController = navigationController.topViewController as? NCSelect + + let _ = viewController?.view + viewController?.loadViewIfNeeded() + } + view = NCSelectCommandView() + + } + + override func setUp() { + super.setUp() + let nib = Bundle.main.loadNibNamed("NCSelectCommandViewCopyMove", owner: nil, options: nil) + view = nib?.first as? NCSelectCommandView + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + + viewController = nil + view = nil + + } + + func testCreateFolderButton() { + + let image: Void? = view?.createFolderButton?.setImage(UIImage(named: "addFolder")?.withTintColor(UIColor.label), for: .normal) + + XCTAssertNotNil(image) + } + + func testOverwriteSwitch() { + + let mySwitch = view?.overwriteSwitch + + XCTAssertNotNil(mySwitch) + + } + + func testCopyButton() { + + let copy = view?.copyButton + + XCTAssertNotNil(copy) + } + + + func testOverwriteSwitchAlwaysOn() { + + XCTAssertTrue(view?.overwriteSwitch?.isOn ?? false, "Overwrite Switch should always be on") + } + + func testCopyButtonandMoveButtonCondition() { + + // Disable copy and move + view?.copyButton?.isEnabled = false + view?.moveButton?.isEnabled = false + + // Creating a test item + let item = tableMetadata() + item.serverUrl = "serverUrl" // Set the serverUrl property of the item + + let items: [tableMetadata] = [item] + + // Update the items in the view controller + viewController?.items = items + + // Verify that the copy and move buttons are still disabled + XCTAssertFalse(view?.copyButton?.isEnabled ?? true, "Copy Button should remain disabled when items.first matches the condition") + XCTAssertFalse(view?.moveButton?.isEnabled ?? true, "Move Button should remain disabled when items.first matches the condition") + + // Enable copy and move + view?.copyButton?.isEnabled = true + view?.moveButton?.isEnabled = true + + // Update the items in the view controller + viewController?.items = [] // Empty items + + // Verify that the copyButton is still enabled + XCTAssertTrue(view?.copyButton?.isEnabled ?? false, "Copy Button should remain enabled when items.first doesn't match the condition") + XCTAssertTrue(view?.moveButton?.isEnabled ?? false, "Move Button should remain enabled when items.first doesn't match the condition") + } + +} diff --git a/Tests/NextcloudUnitTests/NCNotificationText.swift b/Tests/NextcloudUnitTests/NCNotificationText.swift new file mode 100644 index 0000000000..1a7e0b2345 --- /dev/null +++ b/Tests/NextcloudUnitTests/NCNotificationText.swift @@ -0,0 +1,85 @@ +// +// NCNotificationText.swift +// NextcloudUnitTests +// +// Created by Amrut Waghmare on 18/10/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest +import NextcloudKit + +class NCNotificationText: XCTestCase { + var viewController : NCNotification! + + override func setUpWithError() throws { + // Step 1. Create an instance of UIStoryboard + let storyboard = UIStoryboard(name: "NCNotification", bundle: nil) + // Step 2. Instantiate UIViewController with Storyboard ID + viewController = storyboard.instantiateViewController(withIdentifier: "NCNotification.storyboard") as? NCNotification + + // Step 3. Make the viewDidLoad() execute. + viewController.loadViewIfNeeded() + } + + override func tearDownWithError() throws { + viewController = nil + } + + //Test that a cell with the correct reuse identifier is dequeued + func testTableViewCellDequeue() { + let notification = NKNotifications() + viewController.notifications = [notification] + let tableView = UITableView() + tableView.register(NCNotificationCell.self, forCellReuseIdentifier: "Cell") + let indexPath = IndexPath(row: 0, section: 0) + let cell = viewController.tableView(tableView, cellForRowAt: indexPath) as? NCNotificationCell + XCTAssertNotNil(cell) + XCTAssertEqual(cell?.reuseIdentifier, "Cell") + } + + //Test that the cell's icon is set image + func testTableViewCellIcon() { + let notification = NKNotifications() + viewController.notifications = [notification] + let tableView = UITableView() + tableView.register(NCNotificationCell.self, forCellReuseIdentifier: "Cell") + let indexPath = IndexPath(row: 0, section: 0) + let cell = viewController.tableView(tableView, cellForRowAt: indexPath) as? NCNotificationCell + XCTAssertNotNil(cell?.icon.image) + } + + //Test that the cell's primary and secondary buttons are set up correctly + func testTableViewCellButtons() { + let notification = NKNotifications() + notification.actions = Data("[{\"label\":\"OK\",\"primary\":true},{\"label\":\"Cancel\",\"primary\":false}]".utf8) + viewController.notifications = [notification] + let tableView = UITableView() + tableView.register(NCNotificationCell.self, forCellReuseIdentifier: "Cell") + let indexPath = IndexPath(row: 0, section: 0) + let cell = viewController.tableView(tableView, cellForRowAt: indexPath) as? NCNotificationCell + XCTAssertEqual(cell?.primary.title(for: .normal), "OK") + XCTAssertEqual(cell?.secondary.title(for: .normal), "Cancel") + } + + //Test that the cell's date label is set correctly + func testTableViewCellDate() { + let notification = NKNotifications() + notification.date = NSDate() + viewController.notifications = [notification] + let tableView = UITableView() + tableView.register(NCNotificationCell.self, forCellReuseIdentifier: "Cell") + let indexPath = IndexPath(row: 0, section: 0) + let cell = viewController.tableView(tableView, cellForRowAt: indexPath) as? NCNotificationCell + XCTAssertEqual(cell?.date.text, "less than a minute ago") + } + + //Test with a color that is image not nil + func testImageNotNil() { + let color = UIColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 1.0) + let image = UIImage().imageColor(color) + XCTAssertNotNil(image, "Image should not be nil.") + + } +} diff --git a/Tests/NextcloudUnitTests/OnboardingTestCase.swift b/Tests/NextcloudUnitTests/OnboardingTestCase.swift new file mode 100644 index 0000000000..161b3a9258 --- /dev/null +++ b/Tests/NextcloudUnitTests/OnboardingTestCase.swift @@ -0,0 +1,158 @@ +// +// OnboardingTestCase.swift +// NextcloudTests +// +// Created by A200073704 on 21/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest +import NextcloudKit + + class OnboardingTestCase: XCTestCase { + + var viewController = NCIntroViewController() + + + var images:[UIImage?] = [] + let imagesLandscape = [UIImage(named: "introSlideLand1"), UIImage(named: "introSlideLand2"), UIImage(named: "introSlideLand3")] + let imagesPortrait = [UIImage(named: "introSlide1"), UIImage(named: "introSlide2"), UIImage(named: "introSlide3")] + let imagesEightPortrait = [UIImage(named: "introSlideEight1"), UIImage(named: "introSlideEight2"), UIImage(named: "introSlideEight3")] + + + + 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 testValidImage() { + + // onscreen images should not be nill + let image = [UIImage(named: "introSlideLand1"), UIImage(named: "introSlideLand2"), UIImage(named: "introSlideLand3")] + XCTAssertNotNil(image, "Image should not be nil") + + } + + func testImageDimensionsLandscape() { + + // testing height and width of the image + let introCollectionView = UIImage(named: "introSlideLand1") + XCTAssertEqual(introCollectionView?.size.width, 390, "Image width should be 390") + XCTAssertEqual(introCollectionView?.size.height, 844.3333333333334, "Image height should be 844.3333333333334") + } + + func testImageDimensionsPortrait() { + + // testing height and width of the image + let introCollectionView = UIImage(named: "introSlide1") + + XCTAssertEqual(introCollectionView?.size.width, 390, "Image width should be 390") + XCTAssertEqual(introCollectionView?.size.height, 844.3333333333334, "Image height should be 844.3333333333334") + } + + + func testImageDimentionsNotEqual() { + + // testing width and height if not equal + let introCollectionView = UIImage(named: "introSlide2") + + XCTAssertNotEqual(introCollectionView?.size.width, 100, "Image width should be 390") + XCTAssertNotEqual(introCollectionView?.size.height, 820, "Image height should be 844.3333333333334") + + } + + + func testImageContentMode() { + + // imageview content mode should be scaleAspectFill + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFill + imageView.image = UIImage(named: "introSlideLand2") + XCTAssertEqual(imageView.contentMode, .scaleAspectFill, "Image content mode should be scaleAspectFill") + + } + + + // Background color of view should be customer + func testBackgroundcolor() { + + let backgroundColor = NCBrandColor.shared.customer + XCTAssertNotNil(backgroundColor, "NCBrandColor.shared.customer should not be nil") + + } + + + // Button login text color shouyld be white + func testButtonLoginTextColor() { + + let textColor: UIColor = .white + viewController.buttonLogin?.backgroundColor = textColor + + XCTAssertEqual(textColor, textColor) + + } + + // images at loginscreen should not be empty + func testImagesNotEmpty() { + + let isEightPlusDevice = UIScreen.main.bounds.height == 736 + images = UIDevice.current.orientation.isLandscape ? imagesLandscape : (isEightPlusDevice ? imagesEightPortrait : imagesPortrait) + + XCTAssertFalse(images.isEmpty) + } + + + // Status bar and navigation bar color should not be blue color + func testStatueBarColorNotEqualToCustomer() { + + + let view = NCLoginWeb() + var color = view.navigationController?.navigationBar.backgroundColor + let navigationBarColor: UIColor = NCBrandColor.shared.customer + color = .systemBlue + + XCTAssertNotEqual(navigationBarColor, color) + + } + + //NavigationBar and status Bar color should be equal + func testNavigationBarColorEqualToCustomer() { + + let statusBarColor = NCBrandColor.shared.customer + let navigationBarColor: UIColor = NCBrandColor.shared.customer + + XCTAssertEqual(navigationBarColor, statusBarColor) + } + + func testEightPlusDeviceHeight() { + + let eightPlusDevice = UIScreen.main.bounds.height >= 736 + + XCTAssertTrue(eightPlusDevice) + + } + + func testLoginButtonTapped() { + + let viewController = NCIntroViewController() + + let loginButton = UIButton() + loginButton.addTarget(nil, action: #selector(viewController.login(_:)), for: .touchUpInside) + loginButton.sendActions(for: .touchUpInside) + + viewController.login(loginButton) + + XCTAssertNotNil(loginButton) + } + + + + +} diff --git a/Tests/NextcloudUnitTests/PrivacyPolicyTest.swift b/Tests/NextcloudUnitTests/PrivacyPolicyTest.swift new file mode 100644 index 0000000000..f6265f48e7 --- /dev/null +++ b/Tests/NextcloudUnitTests/PrivacyPolicyTest.swift @@ -0,0 +1,154 @@ +// +// PrivacyPolicyTest.swift +// NextcloudTests +// +// Created by A200073704 on 27/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest +import NextcloudKit +import XLForm + + + class PrivacyPolicyTest: XCTestCase { + + var viewController: InitialPrivacySettingsViewController? + var privacySettingsView = PrivacySettingsViewController() + + override func setUpWithError() throws { + + // To Create an instance of UIStoryboard + let storyboard = UIStoryboard(name: "NCSettings", bundle: nil) + + // To Instantiate UIViewController with Storyboard ID + viewController = storyboard.instantiateViewController(withIdentifier: "privacyPolicyViewController") as? InitialPrivacySettingsViewController + + // Outlets are connected + let _ = viewController?.view + + // Make the viewDidLoad() execute. + viewController?.loadViewIfNeeded() + + } + + override func tearDownWithError() throws { + viewController = nil + } + + func testPrivacyPolicyViewControllerIsOpen() { + + // Check that the InitialPrivacyPolicyViewController gets opened + let storyboard = UIStoryboard(name: "NCSettings", bundle: nil) + if let privacyPolicyViewController = storyboard.instantiateViewController(withIdentifier: "privacyPolicyViewController") as? InitialPrivacySettingsViewController { + let navigationController = UINavigationController(rootViewController: privacyPolicyViewController) + + privacyPolicyViewController.loadViewIfNeeded() + + XCTAssertTrue(navigationController.topViewController is InitialPrivacySettingsViewController, "Privacy policy view controller should be open") + } + } + + func testTextViewHasCorrectText() { + + //Check that the text displayed is correct + let expectedText = NSLocalizedString("_privacy_help_text_after_login_", comment: "") + viewController?.privacySettingsHelpText?.text = expectedText + + let actualText = viewController?.privacySettingsHelpText?.text + XCTAssertEqual(actualText, expectedText, "The text view does not have the expected text") + } + + func testHasAcceptButton() { + + // Check that view has the accept button + let acceptButton = viewController?.acceptButton + + XCTAssertNotNil(acceptButton, "View controller does not have an accept button") + + } + + func testSettingsLinkTypeNavigatesToPrivacySettingsViewController() { + + // Simulate tapping the "Settings" link type + let linkType = LinkType.settings + + UserDefaults.standard.set(true, forKey: "showSettingsButton") + viewController?.privacySettingsHelpText.hyperLink(originalText: viewController?.privacyHelpText ?? "", linkTextsAndTypes: [NSLocalizedString("_key_settings_help_", comment: ""): linkType.rawValue]) + + // Check that the correct view controller was pushed onto the navigation stack + XCTAssertNotNil(viewController?.navigationController?.visibleViewController is PrivacySettingsViewController) + } + + func testPrivacyPolicyLinkType_NavigatesToPrivacyPolicyViewController() { + + // Simulate tapping the "Privacy Policy" link type + let linkType = LinkType.privacyPolicy + + viewController?.privacySettingsHelpText.hyperLink(originalText: viewController?.privacyHelpText ?? "", linkTextsAndTypes: [NSLocalizedString("_key_privacy_help_", comment: ""): linkType.rawValue]) + + // Check that the correct view controller was pushed onto the navigation + XCTAssertNotNil(viewController?.navigationController?.visibleViewController is PrivacyPolicyViewController) + } + + func testCorrectImagePresentOnInitialPrivacySettingsViewController() { + + // Check that the image view has the correct image + let expectedImage = UIImage(named: "dataPrivacy") + XCTAssertNotNil(expectedImage) + } + + func testAcceptButtonHasBackgroundColor() { + + // Check that the accept button has the correct background color + let expectedColor = NCBrandColor.shared.brand + XCTAssertEqual(viewController?.acceptButton.backgroundColor, expectedColor) + + } + + func testShowSaveSettingsButton() { + + privacySettingsView.isShowSettingsButton = UserDefaults.standard.bool(forKey: "showSettingsButton") + + XCTAssertTrue(privacySettingsView.isShowSettingsButton) + + } + + func testRequiredDataCollectionSectionExists() { + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + // the section with the title "Required Data Collection" + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: "RequiredDataCollectionCustomCellType", title: "") + section = XLFormSectionDescriptor.formSection(withTitle: "") + section.footerTitle = NSLocalizedString("_required_data_collection_help_text_", comment: "") + + // Verify that section was found + XCTAssertNotNil(row, "Expected 'Required Data Collection' section to exist in form.") + } + + func testAnalysisDataCollectionSection() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + // row with tag "AnalysisDataCollectionSwitch" + row = XLFormRowDescriptor(tag: "AnalysisDataCollectionSwitch", rowType: "AnalysisDataCollectionCustomCellType", title: "") + section = XLFormSectionDescriptor.formSection(withTitle: "") + section.footerTitle = NSLocalizedString("_analysis_data_acqusition_help_text_", comment: "") + + // Assert that the row exists + XCTAssertNotNil(row, "Expected row with tag 'AnalysisDataCollectionSwitch' to exist in form.") + + // Verify the switch is off + XCTAssertFalse(UserDefaults.standard.bool(forKey: "isAnalysisDataCollectionSwitchOn"), "Expected isAnalysisDataCollectionSwitchOn to be false.") + } + + +} diff --git a/Tests/NextcloudUnitTests/RenameFileTests.swift b/Tests/NextcloudUnitTests/RenameFileTests.swift new file mode 100644 index 0000000000..c0aa06f029 --- /dev/null +++ b/Tests/NextcloudUnitTests/RenameFileTests.swift @@ -0,0 +1,108 @@ +// +// RenameFileTests.swift +// NextcloudTests +// +// Created by A200073704 on 14/06/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest +import NextcloudKit + +class RenameFileTests: 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 testStoryboardPresence() { + + let storyboard = UIStoryboard(name: "NCRenameFile", bundle: nil) + XCTAssertNotNil(storyboard, "Storyboard 'NCRenameFile' should be present") + + } + + func testRenameButtonPresence() { + let storyboard = UIStoryboard(name: "NCRenameFile", bundle: nil) + guard let viewController = storyboard.instantiateInitialViewController() as? NCRenameFile else { + XCTFail("Failed to instantiate view controller from storyboard") + return + } + + _ = viewController.view // Load the view + + let renameButton = viewController.renameButton + XCTAssertNotNil(renameButton, "Rename button should be present") + } + + func testRenameButtonBackgroundColor() { + + let storyboard = UIStoryboard(name: "NCRenameFile", bundle: nil) + guard let viewController = storyboard.instantiateInitialViewController() as? NCRenameFile else { + XCTFail("Failed to instantiate view controller from storyboard") + return + } + + _ = viewController.view // Load the view + + let color = NCBrandColor.shared.brand.cgColor + let renameButton = viewController.renameButton.layer.backgroundColor + + XCTAssertEqual(renameButton,color, "Rename Button Bcakground Color should be brand") + } + + func testCancelButtonPresence() { + let storyboard = UIStoryboard(name: "NCRenameFile", bundle: nil) + guard let viewController = storyboard.instantiateInitialViewController() as? NCRenameFile else { + XCTFail("Failed to instantiate view controller from storyboard") + return + } + + _ = viewController.view // Load the view + + let cancelButton = viewController.cancelButton + XCTAssertNotNil(cancelButton, "Cancel button should be present") + } + + func testImageViewPresence() { + + let storyboard = UIStoryboard(name: "NCRenameFile", bundle: nil) + guard let viewController = storyboard.instantiateInitialViewController() as? NCRenameFile else { + XCTFail("Failed to instantiate view controller from storyboard") + return + } + + _ = viewController.view // Load the view + + let imageView = viewController.previewFile + XCTAssertNotNil(imageView, "UIImageView should be present on the storyboard") + } + + func testTextFiledPresence() { + + let storyboard = UIStoryboard(name: "NCRenameFile", bundle: nil) + guard let viewController = storyboard.instantiateInitialViewController() as? NCRenameFile else { + XCTFail("Failed to instantiate view controller from storyboard") + return + } + + _ = viewController.view // Load the view + + let textField = viewController.fileNameNoExtension + let textFieldExt = viewController.ext + + XCTAssertNotNil(textField, "FileNameNoExtention TextFiled should be present on the storyboard") + XCTAssertNotNil(textFieldExt, "Extension TextFiled should be present on the storyboard") + + } + + + +} diff --git a/Tests/NextcloudUnitTests/ScanTests.swift b/Tests/NextcloudUnitTests/ScanTests.swift new file mode 100644 index 0000000000..750fc86d01 --- /dev/null +++ b/Tests/NextcloudUnitTests/ScanTests.swift @@ -0,0 +1,111 @@ +// +// ScanTests.swift +// NextcloudTests +// +// Created by A200020526 on 18/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest +import XLForm + +final class ScanTests: XCTestCase { + + var viewController: NCCreateFormUploadScanDocument? + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + viewController = NCCreateFormUploadScanDocument() + } + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + viewController = nil + } + 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. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + public func testImageColor() { + // Create a test color + let testColor = UIColor.red + // Create a test image + let testImage = UIImage(named: "activityTypeInfo") // Replace "your_image_name" with the name of your test image + // Call the imageColor function with the test color + let resultImage = testImage?.imageColor(testColor) + // Assert that the result image is not nil + XCTAssertNotNil(resultImage, "Result image should not be nil") + // Assert that the result image has the same size as the test image + XCTAssertEqual(resultImage?.size, testImage?.size, "Result image should have the same size as the test image") + } + func testIsAtleastOneFiletypeSelected() { + // Set up the initial switch states + viewController?.isPDFWithOCRSwitchOn = false + viewController?.isPDFWithoutOCRSwitchOn = false + viewController?.isTextFileSwitchOn = false + viewController?.isPNGFormatSwitchOn = false + viewController?.isJPGFormatSwitchOn = false + + // Call the function under test + let result1 = viewController?.isAtleastOneFiletypeSelected() ?? false + + // Assert the initial result + XCTAssertFalse(result1, "None of the file types are selected initially") + + // Update switch states + viewController?.isPDFWithOCRSwitchOn = true + + // Call the function under test again + let result2 = viewController?.isAtleastOneFiletypeSelected() ?? false + + // Assert the updated result + XCTAssertTrue(result2, "At least one file type is selected") + } + + func testBestFittingFont() { + // Set up the initial values + let text = "Hello, World!" + let bounds = CGRect(x: 0, y: 0, width: 200, height: 100) + let fontDescriptor = UIFontDescriptor(name: "Helvetica", size: 20) + let fontColor = UIColor.black + + // Call the function under test + let attributes = viewController?.bestFittingFont(for: text, in: bounds, fontDescriptor: fontDescriptor, fontColor: fontColor) + + // Assert the results + XCTAssertNotNil(attributes?[NSAttributedString.Key.font], "Font attribute should not be nil") + XCTAssertNotNil(attributes?[NSAttributedString.Key.foregroundColor], "Font color attribute should not be nil") + XCTAssertNotNil(attributes?[NSAttributedString.Key.kern], "Kern attribute should not be nil") + + XCTAssertEqual(attributes?[NSAttributedString.Key.foregroundColor] as? UIColor, fontColor, "Font color should match the input value") + + let font = attributes?[NSAttributedString.Key.font] as? UIFont + XCTAssertNotNil(font, "Font should not be nil") + XCTAssertEqual(font?.fontName, fontDescriptor.fontAttributes[.name] as? String, "Font name should match the input value") + } + + func testChangeCompressionImage() { + // Set up the initial values + guard let image = UIImage(named: "activityTypeInfo") else { + return + } + + // Call the function under test + let compressedImage = viewController?.changeCompressionImage(image) + + // Assert the results + XCTAssertNotNil(compressedImage, "Compressed image should not be nil") + if let width = compressedImage?.size.width, let height = compressedImage?.size.height { + XCTAssertTrue(width <= 841.8, "Compressed image width should be less than or equal to the base width") + XCTAssertTrue(height <= 595.2, "Compressed image height should be less than or equal to the base height") + } + } +} diff --git a/Tests/NextcloudUnitTests/SettingsTestCases.swift b/Tests/NextcloudUnitTests/SettingsTestCases.swift new file mode 100644 index 0000000000..13c4dacb82 --- /dev/null +++ b/Tests/NextcloudUnitTests/SettingsTestCases.swift @@ -0,0 +1,341 @@ +// +// SettingsTestCases.swift +// NextcloudTests +// +// Created by A200073704 on 12/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest +import NextcloudKit +import XLForm + + class SettingsTestCases: 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. + } + + // MARK: - Settings + + func testAutoUploadSectionIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + let image = UIImage(named: "autoUpload") + row = XLFormRowDescriptor(tag: "autoUpload", rowType: XLFormRowDescriptorTypeButton, title: NSLocalizedString("_settings_autoupload_", comment: "")); + section = XLFormSectionDescriptor.formSection(withTitle: "") + section.addFormRow(row) + + XCTAssertNotNil(image) + // Verify that section was found + XCTAssertNotNil(row, "Expected 'Auto Upload' section to exist in form.") + + + } + + func testLockSectionIsPresent() { + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + let image = UIImage(named: "lock_open") + row = XLFormRowDescriptor(tag: "bloccopasscode", rowType: XLFormRowDescriptorTypeButton, title: NSLocalizedString("_lock_not_active_", comment: "")); + section = XLFormSectionDescriptor.formSection(withTitle: "") + section.addFormRow(row) + + XCTAssertNotNil(image) + + XCTAssertNotNil(row, "Expected 'Lock Active / Off ' section exists") + + + } + + func testEnableTouchIDSectionIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + row = XLFormRowDescriptor(tag: "enableTouchDaceID", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_enable_touch_face_id_", comment: "")); + section = XLFormSectionDescriptor.formSection(withTitle: "") + section.addFormRow(row) + + XCTAssertNotNil(row, "Expected 'Enable/Disable touch ID' is present") + + } + + func testEndToEndEncryptionSectionIsPresent() { + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + row = XLFormRowDescriptor(tag: "e2eEncryption", rowType: XLFormRowDescriptorTypeButton, title: NSLocalizedString("_e2e_settings_", comment: "")); + section = XLFormSectionDescriptor.formSection(withTitle: "") + section.addFormRow(row) + + XCTAssertNotNil(row, "Expected 'End to End encryption' section exists") + + + } + + func testAdvancedSectionIsPresent() { + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + row = XLFormRowDescriptor(tag: "advanced", rowType: XLFormRowDescriptorTypeButton, title: NSLocalizedString("_e2e_settings_", comment: "")); + section = XLFormSectionDescriptor.formSection(withTitle: "") + section.addFormRow(row) + + XCTAssertNotNil(row, " Expected 'Advanced' Section exists") + } + + + + func testNavigatesToOpenSourceViewController() { + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + let section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + let row = XLFormRowDescriptor(tag: "buttonLeftAligned", rowType: XLFormRowDescriptorTypeButton, title: NSLocalizedString("_used_opensource_software_", comment: "")) + section.addFormRow(row) + + // Create a view controller with the form and add it to a navigation controller + let viewController = OpenSourceSoftwareViewController() + let window = UIApplication.shared.windows.first { $0.isKeyWindow } + let navigationController = UINavigationController(rootViewController: viewController) + window?.rootViewController = navigationController + + viewController.loadViewIfNeeded() + let indexPath = IndexPath(row: 0, section: 0) + print("Calling didSelectRowAt for row at \(indexPath)") + + // Verify that the OpenSourceSoftwareViewController class is opened + XCTAssertTrue(navigationController.topViewController is OpenSourceSoftwareViewController) + + } + + func testHelpSectionIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + let section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + let row = XLFormRowDescriptor(tag: "buttonLeftAligned", rowType: XLFormRowDescriptorTypeButton, title: NSLocalizedString("_help_", comment: "")) + section.addFormRow(row) + + // Create a view controller with the form and add it to a navigation controller + let viewController = HelpViewController() + let window = UIApplication.shared.windows.first { $0.isKeyWindow } + let navigationController = UINavigationController(rootViewController: viewController) + window?.rootViewController = navigationController + + viewController.loadViewIfNeeded() + let indexPath = IndexPath(row: 0, section: 0) + print("Calling didSelectRowAt for row at \(indexPath)") + + // Verify that the HelpViewController class is opened + XCTAssertTrue(navigationController.topViewController is HelpViewController) + + XCTAssertNotNil(row, "Expected 'Help' Section is present") + + } + + func testImprintSectionIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + let section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + let row = XLFormRowDescriptor(tag: "buttonLeftAligned", rowType: XLFormRowDescriptorTypeButton, title: NSLocalizedString("_imprint_", comment: "")) + section.addFormRow(row) + + // Create a view controller with the form and add it to a navigation controller + let viewController = ImprintViewController() + let window = UIApplication.shared.windows.first { $0.isKeyWindow } + let navigationController = UINavigationController(rootViewController: viewController) + window?.rootViewController = navigationController + + viewController.loadViewIfNeeded() + let indexPath = IndexPath(row: 0, section: 0) + print("Calling didSelectRowAt for row at \(indexPath)") + + // Verify that the ImprintViewController class is opened + XCTAssertTrue(navigationController.topViewController is ImprintViewController) + + XCTAssertNotNil(row, "Expected 'Imprint' Section is present") + } + + func testMagentaCloudVersionSectionIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + let section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + let row = XLFormRowDescriptor(tag: "disablefilesapp", rowType: "kNMCCustomCellType", title: NSLocalizedString("_magentacloud_version_", comment: "")) + section.addFormRow(row) + + XCTAssertNotNil(row, "Expected 'MagentaCloud Version' is present") + + + } + + // MARK: - Advanced + + func testShowHiddenFilesSectionIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + let section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + let row = XLFormRowDescriptor(tag: "showHiddenFiles", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_show_hidden_files_", comment: "")) + section.addFormRow(row) + + XCTAssertNotNil(row, "Expected 'Show hidden files' section is present") + + } + + func testMostCompatibleSectionIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + let section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + let row = XLFormRowDescriptor(tag: "formatCompatibility", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_format_compatibility_", comment: "")) + row.value = "1" + section.addFormRow(row) + + XCTAssertNotNil(row, "Expected 'Most Compatible' is present") + } + + func testLivePhotoSectionIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + let section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + let row = XLFormRowDescriptor(tag: "livePhoto", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_upload_mov_livephoto_", comment: "")) + if CCUtility.getLivePhoto() { + row.value = "1" + } else { + row.value = "0" + } + section.addFormRow(row) + + XCTAssertNotNil(row, "Expected 'Live Photo' section is present") + + } + + func testImageResolutionSectionIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + let section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + let row = XLFormRowDescriptor(tag: "automaticDownloadImage", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_automatic_Download_Image_", comment: "")) + section.addFormRow(row) + + XCTAssertNotNil(row, "Expected 'Use images in full resolution' section is present") + } + + func testAppIntegrationSectionIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + let section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + let row = XLFormRowDescriptor(tag: "disablefilesapp", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_disable_files_app_", comment: "")) + section.addFormRow(row) + + XCTAssertNotNil(row, "Expected 'Disable Files App Integration' section is present") + } + + func testDeleteFilesSectionIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + let section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + let row = XLFormRowDescriptor(tag: "deleteoldfiles", rowType: XLFormRowDescriptorTypeSelectorPush, title: NSLocalizedString("_delete_old_files_", comment: "")) + section.addFormRow(row) + + XCTAssertNotNil(row, "Expected 'Delete all files older than..' section is present") + } + + func testClearCacheSectionIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + let section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + let image = UIImage(named: "trashIcon") + + let row = XLFormRowDescriptor(tag: "azzeracache", rowType:XLFormRowDescriptorTypeButton, title: NSLocalizedString("_clear_cache_", comment: "")) + section.addFormRow(row) + + XCTAssertNotNil(image) + + XCTAssertNotNil(row, "Expected 'Clear Cache' section is present") + + } + + func testLogoutButtonIsPresent() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + let section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + let image = UIImage(named: "xmark") + + let row = XLFormRowDescriptor(tag: "esci", rowType: XLFormRowDescriptorTypeButton, title: NSLocalizedString("_exit_", comment: "")) + section.addFormRow(row) + + XCTAssertNotNil(image) + + XCTAssertNotNil(row, "Expected 'Logout' Button is present") + + + } + + + + + + + + + + + +} diff --git a/Tests/NextcloudUnitTests/SharingTest.swift b/Tests/NextcloudUnitTests/SharingTest.swift new file mode 100644 index 0000000000..984a4c0ac3 --- /dev/null +++ b/Tests/NextcloudUnitTests/SharingTest.swift @@ -0,0 +1,232 @@ +// +// SharingTest.swift +// NextcloudTests +// +// Created by A200020526 on 07/06/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import XCTest +@testable import Nextcloud +final class SharingTest: XCTestCase { + + var button: UIButton? + var ncShare: NCShare? + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + super.setUp() + button = UIButton() + ncShare = NCShare() + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + button = nil + ncShare = nil + super.tearDown() + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + + + //Date exntesion test case + func testTomorrow() { + let tomorrow = Date.tomorrow + let expectedTomorrow = Calendar.current.date(byAdding: .day, value: 1, to: Date())! + XCTAssertEqual(tomorrow.extendedIso8601String, expectedTomorrow.extendedIso8601String, "Tomorrow date should be correct.") + } + func testToday() { + let today = Date.today + let currentDate = Date() + XCTAssertEqual(today.extendedIso8601String, currentDate.extendedIso8601String, "Today date should be correct.") + } + + func testDayAfter() { + let date = Date() + let dayAfter = date.dayAfter + let expectedDayAfter = Calendar.current.date(byAdding: .day, value: 1, to: date)! + XCTAssertEqual(dayAfter.extendedIso8601String, expectedDayAfter.extendedIso8601String, "Day after date should be correct.") + } + + //Date Formatter extension Test Case + func testShareExpDate() { + let dateFormatter = DateFormatter.shareExpDate + + XCTAssertEqual(dateFormatter.formatterBehavior, .behavior10_4, "Formatter behavior should be correct.") + XCTAssertEqual(dateFormatter.dateStyle, .medium, "Date style should be correct.") + XCTAssertEqual(dateFormatter.dateFormat, NCShareAdvancePermission.displayDateFormat, "Date format should be correct.") + } + + //Button Extension test case + func testSetBackgroundColor() { + // Arrange + let color = UIColor.red + let state: UIControl.State = .normal + + // Act + button?.setBackgroundColor(color, for: state) + + // Assert + XCTAssertNotNil(button?.currentBackgroundImage, "Button background image not nil") + } + + func testSetBackgroundColorForDifferentStates() { + // Arrange + + let selectedColor = UIColor.green + + // Act + button?.isSelected = true + button?.setBackgroundColor(selectedColor, for: .selected) + + // Assert + XCTAssertNotNil(button?.currentBackgroundImage, "Button background image not nil") + button?.isSelected = false + XCTAssertNil(button?.currentBackgroundImage,"Button background image will be nil") + button?.isHighlighted = true + XCTAssertNil(button?.currentBackgroundImage, "Button background image will be nil") + } + + //UIView extension shadow test case + func testAddShadowWithLocation() { + // Create a UIView instance + let view = UIView() + + // Set the shadow with bottom location + view.addShadow(location: .bottom, height: 2, color: .red, opacity: 0.4, radius: 2) + + // Verify that the shadow offset is set correctly for the bottom location + let bottomShadowOffset = view.layer.shadowOffset + XCTAssertEqual(bottomShadowOffset, CGSize(width: 0, height: 2), "Shadow offset not set correctly for bottom location") + + // Verify that the shadow color is set correctly + let shadowColor = view.layer.shadowColor + XCTAssertEqual(shadowColor, UIColor.red.cgColor, "Shadow color not set correctly") + + // Verify that the shadow opacity is set correctly + let shadowOpacity = view.layer.shadowOpacity + XCTAssertEqual(shadowOpacity, 0.4, "Shadow opacity not set correctly") + + // Verify that the shadow radius is set correctly + let shadowRadius = view.layer.shadowRadius + XCTAssertEqual(shadowRadius, 2.0, "Shadow radius not set correctly") + } + + func testAddShadowWithOffset() { + // Create a UIView instance + let view = UIView() + + // Set the shadow with a custom offset + view.addShadow(offset: CGSize(width: 0, height: -4), color: .blue, opacity: 0.6, radius: 3) + + // Verify that the shadow offset is set correctly + let shadowOffset = view.layer.shadowOffset + XCTAssertEqual(shadowOffset, CGSize(width: 0, height: -4), "Shadow offset not set correctly") + + // Verify that the shadow color is set correctly + let shadowColor = view.layer.shadowColor + XCTAssertEqual(shadowColor, UIColor.blue.cgColor, "Shadow color not set correctly") + + // Verify that the shadow opacity is set correctly + let shadowOpacity = view.layer.shadowOpacity + XCTAssertEqual(shadowOpacity, 0.6, "Shadow opacity not set correctly") + + // Verify that the shadow radius is set correctly + let shadowRadius = view.layer.shadowRadius + XCTAssertEqual(shadowRadius, 3.0, "Shadow radius not set correctly") + } + + func testAddShadowForLocation() { + // Create a UIView instance + let view = UIView() + + // Add shadow to the bottom + view.addShadow(location: .bottom, color: UIColor.black) + + // Verify that the shadow properties are set correctly for the bottom location + XCTAssertEqual(view.layer.shadowOffset, CGSize(width: 0, height: 2), "Shadow offset not set correctly for bottom location") + XCTAssertEqual(view.layer.shadowColor, UIColor.black.cgColor, "Shadow color not set correctly for bottom location") + XCTAssertEqual(view.layer.shadowOpacity, 0.4, "Shadow opacity not set correctly for bottom location") + XCTAssertEqual(view.layer.shadowRadius, 2.0, "Shadow radius not set correctly for bottom location") + + // Add shadow to the top + view.addShadow(location: .top) + + // Verify that the shadow properties are set correctly for the top location + XCTAssertEqual(view.layer.shadowOffset, CGSize(width: 0, height: -2), "Shadow offset not set correctly for top location") + XCTAssertEqual(view.layer.shadowColor, NCBrandColor.shared.customerDarkGrey.cgColor, "Shadow color not set correctly for top location") + XCTAssertEqual(view.layer.shadowOpacity, 0.4, "Shadow opacity not set correctly for top location") + XCTAssertEqual(view.layer.shadowRadius, 2.0, "Shadow radius not set correctly for top location") + } + + func testAddShadowForOffset() { + // Create a UIView instance + let view = UIView() + + // Add shadow with custom offset + view.addShadow(offset: CGSize(width: 2, height: 2)) + + // Verify that the shadow properties are set correctly for the custom offset + XCTAssertEqual(view.layer.shadowOffset, CGSize(width: 2, height: 2), "Shadow offset not set correctly for custom offset") + XCTAssertEqual(view.layer.shadowColor, UIColor.black.cgColor, "Shadow color not set correctly for custom offset") + XCTAssertEqual(view.layer.shadowOpacity, 0.5, "Shadow opacity not set correctly for custom offset") + XCTAssertEqual(view.layer.shadowRadius, 5.0, "Shadow radius not set correctly for custom offset") + } + + + func testHasUploadPermission() { + // Create an instance of NCShare + let share = NCShare() + + // Define the input parameters + let tableShareWithUploadPermission = tableShare() + tableShareWithUploadPermission.permissions = NCGlobal.shared.permissionMaxFileShare + + let tableShareWithoutUploadPermission = tableShare() + tableShareWithoutUploadPermission.permissions = NCGlobal.shared.permissionReadShare + + // Call the hasUploadPermission function + let hasUploadPermission1 = share.hasUploadPermission(tableShare: tableShareWithUploadPermission) + let hasUploadPermission2 = share.hasUploadPermission(tableShare: tableShareWithoutUploadPermission) + + // Verify the results + XCTAssertTrue(hasUploadPermission1, "hasUploadPermission returned false for a tableShare with upload permission") + XCTAssertFalse(hasUploadPermission2, "hasUploadPermission returned true for a tableShare without upload permission") + } + + func testGetImageShareType() { + let sut = NCShareCommon // Replace with the actual class containing the getImageShareType function + + // Test case 1: SHARE_TYPE_USER + let shareType1 = sut.shareTypeUser + let result1 = sut.getImageShareType(shareType: shareType1) + XCTAssertEqual(result1, UIImage(named: "shareTypeEmail")?.imageColor(NCBrandColor.shared.label)) + + // Test case 2: SHARE_TYPE_GROUP + let shareType2 = sut.shareTypeGroup + let result2 = sut.getImageShareType(shareType: shareType2) + XCTAssertEqual(result2, UIImage(named: "shareTypeGroup")?.imageColor(NCBrandColor.shared.label)) + + // Test case 3: SHARE_TYPE_LINK + let shareType3 = sut.shareTypeLink + let result3 = sut.getImageShareType(shareType: shareType3) + XCTAssertEqual(result3, UIImage(named: "shareTypeLink")?.imageColor(NCBrandColor.shared.label)) + + // Test case 4: SHARE_TYPE_EMAIL (with isDropDown=false) + let shareType4 = sut.shareTypeEmail + let result4 = sut.getImageShareType(shareType: shareType4) + XCTAssertEqual(result4, UIImage(named: "shareTypeUser")?.imageColor(NCBrandColor.shared.label)) + + // Test case 5: SHARE_TYPE_EMAIL (with isDropDown=true) + let shareType5 = sut.shareTypeEmail + let isDropDown5 = true + let result5 = sut.getImageShareType(shareType: shareType5)//, isDropDown: isDropDown5) + XCTAssertEqual(result5, UIImage(named: "email")?.imageColor(NCBrandColor.shared.label)) + } +} diff --git a/iOSClient/Account/NCAccount.swift b/iOSClient/Account/NCAccount.swift index cfd22a0b49..d3ca96780b 100644 --- a/iOSClient/Account/NCAccount.swift +++ b/iOSClient/Account/NCAccount.swift @@ -108,6 +108,9 @@ class NCAccount: NSObject { // set theming color NCBrandColor.shared.settingThemingColor(account: account, capabilities: capabilities) } + // Start the auto upload + let num = await NCAutoUpload.shared.initAutoUpload(tblAccount: tblAccount) + nkLog(start: "Auto upload with \(num) photo") // Networking Process await NCNetworkingProcess.shared.setCurrentAccount(account) diff --git a/iOSClient/Analytics/AnalyticsHelper.swift b/iOSClient/Analytics/AnalyticsHelper.swift new file mode 100644 index 0000000000..54281e40df --- /dev/null +++ b/iOSClient/Analytics/AnalyticsHelper.swift @@ -0,0 +1,90 @@ +// +// AnalyticsHelper.swift +// Nextcloud +// +// Created by Amrut Waghmare on 10/06/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// + +import Foundation + +class AnalyticsHelper: NSObject, AnalyticsService { + + @objc static let shared = AnalyticsHelper() + + private var analyticsServices: [AnalyticsService] + + private override init() { + // Initialize the analytics services + let moEngageAnalytics = MoEngageAnalytics() + moEngageAnalytics.trackAppId() + analyticsServices = [moEngageAnalytics] + super.init() + } + + func trackEvent(eventName: AnalyticEvents, properties: [String: Any]? = nil) { + DispatchQueue.global(qos: .background).async { + self.analyticsServices.forEach { $0.trackEvent(eventName: eventName, properties: properties) } + } + } + + func trackUserData() { + DispatchQueue.global(qos: .background).async { + self.analyticsServices.forEach { $0.trackUserData() } + } + } + + func trackUsedStorageData(quotaUsed: Int64) { + DispatchQueue.global(qos: .background).async { + self.analyticsServices.forEach { $0.trackUsedStorageData(quotaUsed: quotaUsed) } + } + } + + @objc func trackAutoUpload(isEnable: Bool) { + DispatchQueue.global(qos: .background).async { + self.analyticsServices.forEach { $0.trackAutoUpload(isEnable: isEnable) } + } + } + + func trackAppVersion(oldVersion: String?) { + DispatchQueue.global(qos: .background).async { + self.analyticsServices.forEach { $0.trackAppVersion(oldVersion: oldVersion) } + } + } + + func trackLogout() { + DispatchQueue.global(qos: .background).async { + self.analyticsServices.forEach { $0.trackLogout() } + } + } + + func trackCreateFile(metadata: tableMetadata) { + DispatchQueue.global(qos: .background).async { + self.analyticsServices.forEach { $0.trackCreateFile(metadata: metadata) } + } + } + + func trackEventWithMetadata(eventName: AnalyticEvents, metadata: tableMetadata) { + DispatchQueue.global(qos: .background).async { + self.analyticsServices.forEach { $0.trackEventWithMetadata(eventName: eventName, metadata: metadata) } + } + } + + func trackCreateVoiceMemo(size: Int64, date: Date) { + DispatchQueue.global(qos: .background).async { + self.analyticsServices.forEach { $0.trackCreateVoiceMemo(size: size, date: date) } + } + } + + func trackCreateFolder(isEncrypted: Bool, creationDate: Date) { + DispatchQueue.global(qos: .background).async { + self.analyticsServices.forEach { $0.trackCreateFolder(isEncrypted: isEncrypted, creationDate: creationDate) } + } + } + + func displayInAppNotification() { + self.analyticsServices.forEach { $0.displayInAppNotification() } + } + + +} diff --git a/iOSClient/Analytics/AnalyticsService.swift b/iOSClient/Analytics/AnalyticsService.swift new file mode 100644 index 0000000000..e20600ca76 --- /dev/null +++ b/iOSClient/Analytics/AnalyticsService.swift @@ -0,0 +1,98 @@ +// +// AnalyticsService.swift +// Nextcloud +// +// Created by Amrut Waghmare on 10/06/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// + +import Foundation + +protocol AnalyticsService { + func trackEvent(eventName: AnalyticEvents, properties: [String: Any]?) + func trackUserData() + func trackUsedStorageData(quotaUsed: Int64) + func trackAutoUpload(isEnable: Bool) + func trackAppVersion(oldVersion: String?) + func trackLogout() + func trackCreateFile(metadata: tableMetadata) + func trackCreateVoiceMemo(size: Int64, date: Date) + func trackCreateFolder(isEncrypted: Bool, creationDate: Date) + func trackEventWithMetadata(eventName: AnalyticEvents, metadata: tableMetadata) + func displayInAppNotification() +} + +// swiftlint:disable identifier_name +enum AnalyticEvents: String { + case USER_PROPERTIES_STORAGE_CAPACITY = "storage_capacity" // in GB + case USER_PROPERTIES_STORAGE_USED = "storage_used" // % of storage used + case USER_PROPERTIES_AUTO_UPLOAD = "auto_upload_on" + case USER_PROPERTIES_APP_VERSION = "app_version" + case EVENT__ACTION_BUTTON = "action_button_clicked" // when user clicks on fab + button + case EVENT__UPLOAD_FILE = "upload_file" // when user uploads any file (not applicable for folder) from other apps + case EVENT__CREATE_FILE = "create_file" // when user creates any file in app + case EVENT__CREATE_FOLDER = "create_folder" + case EVENT__CREATE_VOICE_MEMO = "create_voice_memo" + case EVENT__ADD_FAVORITE = "add_favorite" + case EVENT__SHARE_FILE = "share_file" // when user share any file using link + case EVENT__OFFLINE_AVAILABLE = "offline_available" + case EVENT__ONLINE_OFFICE_USED = "online_office_used" // when user opens any office files + + // screen view events when user open specific screen + case SCREEN_EVENT__FAVOURITES = "favorites" + case SCREEN_EVENT__MEDIA = "medien" + case SCREEN_EVENT__OFFLINE_FILES = "offline_files" + case SCREEN_EVENT__SHARED = "shared" + case SCREEN_EVENT__DELETED_FILES = "deleted_files" + case SCREEN_EVENT__NOTIFICATIONS = "notifications" + + var moEngageEvent: String { + switch self { + default: + return self.rawValue + } + } + + var teliumEvent: String { + return self.rawValue + } + + var adjustEvent: String { + return self.rawValue + } +} + +// swiftlint:disable identifier_name +enum AnalyticPropertyAttributes: String { + // properties attributes key + case PROPERTIES__FILE_TYPE = "file_type" + case PROPERTIES__FOLDER_TYPE = "folder_type" + case PROPERTIES__FILE_SIZE = "file_size" // in MB + case PROPERTIES__CREATION_DATE = "creation_date" // yyyy-MM-dd + case PROPERTIES__UPLOAD_DATE = "upload_date" // // yyyy-MM-dd +} + +enum FolderType: String { + // properties attributes key + case FOLDER_ENCRYPTED = "encrypted" + case FOLDER_NORMAL = "not encrypted" +} + + +enum Size { + static let KILOBYTE = 1024 + static let MEGABYTE = KILOBYTE * 1024 + static let GIGABYTE = MEGABYTE * 1024 +} + +enum FileType: String { + case FOTO = "foto" + case AUDIO = "audio" + case VIDEO = "video" + case PDF = "pdf" + case TEXT = "text" + case DOCX = "docx" + case XLSX = "xlsx" + case PPT = "ppt" + case OTHER = "other" +} diff --git a/iOSClient/Analytics/MoEngage/MoEngageAnalytics.swift b/iOSClient/Analytics/MoEngage/MoEngageAnalytics.swift new file mode 100644 index 0000000000..8a3c903fa3 --- /dev/null +++ b/iOSClient/Analytics/MoEngage/MoEngageAnalytics.swift @@ -0,0 +1,274 @@ +// +// MoEngageAnalytics.swift +// Nextcloud +// +// Created by Amrut Waghmare on 10/06/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// + +import Foundation +import MoEngageSDK +import MoEngageInApps +import StoreKit + +class MoEngageAnalytics: NSObject { + + // Initializer for the MoEngageAnalytics class + override init() { + super.init() + + // Create a configuration object for MoEngage SDK with the given App ID and Data Center + let sdkConfig = MoEngageSDKConfig(appId: "7KWWUKA6OKXGP8Q6DMCXLDX5", dataCenter: MoEngageDataCenter.data_center_02) + + // Disable periodic flushing of analytics data + sdkConfig.analyticsDisablePeriodicFlush = true + + // Initialize the MoEngage SDK + // Use different initialization methods for Debug and Production environments + +#if DEBUG + MoEngage.sharedInstance.initializeDefaultTestInstance(sdkConfig) +#else + MoEngage.sharedInstance.initializeDefaultLiveInstance(sdkConfig) +#endif + setupMoEngageInAppMessaging() + + // Register delegate for In-App Native callbacks + MoEngageSDKInApp.sharedInstance.setInAppDelegate(self) + } + + // Method to track the App ID + func trackAppId() { + MoEngageSDKAnalytics.sharedInstance.trackLocale(forAppID: "312838242") + } + + func setupMoEngageInAppMessaging() { + //MARK: MoEngage In-App messages + MoEngageSDKInApp.sharedInstance.showInApp() + MoEngageSDKInApp.sharedInstance.showNudge() + } + + // Handles triggering Apple's native review popup +// private func requestAppStoreReview() { +// DispatchQueue.main.async { +// if let scene = UIApplication.shared.connectedScenes +// .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene { +// SKStoreReviewController.requestReview(in: scene) +// } +// } +// } + + private func requestAppStoreReview() { + DispatchQueue.main.async { + guard + let windowScene = UIApplication.shared.connectedScenes + .compactMap({ $0 as? UIWindowScene }) + .first(where: { $0.activationState == .foregroundActive }) + else { + return + } + + #if targetEnvironment(simulator) + // Simulator fallback for testing + let alert = UIAlertController( + title: "Review Prompt (Simulator)", + message: "This simulates the App Store review dialog.", + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: "OK", style: .default)) + windowScene.keyWindow?.rootViewController?.present(alert, animated: true) + #else + // Real request on device + SKStoreReviewController.requestReview(in: windowScene) + #endif + } + } + +} + +// AnalyticsService protocol +extension MoEngageAnalytics: AnalyticsService { + // Method to track a specific event with optional properties + func trackEvent(eventName: AnalyticEvents, properties: [String: Any]?) { + let eventProperties = MoEngageProperties(withAttributes: properties) + MoEngageSDKAnalytics.sharedInstance.trackEvent(eventName.moEngageEvent, withProperties: eventProperties) + } + + // Method to track user data + func trackUserData() { + // Get the active user account from the database + guard let user = NCManageDatabase.shared.getActiveTableAccount() else { return } + + // Set user attributes in the MoEngage SDK + MoEngageSDKAnalytics.sharedInstance.setUniqueID(user.userId) + MoEngageSDKAnalytics.sharedInstance.setName(user.displayName) + MoEngageSDKAnalytics.sharedInstance.setEmailID(user.email) + + // Convert the user's total storage quota to a readable format and set it as a user attribute + let storageCapacity = NCUtilityFileSystem().transformedSize(user.quotaTotal) + MoEngageSDKAnalytics.sharedInstance.setUserAttribute(storageCapacity, withAttributeName: AnalyticEvents.USER_PROPERTIES_STORAGE_CAPACITY.rawValue) + + // Track whether auto-upload is enabled for the user + trackAutoUpload(isEnable: user.autoUploadStart) + } + + // Method to track the used storage data + func trackUsedStorageData(quotaUsed: Int64) { + MoEngageSDKAnalytics.sharedInstance.setUserAttribute(quotaUsed, withAttributeName: AnalyticEvents.USER_PROPERTIES_STORAGE_USED.rawValue) + } + + // Method to track the auto-upload setting + func trackAutoUpload(isEnable: Bool) { + if isEnable { + MoEngageSDKAnalytics.sharedInstance.setUserAttribute(isEnable, withAttributeName: AnalyticEvents.USER_PROPERTIES_AUTO_UPLOAD.rawValue) + } + } + + // Method to track the app version + func trackAppVersion(oldVersion: String?) { + // Get the app version and set it as a user attribute + let version = NCUtility().getVersionBuild() as String + + // Check if a build version key is present in UserDefaults + if let oldVersion { + if version != oldVersion { + MoEngageSDKAnalytics.sharedInstance.appStatus(.update) + if let oldAppVersion = Int(oldVersion.dropLast().replacingOccurrences(of: ".", with: "")) { + if oldAppVersion < NCGlobal.shared.moEngageAppVersion { + trackUserData() + } + } + } + } else { + MoEngageSDKAnalytics.sharedInstance.appStatus(.install) + } + + MoEngageSDKAnalytics.sharedInstance.setUserAttribute(version, withAttributeName: AnalyticEvents.USER_PROPERTIES_APP_VERSION.rawValue) + } + + //Method to track user logout + func trackLogout() { + MoEngageSDKAnalytics.sharedInstance.resetUser() + } + + //Method to track create file + func trackCreateFile(metadata: tableMetadata) { + let properties = MoEngageProperties() + properties.addAttribute(getFileType(contentType: metadata.contentType), withName: AnalyticPropertyAttributes.PROPERTIES__FILE_TYPE.rawValue) + properties.addAttribute(String(getFileSizeInMB(bytes: Int(metadata.size))), withName: AnalyticPropertyAttributes.PROPERTIES__FILE_SIZE.rawValue) + properties.addAttribute(getDate(date: metadata.creationDate as Date), withName: AnalyticPropertyAttributes.PROPERTIES__CREATION_DATE.rawValue) + MoEngageSDKAnalytics.sharedInstance.trackEvent(AnalyticEvents.EVENT__CREATE_FILE.rawValue, withProperties: properties) + } + + //Method to track upload file + func trackEventWithMetadata(eventName: AnalyticEvents, metadata: tableMetadata) { + let properties = MoEngageProperties() + properties.addAttribute(getFileType(contentType: metadata.contentType), withName: AnalyticPropertyAttributes.PROPERTIES__FILE_TYPE.rawValue) + properties.addAttribute(String(getFileSizeInMB(bytes: Int(metadata.size))), withName: AnalyticPropertyAttributes.PROPERTIES__FILE_SIZE.rawValue) + properties.addAttribute(getDate(date: metadata.creationDate as Date), withName: AnalyticPropertyAttributes.PROPERTIES__CREATION_DATE.rawValue) + properties.addAttribute(getDate(date: metadata.uploadDate as Date), withName: AnalyticPropertyAttributes.PROPERTIES__UPLOAD_DATE.rawValue) + MoEngageSDKAnalytics.sharedInstance.trackEvent(eventName.rawValue, withProperties: properties) + } + + //Method to track create folder + func trackCreateFolder(isEncrypted: Bool, creationDate: Date) { + let properties = MoEngageProperties() + properties.addAttribute(isEncrypted ? FolderType.FOLDER_ENCRYPTED.rawValue : FolderType.FOLDER_NORMAL.rawValue , withName: AnalyticPropertyAttributes.PROPERTIES__FILE_TYPE.rawValue) + properties.addAttribute(getDate(date: creationDate), withName: AnalyticPropertyAttributes.PROPERTIES__CREATION_DATE.rawValue) + MoEngageSDKAnalytics.sharedInstance.trackEvent(AnalyticEvents.EVENT__CREATE_FOLDER.rawValue, withProperties: properties) + } + + //Method to track create voice memo + func trackCreateVoiceMemo(size: Int64, date: Date) { + let properties = MoEngageProperties() + properties.addAttribute(FileType.AUDIO.rawValue, withName: AnalyticPropertyAttributes.PROPERTIES__FILE_TYPE.rawValue) + properties.addAttribute(String(getFileSizeInMB(bytes: Int(size))), withName: AnalyticPropertyAttributes.PROPERTIES__FILE_SIZE.rawValue) + properties.addAttribute(getDate(date: date), withName: AnalyticPropertyAttributes.PROPERTIES__CREATION_DATE.rawValue) + MoEngageSDKAnalytics.sharedInstance.trackEvent(AnalyticEvents.EVENT__CREATE_VOICE_MEMO.rawValue, withProperties: properties) + } + + func displayInAppNotification() { + MoEngageSDKInApp.sharedInstance.showInApp() + //For showing nudges at any mentioned position + MoEngageSDKInApp.sharedInstance.showNudge() + } +} + +// Functions +extension MoEngageAnalytics { + private func getFileType(contentType: String) -> String? { + switch contentType { + case "image/png": + return FileType.FOTO.rawValue + case "audio/x-m4a", "audio/mp4": + return FileType.AUDIO.rawValue + case "video/mp4": + return FileType.VIDEO.rawValue + case "application/pdf": + return FileType.PDF.rawValue + case "text/x-markdown","text/plain": + return FileType.TEXT.rawValue + case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": + return FileType.DOCX.rawValue + case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","text/csv": + return FileType.XLSX.rawValue + case "application/vnd.openxmlformats-officedocument.presentationml.presentation": + return FileType.PPT.rawValue + default: + return FileType.OTHER.rawValue + } + } + + private func getDate(date: Date) -> String { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-MM-dd" + return dateFormatter.string(from: date) + } + + private func getFileSizeInMB(bytes: Int) -> Float { + return round((Float(bytes) / Float(Size.MEGABYTE)) * 10) / 10 + } + +} + +// MARK: - MoEngage In-App Native Delegate +extension MoEngageAnalytics: MoEngageInAppNativeDelegate { + + // Called when user clicks an in-app with navigation action (e.g., deep link) + func inAppClicked(withCampaignInfo inappCampaign: MoEngageInAppCampaign, + andNavigationActionInfo navigationAction: MoEngageInAppNavigationAction, + forAccountMeta accountMeta: MoEngageAccountMeta) { + // handle navigation actions if needed + } + + // Called when user clicks an in-app with custom action (e.g., our rating trigger) + func inAppClicked(withCampaignInfo inappCampaign: MoEngageInAppCampaign, + andCustomActionInfo customAction: MoEngageInAppAction, + forAccountMeta accountMeta: MoEngageAccountMeta) { + + let kv = customAction.keyValuePairs + + if let showRating = kv["show-native-rating"] as? String, + showRating.lowercased() == "true" { + requestAppStoreReview() + } + } + + // Called when a "self-handled" in-app is triggered + func selfHandledInAppTriggered(withInfo inAppCampaign: MoEngageInAppSelfHandledCampaign, + forAccountMeta accountMeta: MoEngageAccountMeta) { + // no-op unless you use self-handled campaigns + } + + // Optional — track impression + func inAppShown(withCampaignInfo inappCampaign: MoEngageInAppCampaign, + forAccountMeta accountMeta: MoEngageAccountMeta) { + // no-op + } + + // Optional — track dismissal + func inAppDismissed(withCampaignInfo inappCampaign: MoEngageInAppCampaign, + forAccountMeta accountMeta: MoEngageAccountMeta) { + // no-op + } +} diff --git a/iOSClient/AppUpdate/AppUpdater.swift b/iOSClient/AppUpdate/AppUpdater.swift new file mode 100644 index 0000000000..c091a9323d --- /dev/null +++ b/iOSClient/AppUpdate/AppUpdater.swift @@ -0,0 +1,104 @@ +// +// AppUpdater.swift +// Nextcloud +// +// Created by Amrut Waghmare on 09/10/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import Foundation +import FirebaseRemoteConfig + +struct AppUpdaterKey { + static let lastUpdateCheckDate : String = "lastUpdateCheckDate" +} + +class AppUpdater { + func checkForUpdate() { + checkUpdate{ (version, isForceupdate) in + DispatchQueue.main.async { + if let version = version, let isForceupdate = isForceupdate { + if (isForceupdate) { + self.showUpdateAlert(version: version, isForceUpdate: isForceupdate) + } else { + if self.checkLastUpdate() { + self.showUpdateAlert(version: version, isForceUpdate: isForceupdate) + } + } + } + } + } + } + + func showUpdateAlert(version: String, isForceUpdate: Bool) { + guard let appDelegate = UIApplication.shared.delegate as? AppDelegate, let viewControlller = appDelegate.window?.rootViewController else { return } + let descriptionMsg = String(format: NSLocalizedString("update_description", comment: ""), version) + let alert = UIAlertController(title: NSLocalizedString("update_available", comment: ""), message: descriptionMsg, preferredStyle: .alert) + let updateAction = UIAlertAction(title: NSLocalizedString("update", comment: ""), style: .default, handler: { action in + guard let url = URL(string: NCBrandOptions.shared.appStoreUrl) else { return } + UIApplication.shared.open(url) + }) + alert.addAction(updateAction) + if !isForceUpdate { + alert.addAction(UIAlertAction(title: NSLocalizedString("not_now", comment: ""), style: .default, handler: { action in + self.saveAppUpdateCheckDate() + })) + } + alert.preferredAction = updateAction + viewControlller.present(alert, animated: true, completion: {}) + } + + func checkLastUpdate() -> Bool { + if let lastUpdateCheckDate = UserDefaults.standard.object(forKey: AppUpdaterKey.lastUpdateCheckDate) as? Date { + return daysBetweenDate(from: lastUpdateCheckDate) > 7 + } else { + return true + } + } + + func checkUpdate(completion: @escaping (String?, Bool?) -> Void) { + let remoteConfig = RemoteConfig.remoteConfig() + remoteConfig.fetch(withExpirationDuration: 1) { (status, error) in + if status == .success { + remoteConfig.activate { value, error in + // Remote config values fetched successfully + let iOSVersionString = remoteConfig["ios_app_version"].stringValue ?? "default_value" + let isForcheUpdate = remoteConfig["ios_force_update"].boolValue + if let currentVersionString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String, + let currentVersion = Int(currentVersionString.replacingOccurrences(of: ".", with: "")), + let iOSVersion = Int(iOSVersionString.replacingOccurrences(of: ".", with: "")) { +// if let currentVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { + if iOSVersion != currentVersion { + // There is an update available + completion(iOSVersionString, isForcheUpdate) + } else { + completion(nil, nil) + } + } +// let iOSVersion = remoteConfig["ios_app_version"].stringValue ?? "default_value" +// let isForcheUpdate = remoteConfig["ios_force_update"].boolValue +// if let currentVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { +// if iOSVersion != currentVersion { +// // There is an update available +// completion(iOSVersion,isForcheUpdate) +// } else { +// completion(nil, nil) +// } +// } + } + } else { + // Handle error + print("Error fetching remote config: \(error?.localizedDescription ?? "Unknown error")") + completion(nil, nil) + } + } + } + + func saveAppUpdateCheckDate() { + UserDefaults.standard.setValue(Date(), forKey: AppUpdaterKey.lastUpdateCheckDate) + } + + func daysBetweenDate(from date: Date) -> Int { + return Calendar.current.dateComponents([.day], from: date, to: Date()).day ?? 0 + } +} diff --git a/iOSClient/AppUtility.swift b/iOSClient/AppUtility.swift new file mode 100644 index 0000000000..6d940416ca --- /dev/null +++ b/iOSClient/AppUtility.swift @@ -0,0 +1,23 @@ +// +// AppUtility.swift +// Nextcloud +// +// Created by Amrut Waghmare on 17/10/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import Foundation +import UIKit + +struct AppUtility { + static func lockOrientation(_ orientation: UIInterfaceOrientationMask) { + if let delegate = UIApplication.shared.delegate as? AppDelegate { + delegate.orientationLock = orientation + } + } + + static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) { + self.lockOrientation(orientation) + UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation") + } +} diff --git a/iOSClient/EmptyView/NCEmptyDataSet.swift b/iOSClient/EmptyView/NCEmptyDataSet.swift new file mode 100644 index 0000000000..389a11d651 --- /dev/null +++ b/iOSClient/EmptyView/NCEmptyDataSet.swift @@ -0,0 +1,129 @@ +// +// NCEmptyDataSet.swift +// Nextcloud +// +// Created by Marino Faggiana on 19/10/2020. +// Copyright © 2020 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import UIKit + +public protocol NCEmptyDataSetDelegate: AnyObject { + func emptyDataSetView(_ view: NCEmptyView) +} + +// optional func +public extension NCEmptyDataSetDelegate { + func emptyDataSetView(_ view: NCEmptyView) {} +} + +class NCEmptyDataSet: NSObject { + + private var emptyView: NCEmptyView? + private var timer: Timer? + private var numberItemsForSections: Int = 0 + private weak var delegate: NCEmptyDataSetDelegate? + + private var fillBackgroundName: String = "" + private var fillBackgroundView = UIImageView() + + private var centerXAnchor: NSLayoutConstraint? + private var centerYAnchor: NSLayoutConstraint? + + init(view: UIView, offset: CGFloat = 0, delegate: NCEmptyDataSetDelegate?) { + super.init() + + guard let emptyView = NCEmptyView.fromNib().instantiate(withOwner: self, options: nil).first as? NCEmptyView else { return } + + self.delegate = delegate + self.emptyView = emptyView + + emptyView.isHidden = true + emptyView.translatesAutoresizingMaskIntoConstraints = false + + view.addSubview(emptyView) + + emptyView.widthAnchor.constraint(equalToConstant: 350).isActive = true + emptyView.heightAnchor.constraint(equalToConstant: 250).isActive = true + + if let view = view.superview { + centerXAnchor = emptyView.centerXAnchor.constraint(equalTo: view.centerXAnchor) + centerYAnchor = emptyView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: offset) + } else { + centerXAnchor = emptyView.centerXAnchor.constraint(equalTo: view.centerXAnchor) + centerYAnchor = emptyView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: offset) + } + + centerXAnchor?.isActive = true + centerYAnchor?.isActive = true + + } + + func setOffset(_ offset: CGFloat) { + + centerYAnchor?.constant = offset + } + + func numberOfItemsInSection(_ num: Int, section: Int) { + + if section == 0 { + numberItemsForSections = num + } else { + 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 { + self.emptyView?.isHidden = true + } + } +} + +public class NCEmptyView: UIView { + + @IBOutlet weak var emptyImage: UIImageView! + @IBOutlet weak var emptyTitle: UILabel! + @IBOutlet weak var emptyDescription: UILabel! + + static func fromNib() -> UINib { + return UINib(nibName: "NCEmptyView", bundle: nil) + } + + public override func awakeFromNib() { + super.awakeFromNib() + + emptyTitle.textColor = .label + } +} diff --git a/iOSClient/EmptyView/NCEmptyView.xib b/iOSClient/EmptyView/NCEmptyView.xib new file mode 100644 index 0000000000..0b5ebbe133 --- /dev/null +++ b/iOSClient/EmptyView/NCEmptyView.xib @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Helper/AdjustHelper.h b/iOSClient/Helper/AdjustHelper.h new file mode 100644 index 0000000000..9b63269a17 --- /dev/null +++ b/iOSClient/Helper/AdjustHelper.h @@ -0,0 +1,48 @@ +// +// AdjustHelper.h +// Nextcloud +// +// Created by A200073704 on 17/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// +#import +//#import +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef enum : NSUInteger { + Login, + LoginSuccessful, + Sharing, + CreateLink, + DocumentScan, + CameraUpload, + FileUpload, + UseCamera, + Logout, + ResetsApp, + AutomaticUploadPhotosOn, + AutomaticUploadPhotosOff, + ManualBackup, + AutomaticBackup +} TriggerEvent; + +@interface AdjustHelper : NSObject + +@property (nonatomic, strong) NSString *yourAppToken; +@property (nonatomic, strong) NSString *environment; +@property (nonatomic, strong) ADJConfig *adjustConfig; +@property (nonatomic, strong) ADJEvent *eventLogin; +@property (nonatomic, strong) ADJEvent *event; +@property (nonatomic, assign) TriggerEvent triggerEvent; + +-(void)configAdjust; +-(void)subsessionEnd; +-(void)subsessionStart; +-(void)trackLogin; +-(void)trackEvent:(TriggerEvent)event; + +@end + +NS_ASSUME_NONNULL_END diff --git a/iOSClient/Helper/AdjustHelper.m b/iOSClient/Helper/AdjustHelper.m new file mode 100644 index 0000000000..780be4fe8e --- /dev/null +++ b/iOSClient/Helper/AdjustHelper.m @@ -0,0 +1,154 @@ +// +// AdjustHelper.m +// Nextcloud +// +// Created by A200073704 on 17/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +#import "AdjustHelper.h" +//#import + +@implementation AdjustHelper + +-(void)configAdjust { + self.yourAppToken = @"1zfaxn19pd7k"; + self.environment = ADJEnvironmentProduction; + self.adjustConfig = [[ADJConfig alloc] initWithAppToken:self.yourAppToken + environment:self.environment]; + [self.adjustConfig setLogLevel:ADJLogLevelVerbose]; + [Adjust initSdk:self.adjustConfig]; +} + +-(void)subsessionEnd { + [Adjust trackSubsessionEnd]; +} + +-(void)subsessionStart { + [Adjust trackSubsessionStart]; +} + +- (void)trackLogin { + self.eventLogin = [[ADJEvent alloc] initWithEventToken:@"p8hl78"]; +// self.eventLogin = [ADJEvent eventWithEventToken:@"p8hl78"]; + [Adjust trackEvent: self.eventLogin]; +} + +-(void)trackEvent:(TriggerEvent)event { +// self.event = [ADJEvent eventWithEventToken:@"gb97gb"]; + BOOL track = [[NSUserDefaults standardUserDefaults] valueForKey:@"isAnalysisDataCollectionSwitchOn"]; + if (!track) { + return; + } + + switch(event){ + case Login: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"p8hl78"]; +// event = [ADJEvent eventWithEventToken:@"gb97gb"]; +// self.event = [ADJEvent eventWithEventToken:@"gb97gb"]; + [Adjust trackEvent:event]; + } + break; + case LoginSuccessful: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"dowf81"]; + // event = [ADJEvent eventWithEventToken:@"gb97gb"]; + // self.event = [ADJEvent eventWithEventToken:@"gb97gb"]; + [Adjust trackEvent:event]; + } + break; + case Sharing: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"mbeoyd"]; + [Adjust trackEvent:event]; + NSLog(@"%@", [event debugDescription]); + } +// self.event = [ADJEvent eventWithEventToken:@"fqtiu7"]; + break; + case CreateLink: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"29b333"]; + [Adjust trackEvent:event]; + } +// self.event = [ADJEvent eventWithEventToken:@"qeyql3"]; + break; + case DocumentScan: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"im963g"]; + [Adjust trackEvent:event]; + } +// self.event = [ADJEvent eventWithEventToken:@"7fec8n"]; + break; + case CameraUpload: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"hf9paq"]; + [Adjust trackEvent:event]; + } +// self.event = [ADJEvent eventWithEventToken:@"v1g6ly"]; + break; + case FileUpload: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"hsbk2m"]; + [Adjust trackEvent:event]; + } +// self.event = [ADJEvent eventWithEventToken:@"4rd8r4"]; + break; + case UseCamera: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"3czack"]; + [Adjust trackEvent:event]; + } +// self.event = [ADJEvent eventWithEventToken:@"3czack"]; + break; + case Logout: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"n5q2qu"]; + [Adjust trackEvent:event]; + } +// self.event = [ADJEvent eventWithEventToken:@"g6mj9y"]; + break; + case ResetsApp: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"3sj1xp"]; + [Adjust trackEvent:event]; + } +// self.event = [ADJEvent eventWithEventToken:@"zi18r0"]; + break; + case AutomaticUploadPhotosOn: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"5lxz6h"]; + [Adjust trackEvent:event]; + } +// self.event = [ADJEvent eventWithEventToken:@"vwd9yk"]; + break; + case AutomaticUploadPhotosOff: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"176496"]; + [Adjust trackEvent:event]; + } +// self.event = [ADJEvent eventWithEventToken:@"e95w5t"]; + break; + case ManualBackup: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"oojr4y"]; + [Adjust trackEvent:event]; + } +// self.event = [ADJEvent eventWithEventToken:@"oojr4y"]; + break; + case AutomaticBackup: + { + ADJEvent *event = [[ADJEvent alloc] initWithEventToken:@"7dkhkx"]; + [Adjust trackEvent:event]; + } +// self.event = [ADJEvent eventWithEventToken:@"7dkhkx"]; + break; + + default : + break; + } +// [Adjust trackEvent: self.event]; +} + +@end + diff --git a/iOSClient/Helper/TealiumHelper.swift b/iOSClient/Helper/TealiumHelper.swift new file mode 100644 index 0000000000..9680da8e0a --- /dev/null +++ b/iOSClient/Helper/TealiumHelper.swift @@ -0,0 +1,56 @@ +// +// TealiumHelper.swift +// Nextcloud +// +// Created by A200073704 on 17/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// +import TealiumCore +import TealiumLifecycle +import TealiumAutotracking +import TealiumLocation +import TealiumRemoteCommands +import TealiumTagManagement +import TealiumVisitorService +import Foundation + +class TealiumHelper: NSObject { + static let shared = TealiumHelper() + let config = TealiumConfig(account: "telekom", + profile: "magentacloud-app", + environment: "dev") + var tealium: Tealium? + + @objc override init() { + + config.batchingEnabled = true + config.logLevel = .debug + + config.collectors = [Collectors.Lifecycle, + Collectors.Location, + Collectors.VisitorService] + + config.dispatchers = [Dispatchers.TagManagement, + Dispatchers.RemoteCommands] + + tealium = Tealium(config: config, enableCompletion: {value in + print(value) + } + ) + } + + func start() { + _ = TealiumHelper.shared + } + + @objc func trackView(title: String, data: [String: Any]?) { + let tealView = TealiumView(title, dataLayer: data) + TealiumHelper.shared.tealium?.track(tealView) + } + + @objc func trackEvent(title: String, data: [String: Any]?) { + let tealEvent = TealiumEvent(title, dataLayer: data) + TealiumHelper.shared.tealium?.track(tealEvent) + } +} + diff --git a/iOSClient/Login/NCLoginWeb.swift b/iOSClient/Login/NCLoginWeb.swift new file mode 100644 index 0000000000..9d2380e112 --- /dev/null +++ b/iOSClient/Login/NCLoginWeb.swift @@ -0,0 +1,422 @@ +// +// NCLoginWeb.swift +// Nextcloud +// +// Created by Marino Faggiana on 21/08/2019. +// Copyright © 2019 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import UIKit +import WebKit +import NextcloudKit +import FloatingPanel + +class NCLoginWeb: UIViewController { + + var webView: WKWebView? + var newWebView: WKWebView? + + let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + let utility = NCUtility() + + var titleView: String = "" + + var urlBase = "" + var user: String? + + var configServerUrl: String? + var configUsername: String? + var configPassword: String? + var configAppPassword: String? + + var loginFlowV2Available = false + var loginFlowV2Token = "" + var loginFlowV2Endpoint = "" + var loginFlowV2Login = "" + + /// Controller + var controller: NCMainTabBarController? + + // MARK: - View Life Cycle + + override func viewDidLoad() { + super.viewDidLoad() + + let accountCount = NCManageDatabase.shared.getAccounts()?.count ?? 0 + + // load AppConfig + if (NCBrandOptions.shared.disable_multiaccount == false) || (NCBrandOptions.shared.disable_multiaccount == true && accountCount == 0) { + if let configurationManaged = UserDefaults.standard.dictionary(forKey: "com.apple.configuration.managed"), NCBrandOptions.shared.use_AppConfig { + + if let serverUrl = configurationManaged[NCGlobal.shared.configuration_serverUrl] as? String { + self.configServerUrl = serverUrl + } + if let username = configurationManaged[NCGlobal.shared.configuration_username] as? String, !username.isEmpty, username.lowercased() != "username" { + self.configUsername = username + } + if let password = configurationManaged[NCGlobal.shared.configuration_password] as? String, !password.isEmpty, password.lowercased() != "password" { + self.configPassword = password + } + if let apppassword = configurationManaged[NCGlobal.shared.configuration_apppassword] as? String, !apppassword.isEmpty, apppassword.lowercased() != "apppassword" { + self.configAppPassword = apppassword + } + } + } + + if (NCBrandOptions.shared.use_login_web_personalized || NCBrandOptions.shared.use_AppConfig) && accountCount > 0 { + navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(self.closeView(sender:))) + } + + if accountCount > 0 { + navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "users")!.image(color: .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 +// webView!.uiDelegate = 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 + + // AppConfig + if let serverUrl = configServerUrl { + if let username = self.configUsername, let password = configAppPassword { + self.createAccount(urlBase: serverUrl, user: username, password: password) + return + } else if let username = self.configUsername, let password = configPassword { + getAppPassword(urlBase: serverUrl, user: username, password: password) + return + } else { + urlBase = serverUrl + } + } + + // ADD end point for Web Flow + if urlBase != NCBrandOptions.shared.linkloginPreferredProviders { + if loginFlowV2Available { + urlBase = loginFlowV2Login + } else { + urlBase += "/index.php/login/flow" + if let user = self.user { + urlBase += "?user=\(user)" + } + } + } + + if let url = URL(string: urlBase) { + loadWebPage(webView: webView!, url: url) + } else { + let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_login_url_error_") + NCContentPresenter().showError(error: error, priority: .max) + } + + if #available(iOS 13, *) { + let keyWindow = UIApplication.shared.connectedScenes + .filter({$0.activationState == .foregroundActive}) + .map({$0 as? UIWindowScene}) + .compactMap({$0}) + .first?.windows + .filter({$0.isKeyWindow}).first + let statusBar = UIView(frame: (keyWindow?.windowScene?.statusBarManager?.statusBarFrame)!) + statusBar.backgroundColor = NCBrandColor.shared.customer + keyWindow?.addSubview(statusBar) + } else { + if let statusBar = UIApplication.shared.value(forKey: "statusBar") as? UIView { + statusBar.backgroundColor = NCBrandColor.shared.customer + } + } + self.navigationController?.navigationBar.backgroundColor = NCBrandColor.shared.customer + self.edgesForExtendedLayout = [] // iphone 16, white gap between navigaiton and status bar. + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + // Stop timer error network + appDelegate.timerErrorNetworking?.invalidate() + + if let account = NCManageDatabase.shared.getActiveTableAccount(), NCPreferences().getPassword(account: account.account).isEmpty { + + let message = "\n" + NSLocalizedString("_password_not_present_", comment: "") + let alertController = UIAlertController(title: titleView, message: message, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) + present(alertController, animated: true) + } + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + NCActivityIndicator.shared.stop() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + // Start timer error network + appDelegate.startTimerErrorNetworking() + } + + func loadWebPage(webView: WKWebView, url: URL) { + + let language = NSLocale.preferredLanguages[0] as String + var request = URLRequest(url: url) + + 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 = userAgent + } + + request.addValue("true", forHTTPHeaderField: "OCS-APIRequest") + request.addValue(language, forHTTPHeaderField: "Accept-Language") + + webView.load(request) + } + + func getAppPassword(urlBase: String, user: String, password: String) { + + NextcloudKit.shared.getAppPassword(url: urlBase, user: user, password: password) { token, _, error in + if error == .success, let password = token { + self.createAccount(urlBase: urlBase, user: user, password: password) + } else { + NCContentPresenter().showError(error: error) + self.dismiss(animated: true, completion: nil) + } + } + } + + @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: { _ in + _ = self.navigationController?.popViewController(animated: true) + })) + self.present(alertController, animated: true) + return + } + + 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.isEmpty, !user.isEmpty, !password.isEmpty { + + 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: "") + + Task { + self.createAccount(urlBase: server, user: username, password: password) + } + } + } + } + + func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + DispatchQueue.global().async { + if let serverTrust = challenge.protectionSpace.serverTrust { + completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust)) + } else { + completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil) + } + } + } + + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + decisionHandler(.allow) + } + + func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { + if let httpResponse = navigationResponse.response as? HTTPURLResponse { + print("Response status code: \(httpResponse.statusCode)") + + if httpResponse.statusCode == 403 { +// showAccessDeniedAlert() + closeApp() + decisionHandler(.cancel) // Stop loading the page + } else { + decisionHandler(.allow) + } + } else { + decisionHandler(.allow) + } + } + + // Show an alert instead of closing the app + private func showAccessDeniedAlert() { + DispatchQueue.main.async { + let alert = UIAlertController(title: "Access Denied", message: "You are not authorized to view this page.", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in + // Optionally, redirect user + self.webView?.load(URLRequest(url: URL(string: "https://www.google.com")!)) + })) + self.present(alert, animated: true, completion: nil) + } + } + + func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { + NCActivityIndicator.shared.startActivity(style: .medium, blurEffect: false) + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + + NCActivityIndicator.shared.stop() + + if loginFlowV2Available { + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in + if error == .success && server != nil && loginName != nil && appPassword != nil { + self.createAccount(urlBase: server!, user: loginName!, password: appPassword!) + } + } + } + } + } + + private func closeApp() { + // Exit the app immediately + exit(0) + } + + + // MARK: - + +// func createAccount(urlBase: String, user: String, password: String) { +// let controller = UIApplication.shared.firstWindow?.rootViewController as? NCMainTabBarController +// if let host = URL(string: urlBase)?.host { +// NCNetworking.shared.writeCertificate(host: host) +// } +// NCAccount().createAccount(urlBase: urlBase, user: user, password: password, controller: controller) { account, error in +// if error == .success { +// let window = UIApplication.shared.firstWindow +// if let controller = window?.rootViewController as? NCMainTabBarController { +// controller.account = account +// self.dismiss(animated: true) +// } else { +// if let controller = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController { +// AnalyticsHelper.shared.trackUserData() +// controller.account = account +// controller.modalPresentationStyle = .fullScreen +// controller.view.alpha = 0 +// +// window?.rootViewController = controller +// window?.makeKeyAndVisible() +// +// if let scene = window?.windowScene { +// SceneManager.shared.register(scene: scene, withRootViewController: controller) +// } +// +// UIView.animate(withDuration: 0.5) { +// controller.view.alpha = 1 +// } +// } +// } +// } else { +// let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) +// alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) +// self.present(alertController, animated: true) +// } +// } +// } +// func createAccount(urlBase: String, user: String, password: String) { +// let controller = UIApplication.shared.firstWindow?.rootViewController as? NCMainTabBarController +// if let host = URL(string: urlBase)?.host { +// NCNetworking.shared.writeCertificate(host: host) +// } +// NCAccount().createAccount(urlBase: urlBase, user: user, password: password, controller: controller) { account, error in +// if error == .success { +// let window = UIApplication.shared.firstWindow +// if let controller = window?.rootViewController as? NCMainTabBarController { +// controller.account = account +// self.dismiss(animated: true) +// } else { +// if let controller = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController { +// AnalyticsHelper.shared.trackUserData() +// controller.account = account +// controller.modalPresentationStyle = .fullScreen +// controller.view.alpha = 0 +// +// window?.rootViewController = controller +// window?.makeKeyAndVisible() +// +// if let scene = window?.windowScene { +// SceneManager.shared.register(scene: scene, withRootViewController: controller) +// } +// +// UIView.animate(withDuration: 0.5) { +// controller.view.alpha = 1 +// } +// } +// } +// } else { +// let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) +// alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) +// self.present(alertController, animated: true) +// } +// } +// } + + private func createAccount(urlBase: String, user: String, password: String) { + if self.controller == nil { + self.controller = UIApplication.shared.firstWindow?.rootViewController as? NCMainTabBarController + } + + if let host = URL(string: urlBase)?.host { + NCNetworking.shared.writeCertificate(host: host) + } + + Task { + await NCAccount().createAccount(viewController: self, urlBase: urlBase, user: user, password: password, controller: self.controller) + } + } +} diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift index 3f2d134ddc..779139235d 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift @@ -128,15 +128,16 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { } if self.isEditMode { - if let index = self.fileSelect.firstIndex(of: metadata.ocId) { - self.fileSelect.remove(at: index) - } else { - self.fileSelect.append(metadata.ocId) + if !metadata.e2eEncrypted { + if let index = self.fileSelect.firstIndex(of: metadata.ocId) { + self.fileSelect.remove(at: index) + } else { + self.fileSelect.append(metadata.ocId) + } + self.collectionView.reloadItems(at: [indexPath]) + self.tabBarSelect?.update(fileSelect: self.fileSelect, metadatas: self.getSelectedMetadatas(), userId: metadata.userId) + // self.collectionView.reloadSections(IndexSet(integer: indexPath.section)) } - self.collectionView.reloadItems(at: [indexPath]) - self.tabBarSelect?.update(fileSelect: self.fileSelect, metadatas: self.getSelectedMetadatas(), userId: metadata.userId) - // self.collectionView.reloadSections(IndexSet(integer: indexPath.section)) - self.collectionView.collectionViewLayout.invalidateLayout() return } @@ -168,7 +169,7 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { return UIContextMenuConfiguration(identifier: identifier, previewProvider: { return NCViewerProviderContextMenu(metadata: metadata, image: image, sceneIdentifier: self.sceneIdentifier) }, actionProvider: { _ in - let contextMenu = NCContextMenu(metadata: metadata.detachedCopy(), viewController: self, sceneIdentifier: self.sceneIdentifier, image: image, sender: cell) + let contextMenu = NCContextMenu(metadata: metadata.detachedCopy(), viewController: self, sceneIdentifier: self.sceneIdentifier, image: image) return contextMenu.viewMenu() }) } diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+SwipeCollectionViewCellDelegate.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+SwipeCollectionViewCellDelegate.swift new file mode 100644 index 0000000000..d467e73701 --- /dev/null +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+SwipeCollectionViewCellDelegate.swift @@ -0,0 +1,100 @@ +// +// NCCollectionViewCommon+SwipeCollectionViewCellDelegate.swift +// Nextcloud +// +// Created by Milen on 01.03.24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import Foundation +import SwipeCellKit + +extension NCCollectionViewCommon: SwipeCollectionViewCellDelegate { + func collectionView(_ collectionView: UICollectionView, editActionsForItemAt indexPath: IndexPath, for orientation: SwipeCellKit.SwipeActionsOrientation) -> [SwipeCellKit.SwipeAction]? { + guard orientation == .right, let metadata = self.dataSource.cellForItemAt(indexPath: indexPath) else { return nil } + + let scaleTransition = ScaleTransition(duration: 0.3, initialScale: 0.8, threshold: 0.8) + + // wait a fix for truncate the text .. ? .. + let favoriteAction = SwipeAction(style: .default, title: NSLocalizedString(metadata.favorite ? "_favorite_short_" : "_favorite_short_", comment: "") ) { _, _ in + NCNetworking.shared.favoriteMetadata(metadata) { error in + if error != .success { + NCContentPresenter().showError(error: error) + } + } + } + favoriteAction.backgroundColor = NCBrandColor.shared.yellowFavorite + favoriteAction.image = .init(systemName: "star.fill") + favoriteAction.transitionDelegate = scaleTransition + favoriteAction.hidesWhenSelected = true + + var actions = [favoriteAction] + + let shareAction = SwipeAction(style: .default, title: NSLocalizedString("_share_", comment: "")) { _, _ in + NCActionCenter.shared.openActivityViewController(selectedMetadata: [metadata], controller: self.controller) + NCActionCenter.shared.openActivityViewController(selectedMetadata: [metadata]) + } + shareAction.backgroundColor = .blue + shareAction.image = .init(systemName: "square.and.arrow.up") + shareAction.transitionDelegate = scaleTransition + shareAction.hidesWhenSelected = true + + let deleteAction = SwipeAction(style: .destructive, title: NSLocalizedString("_delete_", comment: "")) { _, _ in + let titleDelete: String + + if metadata.directory { + titleDelete = NSLocalizedString("_delete_folder_", comment: "") + } else { + titleDelete = NSLocalizedString("_delete_file_", comment: "") + } + + let message = NSLocalizedString("_want_delete_", comment: "") + "\n - " + metadata.fileNameView + + let alertController = UIAlertController.deleteFileOrFolder(titleString: titleDelete + "?", message: message, canDeleteServer: !metadata.lock, selectedMetadatas: [metadata], sceneIdentifier: self.controller?.sceneIdentifier) { _ in } + + self.viewController.present(alertController, animated: true, completion: nil) + } + deleteAction.image = UIImage.init(systemName: "trash") + let alertController = UIAlertController.deleteFileOrFolder(titleString: titleDelete + "?", message: message, canDeleteServer: !metadata.lock, selectedMetadatas: [metadata], indexPaths: self.selectIndexPaths) { _ in } + + self.viewController.present(alertController, animated: true, completion: nil) + } + deleteAction.image = .init(systemName: "trash") + deleteAction.style = .destructive + deleteAction.transitionDelegate = scaleTransition + deleteAction.hidesWhenSelected = true + + if !NCManageDatabase.shared.isMetadataShareOrMounted(metadata: metadata, metadataFolder: metadataFolder) { + actions.insert(deleteAction, at: 0) + } + + if metadata.canShare { + actions.append(shareAction) + } + + return actions + } + + func collectionView(_ collectionView: UICollectionView, editActionsOptionsForItemAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeOptions { + var options = SwipeOptions() + options.expansionStyle = .selection + options.transitionStyle = .border + options.backgroundColor = .clear + return options + } +} diff --git a/iOSClient/Main/Collection Common/NCSelectableNavigationView.swift b/iOSClient/Main/Collection Common/NCSelectableNavigationView.swift new file mode 100644 index 0000000000..17dbb04c03 --- /dev/null +++ b/iOSClient/Main/Collection Common/NCSelectableNavigationView.swift @@ -0,0 +1,130 @@ +// +// NCSelectableNavigationView.swift +// Nextcloud +// +// Created by Henrik Storch on 27.01.22. +// Copyright © 2022 Henrik Storch. All rights reserved. +// +// Author Marino Faggiana +// Author Henrik Storch +// +// 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 . +// + +import NextcloudKit +import Realm +import UIKit + +extension RealmSwiftObject { + var primaryKeyValue: String? { + guard let primaryKeyName = self.objectSchema.primaryKeyProperty?.name else { return nil } + return value(forKey: primaryKeyName) as? String + } +} + +public protocol NCSelectableViewTabBar { + var tabBarController: UITabBarController? { get } + var hostingController: UIViewController? { get } +} + +protocol NCSelectableNavigationView: AnyObject { + var viewController: UIViewController { get } +// var appDelegate: AppDelegate { get } + var selectableDataSource: [RealmSwiftObject] { get } + var collectionView: UICollectionView! { get set } + var isEditMode: Bool { get set } + var fileSelect: [String] { get set } +// var selectIndexPaths: [IndexPath] { get set } + var appDelegate: AppDelegate { get } + var selectableDataSource: [RealmSwiftObject] { get } + var collectionView: UICollectionView! { get set } + var isEditMode: Bool { get set } + var selectOcId: [String] { get set } + var appDelegate: AppDelegate { get } + var selectIndexPaths: [IndexPath] { get set } + var titleCurrentFolder: String { get } + var navigationItem: UINavigationItem { get } + var navigationController: UINavigationController? { get } + var layoutKey: String { get } + var serverUrl: String { get } +// var tabBarSelect: NCSelectableViewTabBar? { get set } +// var dataSource: NCCollectionViewDataSource { get set } + +// func reloadDataSource(withQueryDB: Bool) + var tabBarSelect: NCSelectableViewTabBar? { get set } + + func reloadDataSource(withQueryDB: Bool) +// func reloadDataSource(withQueryDB: Bool) + func setNavigationLeftItems() + func setNavigationRightItems(enableMenu: Bool) + func createMenuActions() -> [NCMenuAction] + + func toggleSelect(isOn: Bool?) + func onListSelected() + func onGridSelected() +} + +extension NCSelectableNavigationView { + func setNavigationLeftItems() {} + + func saveLayout(_ layoutForView: NCDBLayoutForView) { + NCManageDatabase.shared.setLayoutForView(layoutForView: layoutForView) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource) + setNavigationRightItems(enableMenu: false) + } + + /// If explicit `isOn` is not set, it will invert `isEditMode` + func toggleSelect(isOn: Bool? = nil) { + DispatchQueue.main.async { + self.isEditMode = isOn ?? !self.isEditMode + self.fileSelect.removeAll() +// self.selectIndexPaths.removeAll() + self.selectOcId.removeAll() + self.selectIndexPaths.removeAll() + self.setNavigationLeftItems() + self.setNavigationRightItems(enableMenu: true) + self.collectionView.reloadData() + } + } + + func collectionViewSelectAll() { + + fileSelect = selectableDataSource.compactMap({ $0.primaryKeyValue }) +// fileSelect = NCCollectionViewDataSource().getMetadataSourceForAllSections().compactMap({ $0.primaryKeyValue }) +// selectOcId = selectableDataSource.compactMap({ $0.primaryKeyValue }) + collectionView.reloadData() + setNavigationRightItems(enableMenu: false) + } + + func tapNotification() { + if let viewController = UIStoryboard(name: "NCNotification", bundle: nil).instantiateInitialViewController() as? NCNotification { + navigationController?.pushViewController(viewController, animated: true) + } + } + + func tapTransfer() { + if let navController = UIStoryboard(name: "NCTransfers", bundle: nil).instantiateInitialViewController() as? UINavigationController, + let viewController = navController.topViewController as? NCTransfers { + viewController.modalPresentationStyle = .pageSheet +// self.present(navigationController, animated: true, completion: nil) + navigationController?.present(navController, animated: true, completion: nil) + } + } +} + +extension NCSelectableNavigationView where Self: UIViewController { + var viewController: UIViewController { + self + } +} diff --git a/iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderMenu.swift b/iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderMenu.swift new file mode 100644 index 0000000000..6cd8ae727d --- /dev/null +++ b/iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderMenu.swift @@ -0,0 +1,329 @@ +// +// NCSectionHeaderFooter.swift +// Nextcloud +// +// Created by Marino Faggiana on 09/10/2018. +// Copyright © 2018 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import UIKit +import MarkdownKit + +class NCSectionHeaderMenu: UICollectionReusableView, UIGestureRecognizerDelegate { + + @IBOutlet weak var buttonSwitch: UIButton! + @IBOutlet weak var buttonOrder: UIButton! + @IBOutlet weak var buttonMore: UIButton! + @IBOutlet weak var buttonTransfer: UIButton! + @IBOutlet weak var imageButtonTransfer: UIImageView! + @IBOutlet weak var labelTransfer: UILabel! + @IBOutlet weak var progressTransfer: UIProgressView! + @IBOutlet weak var transferSeparatorBottom: UIView! + @IBOutlet weak var textViewRichWorkspace: UITextView! + @IBOutlet weak var labelSection: UILabel! + @IBOutlet weak var viewTransfer: UIView! + @IBOutlet weak var viewButtonsView: UIView! + @IBOutlet weak var viewSeparator: UIView! + @IBOutlet weak var viewRichWorkspace: UIView! + @IBOutlet weak var viewSection: UIView! + + @IBOutlet weak var viewTransferHeightConstraint: NSLayoutConstraint! + @IBOutlet weak var viewButtonsViewHeightConstraint: NSLayoutConstraint! + @IBOutlet weak var viewSeparatorHeightConstraint: NSLayoutConstraint! + @IBOutlet weak var viewRichWorkspaceHeightConstraint: NSLayoutConstraint! + @IBOutlet weak var viewSectionHeightConstraint: NSLayoutConstraint! + @IBOutlet weak var transferSeparatorBottomHeightConstraint: NSLayoutConstraint! + + weak var delegate: NCSectionHeaderMenuDelegate? + let utility = NCUtility() + private var markdownParser = MarkdownParser() + private var richWorkspaceText: String? + private var textViewColor: UIColor? + private let gradient: CAGradientLayer = CAGradientLayer() + + override func awakeFromNib() { + super.awakeFromNib() + + backgroundColor = .clear + + buttonSwitch.setImage(UIImage(systemName: "list.bullet")!.image(color: NCBrandColor.shared.iconImageColor, size: 25), for: .normal) + + buttonOrder.setTitle("", for: .normal) + buttonOrder.setTitleColor(NCBrandColor.shared.brand, for: .normal) + buttonMore.setImage(UIImage(named: "more")!.image(color: NCBrandColor.shared.iconImageColor, size: 25), for: .normal) + + // Gradient + gradient.startPoint = CGPoint(x: 0, y: 0.50) + gradient.endPoint = CGPoint(x: 0, y: 1) + viewRichWorkspace.layer.addSublayer(gradient) + + let tap = UITapGestureRecognizer(target: self, action: #selector(touchUpInsideViewRichWorkspace(_:))) + tap.delegate = self + viewRichWorkspace?.addGestureRecognizer(tap) + + viewSeparatorHeightConstraint.constant = 0.5 + viewSeparator.backgroundColor = .separator + + markdownParser = MarkdownParser(font: UIFont.systemFont(ofSize: 15), color: .label) + markdownParser.header.font = UIFont.systemFont(ofSize: 25) + if let richWorkspaceText = richWorkspaceText { + textViewRichWorkspace.attributedText = markdownParser.parse(richWorkspaceText) + } + textViewColor = .label + + labelSection.text = "" + viewSectionHeightConstraint.constant = 0 + + buttonTransfer.backgroundColor = .clear + buttonTransfer.setImage(nil, for: .normal) + buttonTransfer.layer.cornerRadius = 6 + buttonTransfer.layer.masksToBounds = true + imageButtonTransfer.image = UIImage(systemName: "stop.circle") + imageButtonTransfer.tintColor = .white + labelTransfer.text = "" + progressTransfer.progress = 0 + progressTransfer.tintColor = NCBrandColor.shared.brand + progressTransfer.trackTintColor = NCBrandColor.shared.brand.withAlphaComponent(0.2) + transferSeparatorBottom.backgroundColor = .separator + transferSeparatorBottomHeightConstraint.constant = 0.5 + } + + override func layoutSublayers(of layer: CALayer) { + super.layoutSublayers(of: layer) + + gradient.frame = viewRichWorkspace.bounds + setInterfaceColor() + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + setInterfaceColor() + } + + // MARK: - View + + func setStatusButtonsView(enable: Bool) { + + buttonSwitch.isEnabled = enable + buttonOrder.isEnabled = enable + buttonMore.isEnabled = enable + } + + func buttonMoreIsHidden(_ isHidden: Bool) { + + buttonMore.isHidden = isHidden + } + + func setImageSwitchList() { + + buttonSwitch.setImage(UIImage(systemName: "list.bullet")!.image(color: NCBrandColor.shared.iconImageColor, width: 20, height: 15), for: .normal) + } + + func setImageSwitchGrid() { + + buttonSwitch.setImage(UIImage(systemName: "square.grid.2x2")!.image(color: NCBrandColor.shared.iconImageColor, size: 20), for: .normal) + } + + func setButtonsView(height: CGFloat) { + + viewButtonsViewHeightConstraint.constant = height + if height == 0 { + viewButtonsView.isHidden = true + } else { + viewButtonsView.isHidden = false + } + } + + func setSortedTitle(_ title: String) { + + let title = NSLocalizedString(title, comment: "") + buttonOrder.setTitle(title, for: .normal) + } + + // MARK: - RichWorkspace + + func setRichWorkspaceHeight(_ size: CGFloat) { + + viewRichWorkspaceHeightConstraint.constant = size + if size == 0 { + viewRichWorkspace.isHidden = true + } else { + viewRichWorkspace.isHidden = false + } + } + + func setInterfaceColor() { + + if traitCollection.userInterfaceStyle == .dark { + gradient.colors = [UIColor(white: 0, alpha: 0).cgColor, UIColor.black.cgColor] + } else { + gradient.colors = [UIColor(white: 1, alpha: 0).cgColor, UIColor.white.cgColor] + } + } + + func setRichWorkspaceText(_ text: String?) { + guard let text = text else { return } + + if text != self.richWorkspaceText { + textViewRichWorkspace.attributedText = markdownParser.parse(text) + self.richWorkspaceText = text + } + } + + // MARK: - Transfer + + func setViewTransfer(isHidden: Bool, ocId: String? = nil, text: String? = nil, progress: Float? = nil) { + + labelTransfer.text = text + viewTransfer.isHidden = isHidden + progressTransfer.progress = 0 + + if isHidden { + viewTransferHeightConstraint.constant = 0 + } else { + var image: UIImage? + if let ocId, + let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { + image = utility.createFilePreviewImage(ocId: metadata.ocId, etag: metadata.etag, fileNameView: metadata.fileNameView, classFile: metadata.classFile, status: metadata.status, createPreviewMedia: true)//?.darken() + if image == nil { + image = UIImage(named: metadata.iconName) + buttonTransfer.backgroundColor = .lightGray + } else { + buttonTransfer.backgroundColor = .clear + } + buttonTransfer.setImage(image, for: .normal) + } + viewTransferHeightConstraint.constant = NCGlobal.shared.heightHeaderTransfer + if let progress { + progressTransfer.progress = progress + } + } + } + + // MARK: - Section + + func setSectionHeight(_ size: CGFloat) { + + viewSectionHeightConstraint.constant = size + if size == 0 { + viewSection.isHidden = true + } else { + viewSection.isHidden = false + } + } + + // MARK: - Action + + @IBAction func touchUpInsideSwitch(_ sender: Any) { + delegate?.tapButtonSwitch(sender) + } + + @IBAction func touchUpInsideOrder(_ sender: Any) { + delegate?.tapButtonOrder(sender) + } + + @IBAction func touchUpInsideMore(_ sender: Any) { + delegate?.tapButtonMore(sender) + } + + @IBAction func touchUpTransfer(_ sender: Any) { + delegate?.tapButtonTransfer(sender) + } + + @objc func touchUpInsideViewRichWorkspace(_ sender: Any) { + delegate?.tapRichWorkspace(sender) + } +} + +protocol NCSectionHeaderMenuDelegate: AnyObject { + func tapButtonSwitch(_ sender: Any) + func tapButtonOrder(_ sender: Any) + func tapButtonMore(_ sender: Any) + func tapButtonTransfer(_ sender: Any) + func tapRichWorkspace(_ sender: Any) +} + +// optional func +extension NCSectionHeaderMenuDelegate { + func tapButtonSwitch(_ sender: Any) {} + func tapButtonOrder(_ sender: Any) {} + func tapButtonMore(_ sender: Any) {} + func tapButtonTransfer(_ sender: Any) {} + func tapRichWorkspace(_ sender: Any) {} +} + +// optional func +extension NCSectionFooterDelegate { + func tapButtonSection(_ sender: Any, metadataForSection: NCMetadataForSection?) {} +} + +//// https://stackoverflow.com/questions/16278463/darken-an-uiimage +//public extension UIImage { +// +// private enum BlendMode { +// case multiply // This results in colors that are at least as dark as either of the two contributing sample colors +// case screen // This results in colors that are at least as light as either of the two contributing sample colors +// } +// +// // A level of zero yeilds the original image, a level of 1 results in black +// func darken(level: CGFloat = 0.5) -> UIImage? { +// return blend(mode: .multiply, level: level) +// } +// +// // A level of zero yeilds the original image, a level of 1 results in white +// func lighten(level: CGFloat = 0.5) -> UIImage? { +// return blend(mode: .screen, level: level) +// } +// +// private func blend(mode: BlendMode, level: CGFloat) -> UIImage? { +// let context = CIContext(options: nil) +// +// var level = level +// if level < 0 { +// level = 0 +// } else if level > 1 { +// level = 1 +// } +// +// let filterName: String +// switch mode { +// case .multiply: // As the level increases we get less white +// level = abs(level - 1.0) +// filterName = "CIMultiplyBlendMode" +// case .screen: // As the level increases we get more white +// filterName = "CIScreenBlendMode" +// } +// +// let blender = CIFilter(name: filterName)! +// let backgroundColor = CIColor(color: UIColor(white: level, alpha: 1)) +// +// guard let inputImage = CIImage(image: self) else { return nil } +// blender.setValue(inputImage, forKey: kCIInputImageKey) +// +// guard let backgroundImageGenerator = CIFilter(name: "CIConstantColorGenerator") else { return nil } +// backgroundImageGenerator.setValue(backgroundColor, forKey: kCIInputColorKey) +// guard let backgroundImage = backgroundImageGenerator.outputImage?.cropped(to: CGRect(origin: CGPoint.zero, size: self.size)) else { return nil } +// blender.setValue(backgroundImage, forKey: kCIInputBackgroundImageKey) +// +// guard let blendedImage = blender.outputImage else { return nil } +// +// guard let cgImage = context.createCGImage(blendedImage, from: blendedImage.extent) else { return nil } +// return UIImage(cgImage: cgImage) +// } +//} diff --git a/iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderMenu.xib b/iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderMenu.xib new file mode 100644 index 0000000000..5d206c1d2f --- /dev/null +++ b/iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderMenu.xib @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Main/Create/NCCreateFormUploadDocuments.storyboard b/iOSClient/Main/Create/NCCreateFormUploadDocuments.storyboard new file mode 100644 index 0000000000..6995ac52d9 --- /dev/null +++ b/iOSClient/Main/Create/NCCreateFormUploadDocuments.storyboard @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Main/Create/NCCreateFormUploadDocuments.swift b/iOSClient/Main/Create/NCCreateFormUploadDocuments.swift new file mode 100644 index 0000000000..758e2249e2 --- /dev/null +++ b/iOSClient/Main/Create/NCCreateFormUploadDocuments.swift @@ -0,0 +1,596 @@ +// +// NCCreateFormUploadDocuments.swift +// Nextcloud +// +// Created by Marino Faggiana on 14/11/18. +// Copyright © 2018 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import UIKit +import NextcloudKit +import XLForm + +// MARK: - + +@objc class NCCreateFormUploadDocuments: XLFormViewController, NCSelectDelegate, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, NCCreateFormUploadConflictDelegate { + func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool, session: NCSession.Session) { + + } + + + @IBOutlet weak var indicator: UIActivityIndicatorView! + @IBOutlet weak var collectionView: UICollectionView! + @IBOutlet weak var collectionViewHeigth: NSLayoutConstraint! + + let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + var editorId = "" + var creatorId = "" + var typeTemplate = "" + var templateIdentifier = "" + var serverUrl = "" + var fileNameFolder = "" + var fileName = "" + var fileNameExtension = "" + var titleForm = "" + var listOfTemplate: [NKEditorTemplate] = [] + var selectTemplate: NKEditorTemplate? + let utilityFileSystem = NCUtilityFileSystem() + let utility = NCUtility() + + // Layout + let numItems = 2 + let sectionInsets: CGFloat = 10 + let highLabelName: CGFloat = 20 + + var controller: NCMainTabBarController! + var session: NCSession.Session { + NCSession.shared.getSession(controller: controller) + } + + // MARK: - View Life Cycle + + override func viewDidLoad() { + super.viewDidLoad() + + if serverUrl == utilityFileSystem.getHomeServer(session: session) { + fileNameFolder = "/" + } else { + fileNameFolder = utilityFileSystem.getTextServerUrl(session: session, serverUrl: serverUrl)//(serverUrl as NSString).lastPathComponent + } + + self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none + + view.backgroundColor = .systemGroupedBackground + collectionView.backgroundColor = .systemGroupedBackground + tableView.backgroundColor = .secondarySystemGroupedBackground + + 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)) + cancelButton.tintColor = NCBrandColor.shared.brand + saveButton.tintColor = NCBrandColor.shared.brand + + self.navigationItem.leftBarButtonItem = cancelButton + self.navigationItem.rightBarButtonItem = saveButton + self.navigationItem.rightBarButtonItem?.isEnabled = false + + // title + self.title = titleForm + + fileName = NCUtilityFileSystem().createFileNameDate("Text", ext: getFileExtension()) + + initializeForm() + getTemplate() + } + + // MARK: - Tableview (XLForm) + + func initializeForm() { + + let form: XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section: XLFormSectionDescriptor + var row: XLFormRowDescriptor + + // Section: Destination Folder + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_save_path_", comment: "").uppercased()) + section.footerTitle = " " + form.addFormSection(section) + + XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFolderCustomCellType"] = FolderPathCustomCell.self + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: "kNMCFolderCustomCellType", title: "") + row.action.formSelector = #selector(changeDestinationFolder(_:)) + row.cellConfig["folderImage.image"] = UIImage(named: "folder")!.withTintColor(NCBrandColor.shared.customer) + row.cellConfig["photoLabel.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["photoLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["photoLabel.textColor"] = UIColor.label //photos + if(self.fileNameFolder == "/"){ + row.cellConfig["photoLabel.text"] = NSLocalizedString("_prefix_upload_path_", comment: "") + }else{ + row.cellConfig["photoLabel.text"] = self.fileNameFolder + } + row.cellConfig["textLabel.text"] = "" + + section.addFormRow(row) + + // Section: File Name + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_filename_", comment: "").uppercased()) + form.addFormSection(section) + + XLFormViewController.cellClassesForRowDescriptorTypes()["kMyAppCustomCellType"] = NCCreateDocumentCustomTextField.self + + row = XLFormRowDescriptor(tag: "fileName", rowType: "kMyAppCustomCellType", title: NSLocalizedString("_filename_", comment: "")) + row.cellClass = NCCreateDocumentCustomTextField.self + + row.cellConfigAtConfigure["backgroundColor"] = UIColor.secondarySystemGroupedBackground; + row.cellConfig["fileNameTextField.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["fileNameTextField.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["fileNameTextField.textColor"] = UIColor.label + row.cellConfig["fileNameTextField.placeholder"] = self.fileName + + section.addFormRow(row) + + self.form = form + // tableView.reloadData() + // collectionView.reloadData() + } + + override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { + let header = view as? UITableViewHeaderFooterView + header?.textLabel?.font = UIFont.systemFont(ofSize: 13.0) + header?.textLabel?.textColor = .gray + header?.tintColor = tableView.backgroundColor + } + + override func tableView(_ tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) { + let header = view as? UITableViewHeaderFooterView + header?.textLabel?.font = UIFont.systemFont(ofSize: 13.0) + header?.textLabel?.textColor = .gray + header?.tintColor = tableView.backgroundColor + } + + // 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.isEmpty { + let fileNameLocalPath = utilityFileSystem.directoryUserData + "/" + template.name + ".png" + if FileManager.default.fileExists(atPath: fileNameLocalPath) { + let imageURL = URL(fileURLWithPath: fileNameLocalPath) + if let image = UIImage(contentsOfFile: imageURL.path) { + imagePreview?.image = image + } + } else { + getImageFromTemplate(name: template.name, preview: template.preview, indexPath: indexPath) + } + } + + // name + let name = cell.viewWithTag(200) as? UILabel + name?.text = template.name + name?.textColor = .secondarySystemGroupedBackground + + // select + let imageSelect = cell.viewWithTag(300) as? UIImageView + if selectTemplate != nil && selectTemplate?.name == template.name { + cell.backgroundColor = .label + imageSelect?.image = UIImage(named: "plus100") + imageSelect?.isHidden = false + } else { + cell.backgroundColor = .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 == utilityFileSystem.getHomeServer(session: session) { + fileNameFolder = "/" + } else { + fileNameFolder = (serverUrl as NSString).lastPathComponent + } + + let buttonDestinationFolder: XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! + buttonDestinationFolder.cellConfig["photoLabel.text"] = fileNameFolder + + self.tableView.reloadData() + } + +// 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.form.delegate = self +//// } +// } + + @objc func changeDestinationFolder(_ sender: XLFormRowDescriptor) { + + self.deselectFormRow(sender) + + let storyboard = UIStoryboard(name: "NCSelect", bundle: nil) + if 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() { + + Task { + guard let selectTemplate = self.selectTemplate else { return } + templateIdentifier = selectTemplate.identifier + + let rowFileName: XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! + var fileName = rowFileName.value as? String + if fileName?.isEmpty ?? false || fileName == nil { + fileName = NCUtilityFileSystem().createFileNameDate("Text", ext: getFileExtension()) + } else if fileName?.trimmingCharacters(in: .whitespaces).isEmpty ?? false { + let alert = UIAlertController(title: "", message: NSLocalizedString("_please_enter_file_name_", comment: ""), preferredStyle: .alert) + alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .cancel, handler: nil)) + self.present(alert, animated: true) + return + } + + // Ensure fileName is not nil or empty + guard var fileNameForm: String = fileName, !fileNameForm.isEmpty else { return } + + // Trim whitespaces and newlines + fileNameForm = fileNameForm.trimmingCharacters(in: .whitespacesAndNewlines) + + let fileAutoRenamer = FileAutoRenamer() + fileName = fileAutoRenamer.rename(filename: fileNameForm, isFolderPath: true) + + let result = await NKTypeIdentifiers.shared.getInternalType(fileName: fileNameForm, mimeType: "", directory: false, account: session.account) + + if utility.editorsDirectEditing(account: session.account, contentType: result.mimeType).isEmpty { + fileNameForm = (fileNameForm as NSString).deletingPathExtension + "." + fileNameExtension + } + + // verify if already exists + if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView == %@", session.account, self.serverUrl, fileNameForm)) != nil { + NCContentPresenter().showError(error: NKError(errorCode: 0, errorDescription: "_rename_already_exists_")) + return + // } + // + // if NCManageDatabase.shared.getMetadataConflict(account: session.account, serverUrl: serverUrl, fileNameView: String(describing: fileNameForm), nativeFormat: false) != nil { + // + // let metadataForUpload = NCManageDatabase.shared.createMetadata(fileName: String(describing: fileNameForm), fileNameView: String(describing: fileNameForm), ocId: UUID().uuidString, serverUrl: serverUrl, url: "", contentType: "", session: session, sceneIdentifier: self.appDelegate.sceneIdentifier) + // + // guard let conflict = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict else { return } + // + // conflict.textLabelDetailNewFile = NSLocalizedString("_now_", comment: "") + // conflict.alwaysNewFileNameNumber = true + // conflict.serverUrl = serverUrl + // conflict.metadatasUploadInConflict = [metadataForUpload] + // conflict.delegate = self + // + // self.present(conflict, animated: true, completion: nil) + + } else { + + let fileNamePath = utilityFileSystem.getFileNamePath(String(describing: fileNameForm), serverUrl: serverUrl, session: session) + await NCCreateDocument().createDocument(controller: controller, fileNamePath: fileNamePath, fileName: String(describing: fileNameForm), fileNameExtension: self.fileNameExtension, editorId: editorId, creatorId: creatorId, templateId: templateIdentifier, account: session.account) + + } + } + } + + func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) { + + if let metadatas, metadatas.count > 0 { + let fileName = metadatas[0].fileName + let fileNamePath = utilityFileSystem.getFileNamePath(fileName, serverUrl: serverUrl, session: session) +// createDocument(fileNamePath: fileNamePath, fileName: fileName) + Task { + await NCCreateDocument().createDocument(controller: controller, fileNamePath: fileNamePath, fileName: String(describing: fileName), editorId: editorId, creatorId: creatorId, templateId: templateIdentifier, account: session.account) + } + + } else { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + self.cancel() + } + } + } + + func createDocument(fileNamePath: String, fileName: String) { + + self.navigationItem.rightBarButtonItem?.isEnabled = false + var UUID = NSUUID().uuidString + UUID = "TEMP" + UUID.replacingOccurrences(of: "-", with: "") + + if self.editorId == NCGlobal.shared.editorText || self.editorId == NCGlobal.shared.editorOnlyoffice { + + Task { + var options = NKRequestOptions() + if self.editorId == NCGlobal.shared.editorOnlyoffice { + options = NKRequestOptions(customUserAgent: utility.getCustomUserAgentOnlyOffice()) + } else if editorId == NCGlobal.shared.editorText { + options = NKRequestOptions(customUserAgent: utility.getCustomUserAgentNCText()) + } + + let results = await NextcloudKit.shared.textCreateFileAsync(fileNamePath: fileNamePath, editorId: editorId, creatorId: creatorId, templateId: templateIdentifier, account: session.account, options: options) { task in + Task { + let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: self.session.account, + path: fileNamePath, + name: "textCreateFile") + await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task) + } + } + guard results.error == .success, let url = results.url else { + return NCContentPresenter().showError(error: results.error) + } + let metadata = await NCManageDatabase.shared.createMetadataAsync(fileName: fileName, + ocId: UUID, + serverUrl: serverUrl, + url: url, + session: session, + sceneIdentifier: controller.sceneIdentifier) + AnalyticsHelper.shared.trackCreateFile(metadata: metadata) + if let vc = await NCViewer().getViewerController(metadata: metadata, delegate: controller) { + controller.navigationController?.pushViewController(vc, animated: true) + } + } + } + + if self.editorId == NCGlobal.shared.editorCollabora { + Task { + + let results = await NextcloudKit.shared.createRichdocumentsAsync(path: fileNamePath, templateId: templateIdentifier, account: session.account) { task in + Task { + let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: self.session.account, + path: fileNamePath, + name: "CreateRichdocuments") + await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task) + } + } + guard results.error == .success, let url = results.url else { + return NCContentPresenter().showError(error: results.error) + } + + let metadata = await NCManageDatabase.shared.createMetadataAsync(fileName: fileName, + ocId: UUID, + serverUrl: serverUrl, + url: url, + session: session, + sceneIdentifier: controller.sceneIdentifier) + + if let vc = await NCViewer().getViewerController(metadata: metadata, delegate: controller) { + controller.navigationController?.pushViewController(vc, animated: true) + } + } + } + } + + @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 options = NKRequestOptions() + if self.editorId == NCGlobal.shared.editorOnlyoffice { + options = NKRequestOptions(customUserAgent: utility.getCustomUserAgentOnlyOffice()) + } else if editorId == NCGlobal.shared.editorText { + options = NKRequestOptions(customUserAgent: utility.getCustomUserAgentNCText()) + } + + NextcloudKit.shared.textGetListOfTemplates(account: session.account, options: options) { account, templates, _, error in + + self.indicator.stopAnimating() + + if error == .success && account == self.session.account, let templates = templates { + + for template in templates { + + var temp = NKEditorTemplate() + + 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.isEmpty { + self.selectTemplate = temp + self.fileNameExtension = template.ext + self.navigationItem.rightBarButtonItem?.isEnabled = true + } + } + } + + if self.listOfTemplate.isEmpty { + + var temp = NKEditorTemplate() + + temp.identifier = "" + if self.editorId == NCGlobal.shared.editorText { + temp.ext = "md" + } else if self.editorId == NCGlobal.shared.editorOnlyoffice && self.typeTemplate == NCGlobal.shared.templateDocument { + temp.ext = "docx" + } else if self.editorId == NCGlobal.shared.editorOnlyoffice && self.typeTemplate == NCGlobal.shared.templateSpreadsheet { + temp.ext = "xlsx" + } else if self.editorId == NCGlobal.shared.editorOnlyoffice && self.typeTemplate == NCGlobal.shared.templatePresentation { + temp.ext = "pptx" + } + 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 { + + NextcloudKit.shared.getTemplatesRichdocuments(typeTemplate: typeTemplate, account: session.account) { account, templates, _, error in + + self.indicator.stopAnimating() + + if error == .success && account == self.session.account { + + for template in templates! { + + var temp = NKEditorTemplate() + + 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.isEmpty { + self.selectTemplate = temp + self.fileNameExtension = temp.ext + self.navigationItem.rightBarButtonItem?.isEnabled = true + } + } + } + + if self.listOfTemplate.isEmpty { + + var temp = NKEditorTemplate() + + temp.identifier = "" + if self.typeTemplate == NCGlobal.shared.templateDocument { + temp.ext = "docx" + } else if self.typeTemplate == NCGlobal.shared.templateSpreadsheet { + temp.ext = "xlsx" + } else if self.typeTemplate == NCGlobal.shared.templatePresentation { + temp.ext = "pptx" + } + 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 = utilityFileSystem.directoryUserData + "/" + name + ".png" + + NextcloudKit.shared.download(serverUrlFileName: preview, fileNameLocalPath: fileNameLocalPath, account: session.account, requestHandler: { _ in + + }, taskHandler: { _ in + + }, progressHandler: { _ in + + }) { account, _, _, _, _, _, error in + + if error == .success && account == self.session.account { + self.collectionView.reloadItems(at: [indexPath]) + } else if error != .success { + print("\(error.errorCode)") + } else { + print("[ERROR] It has been changed user during networking process, error.") + } + } + } + + func getFileExtension() -> String { + switch typeTemplate { + case NCGlobal.shared.editorText: + return "md" + case NCGlobal.shared.templateDocument: + return "docx" + case NCGlobal.shared.templateSpreadsheet: + return "xlsx" + case NCGlobal.shared.templatePresentation: + return "pptx" + default: + return "" + } + } +} diff --git a/iOSClient/Main/Create/NCCreateFormUploadVoiceNote.storyboard b/iOSClient/Main/Create/NCCreateFormUploadVoiceNote.storyboard new file mode 100644 index 0000000000..1b5344ccee --- /dev/null +++ b/iOSClient/Main/Create/NCCreateFormUploadVoiceNote.storyboard @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Main/Create/NCCreateFormUploadVoiceNote.swift b/iOSClient/Main/Create/NCCreateFormUploadVoiceNote.swift new file mode 100644 index 0000000000..f61f3cf801 --- /dev/null +++ b/iOSClient/Main/Create/NCCreateFormUploadVoiceNote.swift @@ -0,0 +1,371 @@ +// +// NCCreateFormUploadVoiceNote.swift +// Nextcloud +// +// Created by Marino Faggiana on 9/03/2019. +// Copyright © 2019 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import UIKit +import NextcloudKit +import XLForm +import AVFAudio + +class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAudioPlayerDelegate, NCCreateFormUploadConflictDelegate { + + @IBOutlet weak var buttonPlayStop: UIButton! + @IBOutlet weak var labelTimer: UILabel! + @IBOutlet weak var labelDuration: UILabel! + @IBOutlet weak var progressView: UIProgressView! + + private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + let utilityFileSystem = NCUtilityFileSystem() + let utility = NCUtility() + private var serverUrl = "" + private var titleServerUrl = "" + private var fileName = "" + private var fileNamePath = "" + private var durationPlayer: TimeInterval = 0 + private var counterSecondPlayer: TimeInterval = 0 + + private var audioPlayer: AVAudioPlayer! + private var timer = Timer() + + var cellBackgoundColor = UIColor.secondarySystemGroupedBackground + + var controller: NCMainTabBarController! + var session: NCSession.Session { + NCSession.shared.getSession(controller: controller) + } + + // MARK: - View Life Cycle + + 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.navigationItem.leftBarButtonItem?.tintColor = NCBrandColor.shared.brand + self.navigationItem.rightBarButtonItem?.tintColor = NCBrandColor.shared.brand + + self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none + + view.backgroundColor = .systemGroupedBackground + tableView.backgroundColor = .systemGroupedBackground + cellBackgoundColor = .secondarySystemGroupedBackground + + self.title = NSLocalizedString("_voice_memo_title_", comment: "") + + // Button Play Stop + buttonPlayStop.setImage(UIImage(named: "audioPlay")!.image(color: NCBrandColor.shared.iconImageColor, size: 100), for: .normal) + + // Progress view + progressView.progress = 0 + progressView.progressTintColor = NCBrandColor.shared.customer + progressView.trackTintColor = .white + progressView.layer.borderWidth = 1 + progressView.layer.cornerRadius = 5.0 + progressView.layer.borderColor = NCBrandColor.shared.customer.cgColor + + labelTimer.textColor = .label + labelDuration.textColor = .label + + initializeForm() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + updateTimerUI() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + if audioPlayer.isPlaying { + stop() + } + } + + public func setup(serverUrl: String, fileNamePath: String, fileName: String) { + + if serverUrl == utilityFileSystem.getHomeServer(session: session) { + titleServerUrl = "/" + } else { + titleServerUrl = utilityFileSystem.getTextServerUrl(session: session, serverUrl: serverUrl)//(serverUrl as NSString).lastPathComponent + } + + self.fileName = fileName + self.serverUrl = serverUrl + self.fileNamePath = fileNamePath + + // player + do { + try audioPlayer = AVAudioPlayer(contentsOf: URL(fileURLWithPath: fileNamePath)) + audioPlayer.prepareToPlay() + audioPlayer.delegate = self + durationPlayer = TimeInterval(audioPlayer.duration) + } catch { + buttonPlayStop.isEnabled = false + } + } + + // MARK: XLForm + + func initializeForm() { + + let form: XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section: XLFormSectionDescriptor + var row: XLFormRowDescriptor + + // Section: Destination Folder + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_save_path_", comment: "").uppercased()) + section.footerTitle = "" + form.addFormSection(section) + + XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFolderCustomCellType"] = FolderPathCustomCell.self + + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: "kNMCFolderCustomCellType", title: self.titleServerUrl) + row.cellConfig["backgroundColor"] = UIColor.secondarySystemGroupedBackground + row.action.formSelector = #selector(changeDestinationFolder(_:)) + row.cellConfig["folderImage.image"] = UIImage(named: "folder_nmcloud")?.image(color: NCBrandColor.shared.brandElement, size: 25) + row.cellConfig["photoLabel.textAlignment"] = NSTextAlignment.right.rawValue + row.cellConfig["photoLabel.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["photoLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["photoLabel.textColor"] = UIColor.label //photos + if(self.titleServerUrl == "/"){ + row.cellConfig["photoLabel.text"] = NSLocalizedString("_prefix_upload_path_", comment: "") + }else{ + row.cellConfig["photoLabel.text"] = self.titleServerUrl + } + row.cellConfig["textLabel.text"] = "" + section.addFormRow(row) + + // Section: File Name + + XLFormViewController.cellClassesForRowDescriptorTypes()["kMyAppCustomCellType"] = TextTableViewCell.self + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_filename_", comment: "").uppercased()) + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: "fileName", rowType: "kMyAppCustomCellType", title: NSLocalizedString("_filename_", comment: "")) + row.cellClass = TextTableViewCell.self + row.cellConfigAtConfigure["backgroundColor"] = UIColor.secondarySystemGroupedBackground; + row.cellConfig["fileNameTextField.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["fileNameTextField.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["fileNameTextField.textColor"] = UIColor.label + row.cellConfig["fileNameTextField.text"] = self.fileName + 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 as? String { + self.fileName = utility.removeForbiddenCharacters(fileNameNew) + self.fileName = FileAutoRenamer.rename(filename: fileNameNew, isFolderPath: true) + } else { + self.fileName = "" + } + + + self.form.delegate = self + } + } + + // MARK: TableViewDelegate + + override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { + let header = view as? UITableViewHeaderFooterView + header?.textLabel?.font = UIFont.systemFont(ofSize: 13.0) + 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 == utilityFileSystem.getHomeServer(session: session) { + self.titleServerUrl = "/" + } else { + self.titleServerUrl = (serverUrl! as NSString).lastPathComponent + } + + // Update + let row: XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! + row.cellConfig["photoLabel.text"] = self.titleServerUrl + self.updateFormRow(row) + } + } + + @objc func save() { + let name = self.fileName + guard name.trimmingCharacters(in: .whitespaces) != "" else { + let alert = UIAlertController(title: "", message: NSLocalizedString("_prompt_insert_file_name", comment: ""), preferredStyle: .alert) + alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .cancel, handler: nil)) + self.present(alert, animated: true) + return + } + let ext = (name as NSString).pathExtension.uppercased() + var fileNameSave = "" + + if ext.isEmpty { + fileNameSave = name + ".m4a" + } else { + fileNameSave = (name as NSString).deletingPathExtension + ".m4a" + } + + let metadataForUpload = NCManageDatabase.shared.createMetadata(fileName: fileNameSave, fileNameView: fileNameSave, ocId: UUID().uuidString, serverUrl: serverUrl, url: "", contentType: "", session: session, sceneIdentifier: self.appDelegate.sceneIdentifier) + + metadataForUpload.session = NCNetworking.shared.sessionUploadBackground + metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile + metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload + metadataForUpload.size = utilityFileSystem.getFileSize(filePath: fileNamePath) + + if NCManageDatabase.shared.getMetadataConflict(account: session.account, serverUrl: serverUrl, fileNameView: fileNameSave, nativeFormat: false) != nil { + + guard let conflict = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict else { return } + + conflict.textLabelDetailNewFile = NSLocalizedString("_now_", comment: "") + conflict.serverUrl = serverUrl + conflict.metadatasUploadInConflict = [metadataForUpload] + conflict.delegate = self + + self.present(conflict, animated: true, completion: nil) + + } else { + + dismissAndUpload(metadataForUpload) + } + } + + func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) { + + if let metadatas, metadatas.count > 0 { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + self.dismissAndUpload(metadatas[0]) + } + } + } + + func dismissAndUpload(_ metadata: tableMetadata) { + + AnalyticsHelper.shared.trackCreateVoiceMemo(size: metadata.size, date: metadata.creationDate as Date) + + utilityFileSystem.copyFile(atPath: self.fileNamePath, toPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)) + + NCNetworkingProcess.shared.createProcessUploads(metadatas: [metadata], completion: { _ in }) + + 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) + if 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 + + func updateTimerUI() { + 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: UIColor.systemGray, 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: UIColor.systemGray, 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: UIColor.systemGray, size: 100), for: .normal) + } +} diff --git a/iOSClient/Main/Create/TextTableViewCell.swift b/iOSClient/Main/Create/TextTableViewCell.swift new file mode 100644 index 0000000000..8777b1878a --- /dev/null +++ b/iOSClient/Main/Create/TextTableViewCell.swift @@ -0,0 +1,95 @@ +// +// TextTableViewCell.swift +// Nextcloud +// +// Created by Ashu on 23/04/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import UIKit +import XLForm + +class TextTableViewCell: XLFormBaseCell, UITextFieldDelegate { + + @IBOutlet weak var fileNameTextField: UITextField! + @IBOutlet weak var topLineView: UIView! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + + fileNameTextField.delegate = self + topLineView.backgroundColor = UIColor.secondarySystemBackground + + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + if (rowDescriptor.tag == "maskFileName"){ + topLineView.isHidden = true + }else{ + topLineView.isHidden = false + } + + fileNameTextField.tintColor = UIColor.systemGray + fileNameTextField.selectedTextRange = fileNameTextField.textRange(from: fileNameTextField.beginningOfDocument, to: fileNameTextField.endOfDocument) + } + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + + if fileNameTextField == textField { + if let rowDescriptor = rowDescriptor, let text = self.fileNameTextField.text { + + if (text + " ").isEmpty == false { + rowDescriptor.value = self.fileNameTextField.text! + string + } else { + rowDescriptor.value = nil + } + } + } + + self.formViewController().textField(textField, shouldChangeCharactersIn: range, replacementString: string) + + return true + } + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + self.formViewController()?.textFieldShouldReturn(fileNameTextField) + return true + } + + func textFieldShouldClear(_ textField: UITextField) -> Bool { + self.formViewController()?.textFieldShouldClear(fileNameTextField) + rowDescriptor.value = nil + + self.formViewController().textField(textField, shouldChangeCharactersIn: NSRange.init().self, replacementString: "") + return true + } + + override class func formDescriptorCellHeight(for rowDescriptor: XLFormRowDescriptor!) -> CGFloat { + return 45 + } +} + +extension UITextField { + @IBInspectable var placeholderColor: UIColor { + get { + return attributedPlaceholder?.attribute(.foregroundColor, at: 0, effectiveRange: nil) as? UIColor ?? .clear + } + set { + guard let attributedPlaceholder = attributedPlaceholder else { return } + let attributes: [NSAttributedString.Key: UIColor] = [.foregroundColor: newValue] + self.attributedPlaceholder = NSAttributedString(string: attributedPlaceholder.string, attributes: attributes) + } + } +} diff --git a/iOSClient/Main/Create/TextTableViewCell.xib b/iOSClient/Main/Create/TextTableViewCell.xib new file mode 100644 index 0000000000..e4be37d230 --- /dev/null +++ b/iOSClient/Main/Create/TextTableViewCell.xib @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Media/NCMediaCommandView.xib b/iOSClient/Media/NCMediaCommandView.xib new file mode 100644 index 0000000000..b2df2d68eb --- /dev/null +++ b/iOSClient/Media/NCMediaCommandView.xib @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/NMC Custom Views/FolderPathCustomCell.swift b/iOSClient/NMC Custom Views/FolderPathCustomCell.swift new file mode 100644 index 0000000000..cb7553eda7 --- /dev/null +++ b/iOSClient/NMC Custom Views/FolderPathCustomCell.swift @@ -0,0 +1,34 @@ +// +// FolderPathCustomCell.swift +// Nextcloud +// +// Created by A200073704 on 04/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import UIKit +import XLForm + +class FolderPathCustomCell: XLFormButtonCell{ + + @IBOutlet weak var photoLabel: UILabel! + @IBOutlet weak var folderImage: UIImageView! + @IBOutlet weak var bottomLineView: UIView! + + override func awakeFromNib() { + super.awakeFromNib() + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + if (rowDescriptor.tag == "PhotoButtonDestinationFolder"){ + bottomLineView.isHidden = true + }else{ + bottomLineView.isHidden = false + } + } +} diff --git a/iOSClient/NMC Custom Views/FolderPathCustomCell.xib b/iOSClient/NMC Custom Views/FolderPathCustomCell.xib new file mode 100644 index 0000000000..caca063abf --- /dev/null +++ b/iOSClient/NMC Custom Views/FolderPathCustomCell.xib @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/NMC Custom Views/NCCreateDocumentCustomTextField.swift b/iOSClient/NMC Custom Views/NCCreateDocumentCustomTextField.swift new file mode 100644 index 0000000000..3983e413a6 --- /dev/null +++ b/iOSClient/NMC Custom Views/NCCreateDocumentCustomTextField.swift @@ -0,0 +1,71 @@ +// +// NCCreateDocumentCustomTextField.swift +// Nextcloud +// +// Created by A200073704 on 04/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import UIKit +import XLForm + +class NCCreateDocumentCustomTextField: XLFormBaseCell,UITextFieldDelegate { + + @IBOutlet weak var fileNameTextField: UITextField! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + + fileNameTextField.delegate = self + + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + } + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + + if fileNameTextField == textField { + if let rowDescriptor = rowDescriptor { + if let text = textField.text{ + if (text + " ").isEmpty == false { + rowDescriptor.value = self.fileNameTextField.text! + string + } else { + rowDescriptor.value = nil + } + } + } + } + + self.formViewController().textField(textField, shouldChangeCharactersIn: range, replacementString: string) + + + return true + } + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + self.formViewController()?.textFieldShouldReturn(fileNameTextField) + return true + } + + func textFieldShouldClear(_ textField: UITextField) -> Bool { + self.formViewController()?.textFieldShouldClear(fileNameTextField) + return true + } + + override class func formDescriptorCellHeight(for rowDescriptor: XLFormRowDescriptor!) -> CGFloat { + return 45 + } +} diff --git a/iOSClient/NMC Custom Views/NCCreateDocumentCustomTextField.xib b/iOSClient/NMC Custom Views/NCCreateDocumentCustomTextField.xib new file mode 100644 index 0000000000..3fd86bb2d6 --- /dev/null +++ b/iOSClient/NMC Custom Views/NCCreateDocumentCustomTextField.xib @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Scan document/NCCreateFormUploadScanDocument.swift b/iOSClient/Scan document/NCCreateFormUploadScanDocument.swift new file mode 100644 index 0000000000..caa5aefaf4 --- /dev/null +++ b/iOSClient/Scan document/NCCreateFormUploadScanDocument.swift @@ -0,0 +1,1334 @@ +// +// NCCreateFormUploadScanDocument.swift +// Nextcloud +// +// Created by Marino Faggiana on 14/11/2018. +// Copyright © 2018 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import UIKit +import NextcloudKit +import Vision +import VisionKit +import Photos +import XLForm + +class NCCreateFormUploadScanDocument: XLFormViewController, NCSelectDelegate, NCCreateFormUploadConflictDelegate { + + let appDelegate = UIApplication.shared.delegate as? AppDelegate + + enum TypeQuality { + case low + case medium + case high + } + var quality: TypeQuality = .medium + + var editorId = "" + var serverUrl = "" + var titleServerUrl = "" + var arrayImages: [UIImage] = [] + var fileName = NCUtilityFileSystem().createFileNameDate("scan", ext: "pdf") + var password: String = "" + var fileType = "PDF" + var isPDFWithOCRSwitchOn = false + var isPDFWithoutOCRSwitchOn = false + var isSetpasswordEnable = false + + var isTextFileSwitchOn = false + var isPNGFormatSwitchOn = false + var isJPGFormatSwitchOn = false + var isOCRActivatedFileConflicts = false + + + var cellBackgoundColor = NCBrandColor.shared.secondarySystemGroupedBackground + let utilityFileSystem = NCUtilityFileSystem() + let utility = NCUtility() + let contentPresenter = NCContentPresenter() + var controller: NCMainTabBarController! + var session: NCSession.Session { + NCSession.shared.getSession(controller: controller) + } + + // MARK: - View Life Cycle + + convenience init(serverUrl: String, arrayImages: [UIImage]) { + + self.init() + + if serverUrl == utilityFileSystem.getHomeServer(urlBase: appDelegate?.urlBase ?? "", userId: appDelegate?.userId ?? "") { + titleServerUrl = "/" + } else { + titleServerUrl = (serverUrl as NSString).lastPathComponent + if serverUrl == utilityFileSystem.getHomeServer(session: session) { + titleServerUrl = "/" + } else { + titleServerUrl = utilityFileSystem.getTextServerUrl(session: session, serverUrl: serverUrl)//(serverUrl as NSString).lastPathComponent + } + + self.serverUrl = serverUrl + self.arrayImages = arrayImages + } + + // MARK: - View Life Cycle + + 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)) + + self.navigationItem.rightBarButtonItem = saveButton + let cancelButton : UIBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(cancel)) + self.navigationItem.leftBarButtonItem = cancelButton + self.navigationItem.rightBarButtonItem?.tintColor = NCBrandColor.shared.brand + self.navigationItem.leftBarButtonItem?.tintColor = NCBrandColor.shared.brand + + self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none + + changeTheming() + + initializeForm() + + let value = NCKeychain().textRecognitionStatus + setTextRecognition(newValue: value) + NotificationCenter.default.addObserver(self, selector: #selector(appTerminateNotify), name: UIApplication.willTerminateNotification, object: nil) + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + changeTheming() + } + + override func viewWillDisappear(_ animated: Bool) { + NotificationCenter.default.removeObserver(self) + showDeleteAlert() + } + + @objc func appTerminateNotify() { + showDeleteAlert() + } + // MARK: - Theming + + @objc func changeTheming() { + + view.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground + tableView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground + cellBackgoundColor = NCBrandColor.shared.secondarySystemGroupedBackground + tableView.reloadData() + } + + // MARK: XLForm + + func initializeForm() { + + let form: XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section: XLFormSectionDescriptor + var row: XLFormRowDescriptor + + // Section: Destination Folder + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_save_path_", comment: "")) + form.addFormSection(section) + + XLFormViewController.cellClassesForRowDescriptorTypes()["NMCScamFileNameCustomInputField"] = FileNameInputTextField.self + row = XLFormRowDescriptor(tag: "fileName", rowType: "NMCScamFileNameCustomInputField", title: NSLocalizedString("_filename_", comment: "")) + row.cellClass = FileNameInputTextField.self + row.cellConfig["fileNameInputTextField.placeholder"] = self.fileName + + row.cellConfig["fileNameInputTextField.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["fileNameInputTextField.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["fileNameInputTextField.textColor"] = NCBrandColor.shared.label + + + section.addFormRow(row) + //FileName custom view END + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_location_", comment: "")) + form.addFormSection(section) + + //Scan documnet folder path + XLFormViewController.cellClassesForRowDescriptorTypes()["NMCScanFolderPathCustomCell"] = ScanDocumentPathView.self + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: "NMCScanFolderPathCustomCell", title: self.titleServerUrl) + row.action.formSelector = #selector(changeDestinationFolder(_:)) + row.cellConfig["backgroundColor"] = cellBackgoundColor + row.cellConfig["folderImage.image"] = UIImage(named: "folder")?.imageColor(NCBrandColor.shared.customer) + row.cellConfig["photoLabel.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["photoLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["photoLabel.textColor"] = NCBrandColor.shared.label + + // Section: Destination Folder + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_save_path_", comment: "").uppercased()) + section.footerTitle = "" + form.addFormSection(section) + + XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFolderCustomCellType"] = FolderPathCustomCell.self + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: "kNMCFolderCustomCellType", title: self.titleServerUrl) + row.cellConfig["backgroundColor"] = UIColor.secondarySystemGroupedBackground + row.action.formSelector = #selector(changeDestinationFolder(_:)) + row.cellConfig["folderImage.image"] = UIImage(named: "folder_nmcloud")?.image(color: NCBrandColor.shared.brandElement, size: 25) + row.cellConfig["photoLabel.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["photoLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["photoLabel.textColor"] = UIColor.label //photos + if(self.titleServerUrl == "/"){ + row.cellConfig["photoLabel.text"] = NSLocalizedString("_prefix_upload_path_", comment: "") + }else{ + row.cellConfig["photoLabel.text"] = self.titleServerUrl + } + row.cellConfig["textLabel.text"] = "" + + section.addFormRow(row) + // END of Scan documnet folder path + + section.addFormRow(row) + + // Section: File Name + + XLFormViewController.cellClassesForRowDescriptorTypes()["kMyAppCustomCellType"] = TextTableViewCell.self + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_filename_", comment: "").uppercased()) + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: "fileName", rowType: "kMyAppCustomCellType", title: NSLocalizedString("_filename_", comment: "")) + row.cellClass = TextTableViewCell.self + row.cellConfigAtConfigure["backgroundColor"] = UIColor.secondarySystemGroupedBackground; + row.cellConfig["fileNameTextField.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["fileNameTextField.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["fileNameTextField.textColor"] = UIColor.label + row.cellConfig["fileNameTextField.text"] = self.fileName + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_save_with_text_recognition_", comment: "")) + form.addFormSection(section) + + // Save with Text Recognition PDF + XLFormViewController.cellClassesForRowDescriptorTypes()["NMCPdfWithOCRSwitchCell"] = PdfWithOcrSwitchView.self + row = XLFormRowDescriptor(tag: "PDFWithOCRSwitch", rowType: "NMCPdfWithOCRSwitchCell", title: self.titleServerUrl) + row.cellConfig["cellLabel.text"] = NSLocalizedString("_pdf_with_ocr_", comment: "") + row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.brand + row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["cellLabel.textColor"] = NCBrandColor.shared.label + + section.addFormRow(row) + // END of Save with Text Recognition PDF + + //Save with Text Recognition text file + XLFormViewController.cellClassesForRowDescriptorTypes()["NMCTextFileWithOCRSwitchCell"] = TextFileWithOcrSwitchView.self + row = XLFormRowDescriptor(tag: "TextFileWithOCRSwitch", rowType: "NMCTextFileWithOCRSwitchCell", title: self.titleServerUrl) + row.cellConfig["cellLabel.text"] = NSLocalizedString("_text_file_ocr_", comment: "") + row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.brand + row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["cellLabel.textColor"] = NCBrandColor.shared.label + + section.addFormRow(row) + //END of Save with Text Recognition text file + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_save_without_text_recognition_", comment: "")) + form.addFormSection(section) + + // PDF without text recongnition + XLFormViewController.cellClassesForRowDescriptorTypes()["NMCPDFWithoutOCRSwitchCell"] = PdfWithoutOcrSwitchView.self + row = XLFormRowDescriptor(tag: "PDFWithoutOCRSwitch", rowType: "NMCPDFWithoutOCRSwitchCell", title: self.titleServerUrl) + row.cellConfig["cellLabel.text"] = NSLocalizedString("_pdf_", comment: "") + row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.brand + row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["cellLabel.textColor"] = NCBrandColor.shared.label + + section.addFormRow(row) + // END of PDF without text recongnition + + // JPG without text recongnition + + XLFormViewController.cellClassesForRowDescriptorTypes()["NMCJPGWithoutOCRSwitchCell"] = JPGImageSaveSwitchView.self + row = XLFormRowDescriptor(tag: "JPGWithoutOCRSwitch", rowType: "NMCJPGWithoutOCRSwitchCell", title: self.titleServerUrl) + row.cellConfig["cellLabel.text"] = NSLocalizedString("_jpg_", comment: "") + row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.brand + row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["cellLabel.textColor"] = NCBrandColor.shared.label + + section.addFormRow(row) + // END JPG without text recongnition + + // PNG without text recongnition + XLFormViewController.cellClassesForRowDescriptorTypes()["NMCPNGWithoutOCRSwitchCell"] = PNGImageSaveSwitchView.self + row = XLFormRowDescriptor(tag: "PNGWithoutOCRSwitch", rowType: "NMCPNGWithoutOCRSwitchCell", title: self.titleServerUrl) + row.cellConfig["cellLabel.text"] = NSLocalizedString("_png_", comment: "") + row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.brand + row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["cellLabel.textColor"] = NCBrandColor.shared.label + + section.addFormRow(row) + // END without text recongnition + + // PDF password section + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_pdf_password_", comment: "")) + form.addFormSection(section) + // END of PDF password + + // Set PDF password switch + XLFormViewController.cellClassesForRowDescriptorTypes()["NMCSetPDFPasswordSwitchCell"] = SetPDFPasswordSwitchView.self + row = XLFormRowDescriptor(tag: "PDFSetPasswordSwitch", rowType: "NMCSetPDFPasswordSwitchCell", title: self.titleServerUrl) + row.cellConfig["cellLabel.text"] = NSLocalizedString("_set_password_", comment: "") + row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.brand + row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["cellLabel.textColor"] = NCBrandColor.shared.label + + section.addFormRow(row) + // END of set PDF password switch + + // enter password input field + XLFormViewController.cellClassesForRowDescriptorTypes()["NMCSetPasswordCustomInputField"] = PasswordInputField.self + row = XLFormRowDescriptor(tag: "SetPasswordInputField", rowType: "NMCSetPasswordCustomInputField", title: NSLocalizedString("_filename_", comment: "")) + row.cellClass = PasswordInputField.self + row.cellConfig["fileNameInputTextField.placeholder"] = NSLocalizedString("_password_", comment: "") + + row.cellConfig["fileNameInputTextField.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["fileNameInputTextField.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["fileNameInputTextField.textColor"] = NCBrandColor.shared.label + row.cellConfig["backgroundColor"] = NCBrandColor.shared.secondarySystemGroupedBackground + row.hidden = 1 + + + 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"] = NCBrandColor.shared.backgroundForm + + 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 + + self.form = form + } + + override func formRowDescriptorValueHasChanged(_ formRow: XLFormRowDescriptor!, oldValue: Any!, newValue: Any!) { + + super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue) + + if formRow.tag == "textRecognition" { + + } + + if formRow.tag == "fileName" { + + self.form.delegate = nil + + let fileNameNew = newValue as? String + + if let fileNameNew = newValue as? String { + self.fileName = utility.removeForbiddenCharacters(fileNameNew) + self.fileName = FileAutoRenamer.rename(filename: fileNameNew, isFolderPath: true) + } else { + self.fileName = "" + } + + formRow.value = self.fileName + + self.updateFormRow(formRow) + + self.form.delegate = self + } + + if formRow.tag == "password" { + let stringPassword = newValue as? String + if stringPassword != nil { + password = stringPassword! + } else { + 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")! + rowFileName.value = createFileName(rowFileName.value as? String) + + self.updateFormRow(rowFileName) + + // rowPassword + if fileType == "JPG" || fileType == "TXT" { + rowPassword.value = "" + password = "" + rowPassword.disabled = true + } else { + rowPassword.disabled = false + } + + self.updateFormRow(rowPassword) + } + + if formRow.tag == "PDFSetPasswordSwitch"{ + + isSetpasswordEnable = (formRow.value! as AnyObject).boolValue + let setPasswordInputField : XLFormRowDescriptor = self.form.formRow(withTag: "SetPasswordInputField")! + if (formRow.value! as AnyObject).boolValue == true { + setPasswordInputField.hidden = 0 + }else { + setPasswordInputField.hidden = 1 + } + } + + if formRow.tag == "PDFWithOCRSwitch"{ + //TODO + print("In PDF with OCR: value for without OCR \(isPDFWithoutOCRSwitchOn)") + isPDFWithOCRSwitchOn = (formRow.value! as AnyObject).boolValue + if (!isPDFWithoutOCRSwitchOn){ + if (formRow.value! as AnyObject).boolValue == true { + let setPasswordSwitchOption : XLFormRowDescriptor = self.form.formRow(withTag: "PDFSetPasswordSwitch")! + setPasswordSwitchOption.cellConfig["cellLabel.textColor"] = NCBrandColor.shared.label//isEnabled + setPasswordSwitchOption.value = "enable_switch" + + self.tableView.reloadData() + }else{ + let setPasswordSwitchOption : XLFormRowDescriptor = self.form.formRow(withTag: "PDFSetPasswordSwitch")! + setPasswordSwitchOption.cellConfig["cellLabel.textColor"] = NCBrandColor.shared.graySoft + setPasswordSwitchOption.disabled = true + setPasswordSwitchOption.value = "disable_switch" + self.tableView.reloadData() + + } + } + + } + + if formRow.tag == "PDFWithoutOCRSwitch"{ + print("In PDF without OCR: value for with OCR \(isPDFWithOCRSwitchOn)") + + isPDFWithoutOCRSwitchOn = (formRow.value! as AnyObject).boolValue + if(!isPDFWithOCRSwitchOn){ + if (formRow.value! as AnyObject).boolValue == true { + let setPasswordSwitchOption : XLFormRowDescriptor = self.form.formRow(withTag: "PDFSetPasswordSwitch")! + setPasswordSwitchOption.cellConfig["cellLabel.textColor"] = NCBrandColor.shared.label//isEnabled + setPasswordSwitchOption.value = "enable_switch" + + self.tableView.reloadData() + }else{ + let setPasswordSwitchOption : XLFormRowDescriptor = self.form.formRow(withTag: "PDFSetPasswordSwitch")! + setPasswordSwitchOption.cellConfig["cellLabel.textColor"] = NCBrandColor.shared.graySoft + setPasswordSwitchOption.disabled = true + setPasswordSwitchOption.value = "disable_switch" + self.tableView.reloadData() + + } + } + + } + + if formRow.tag == "SetPasswordInputField" { + let stringPassword = newValue as? String + if stringPassword != nil { + password = stringPassword! + } else { + password = "" + } + } + + if formRow.tag == "TextFileWithOCRSwitch" { + isTextFileSwitchOn = (formRow.value! as AnyObject).boolValue + self.setTextRecognition(newValue: newValue as? Bool ?? false) + } + if formRow.tag == "JPGWithoutOCRSwitch" { + isJPGFormatSwitchOn = (formRow.value! as AnyObject).boolValue + } + if formRow.tag == "PNGWithoutOCRSwitch" { + isPNGFormatSwitchOn = (formRow.value! as AnyObject).boolValue + } + + + } + + + override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { + return 4 + } + func setTextRecognition(newValue: Bool) { + + let rowFileName: XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! + + self.form.delegate = nil + fileType = "PDF" + rowFileName.value = createFileName(rowFileName.value as? String) + self.updateFormRow(rowFileName) + self.tableView.reloadData() + + NCKeychain().textRecognitionStatus = newValue + + self.form.delegate = self + } + + func createFileName(_ fileName: String?) -> String { + + var name: String = "" + var newFileName: String = "" + + if fileName == nil || fileName == "" { + name = utilityFileSystem.createFileNameDate("scan", ext: "pdf") + name = utilityFileSystem.createFileNameDate("scan", ext: "pdf") + } else { + name = fileName! + } + + let ext = (name as NSString).pathExtension.uppercased() + + 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], indexPath: [IndexPath], overwrite: Bool, copy: Bool, move: Bool) { + + func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) { + + + func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) { + + if serverUrl != nil { + + self.serverUrl = serverUrl! + + if serverUrl == utilityFileSystem.getHomeServer(urlBase: appDelegate?.urlBase ?? "", userId: appDelegate?.userId ?? "") { + if serverUrl == utilityFileSystem.getHomeServer(session: session) { + self.titleServerUrl = "/" + } else { + self.titleServerUrl = (serverUrl! as NSString).lastPathComponent + } + + // Update + let row : XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! + row.title = self.titleServerUrl + row.cellConfig["photoLabel.text"] = self.titleServerUrl + self.updateFormRow(row) + } + } + + func startProcessForSaving(){ + + 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 == "" { + fileNameSave = (name as? String ?? "") + "." + fileType.lowercased() + } else { + fileNameSave = ((name as? NSString)?.deletingPathExtension ?? "") + "." + fileType.lowercased() + } + + + NCActivityIndicator.shared.startActivity(backgroundView: self.view, style: .medium) + + saveImages(fileNameSave: fileNameSave,fileType: "jpg",metadataConflict: nil,completion: { (success) -> Void in + print("jpg line of code executed") + if success { // this will be equal to whatever value is set in this method call + print("true") + saveImages(fileNameSave: fileNameSave,fileType: "png",metadataConflict: nil,completion: { (success) -> Void in + print("png line of code executed") + if success { + if(isPDFWithOCRSwitchOn){ + savePDF(ocrSwitchOn: true,completion: {(success) -> Void in + if success{ + if(isPDFWithoutOCRSwitchOn){ + savePDF(ocrSwitchOn: false, completion: {(success) -> Void in + if success{ + //Save Text File + if(isTextFileSwitchOn){ + saveTxtFile(completion: {(success) -> Void in + if success{ + //DELETE Files + showDeleteAlert() + NCActivityIndicator.shared.stop() + } + }) + }else{ + //DELETE files + showDeleteAlert() + NCActivityIndicator.shared.stop() + } + } + }) + }else{ + //Save Text File + if(isTextFileSwitchOn){ + saveTxtFile(completion: {(success) -> Void in + if success{ + //DELETE Files + showDeleteAlert() + NCActivityIndicator.shared.stop() + } + }) + }else{ + //DELETE files + showDeleteAlert() + NCActivityIndicator.shared.stop() + } + } + } + }) + }else { + if(isPDFWithoutOCRSwitchOn){ + savePDF(ocrSwitchOn: false, completion: {(success) -> Void in + if success{ + //Save Text File + if(isTextFileSwitchOn){ + saveTxtFile(completion: {(success) -> Void in + if success{ + //DELETE Files + showDeleteAlert() + NCActivityIndicator.shared.stop() + } + }) + }else{ + //DELETE files + showDeleteAlert() + NCActivityIndicator.shared.stop() + } + } + }) + }else{ + //Save Text File + if(isTextFileSwitchOn){ + saveTxtFile(completion: {(success) -> Void in + if success{ + //DELETE Files + showDeleteAlert() + NCActivityIndicator.shared.stop() + } + }) + }else{ + //DELETE files + showDeleteAlert() + NCActivityIndicator.shared.stop() + } + } + } + } + }) + } + }) + } + + + @objc func save() { + let password = (getPasswordFromField() ?? "").trimmingCharacters(in: .whitespaces) + self.password = password + + if(isSetpasswordEnable && password == ""){ + showAlert() + return + } + + if(!isAtleastOneFiletypeSelected()){ + + let alertController = UIAlertController(title: "", message: NSLocalizedString("_no_file_type_selection_error_", comment: ""), preferredStyle: .alert) + let alertWindow = UIWindow(frame: UIScreen.main.bounds) + alertWindow.windowLevel = UIWindow.Level.alert + alertWindow.rootViewController = UIViewController() + alertWindow.makeKeyAndVisible() + let actionOk = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default) { (action:UIAlertAction) in + alertController.dismiss(animated: true, completion: nil) + } + + alertController.addAction(actionOk) + self.present(alertController, animated: true) + }else { + // Request delete all image scanned + let alertController = UIAlertController(title: "", message: NSLocalizedString("_saved_info_alert_", comment: ""), preferredStyle: .alert) + let alertWindow = UIWindow(frame: UIScreen.main.bounds) + alertWindow.windowLevel = UIWindow.Level.alert + alertWindow.rootViewController = UIViewController() + alertWindow.makeKeyAndVisible() + let actionOk = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default) { (action:UIAlertAction) in + self.startProcessForSaving() + alertController.dismiss(animated: true, completion: nil) + } + + alertController.addAction(actionOk) + self.present(alertController, animated: true) + } + + } + + func showAlert(){ + // Request delete all image scanned + let alertController = UIAlertController(title: "", message: NSLocalizedString("_no_password_warn_", comment: ""), preferredStyle: .alert) + let alertWindow = UIWindow(frame: UIScreen.main.bounds) + alertWindow.windowLevel = UIWindow.Level.alert + alertWindow.rootViewController = UIViewController() + alertWindow.makeKeyAndVisible() + let actionOk = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default) { (action:UIAlertAction) in + alertController.dismiss(animated: true, completion: nil) + } + + alertController.addAction(actionOk) + //alertWindow.addSubview(alertController) + self.present(alertController, animated: true) + //alertWindow.rootViewController?.present(alertController, animated: true, completion: nil) + + } + + func showAlertForInfo(){ + // Request delete all image scanned + let alertController = UIAlertController(title: "", message: NSLocalizedString("_saved_info_alert_", comment: ""), preferredStyle: .alert) + let alertWindow = UIWindow(frame: UIScreen.main.bounds) + alertWindow.windowLevel = UIWindow.Level.alert + alertWindow.rootViewController = UIViewController() + alertWindow.makeKeyAndVisible() + let actionOk = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default) { (action:UIAlertAction) in + alertController.dismiss(animated: true, completion: nil) + } + + alertController.addAction(actionOk) + //alertWindow.addSubview(alertController) + self.present(alertController, animated: true) + } + func saveTxtFile(completion: (Bool) -> ()){ + + let rowFileName : XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! + guard var name = rowFileName.value else { + return + } + if name as? String == "" { + return + } + + for count in 0.. ()){ + + let rowFileName : XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! + guard var name = rowFileName.value else { + return + } + if name as? String == "" { + return + } + + if (ocrSwitchOn){ + name = name as? String + } + + let ext = (name as? NSString)?.pathExtension.uppercased() + var fileNameSave = "" + + if (ext == "") { + if (ocrSwitchOn){ + fileNameSave = (name as? String ?? "") + "_OCR" + "." + "pdf" + }else{ + fileNameSave = (name as? String ?? "") + "." + "pdf" + } + } else { + if(ocrSwitchOn){ + fileNameSave = ((name as? NSString)?.deletingPathExtension ?? "") + "_OCR" + "." + fileType.lowercased() + + }else{ + fileNameSave = ((name as? NSString)?.deletingPathExtension ?? "") + "." + fileType.lowercased() + } + } + + + 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: "") + +// 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: "") + let metadataForUpload = NCManageDatabase.shared.createMetadata(fileName: fileNameSave, fileNameView: fileNameSave, ocId: UUID().uuidString, serverUrl: serverUrl, url: "", contentType: "", session: session, sceneIdentifier: self.appDelegate?.sceneIdentifier) + + metadataForUpload.session = NCNetworking.shared.sessionUploadBackground + metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile + metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload + + NCActivityIndicator.shared.startActivity(backgroundView: self.view, style: .medium) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + self.isPDFWithOCRSwitchOn = ocrSwitchOn + self.dismissAndUpload(metadataForUpload, fileType: "PDF") + } + + completion(true) + } + + fileprivate func showDeleteAlert() { + + let path = utilityFileSystem.directoryScan + + do { + let filePaths = try FileManager.default.contentsOfDirectory(atPath: path) + for filePath in filePaths { + try FileManager.default.removeItem(atPath: path + "/" + filePath) + } + } catch let error as NSError { + print("Error: \(error.debugDescription)") + } + + self.dismiss(animated: true, completion: nil) + } + + func saveImages(fileNameSave: String, fileType: String, metadataConflict: tableMetadata?, completion: (Bool) -> ()) { + + if(!isJPGFormatSwitchOn && fileType == "jpg"){ + completion(true) + return + }else if(!isPNGFormatSwitchOn && fileType == "png"){ + completion(true) + return + } + else { + let rowFileName : XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! + guard var name = rowFileName.value else { + return + } + if name as? String == "" { + return + } + + for count in 0.. 0 { + NCActivityIndicator.shared.startActivity(backgroundView: self.view, style: .medium) + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + // if let metadata = metadatas![0] as? tableMetadata{ + if (metadatas![0].fileExtension == "jpg"){ + //TODO for jpg + self.dismissAndUpload(metadatas![0],fileType: "JPG") + NCActivityIndicator.shared.stop() + + }else if(metadatas![0].fileExtension == "png") { + //TODO for png + self.dismissAndUpload(metadatas![0],fileType: "PNG") + NCActivityIndicator.shared.stop() + + + }else if(metadatas![0].fileExtension == "pdf"){ + //TODO for pdf + self.isOCRActivatedFileConflicts = metadatas![0].fileName.contains("_OCR") + self.dismissAndUpload(metadatas![0],fileType: "PDF") + NCActivityIndicator.shared.stop() + + }else if(metadatas![0].fileExtension == "txt"){ + //TODO for txt + self.dismissAndUpload(metadatas![0],fileType: "TXT") + NCActivityIndicator.shared.stop() + + } + } + } + } + + func dismissAndUpload(_ metadata: tableMetadata, fileType: String?) { + + let fileNameGenerateExport = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView) + let fileUrl = URL(fileURLWithPath: fileNameGenerateExport) + + // Text Recognition TXT + // if fileType == "TXT" && self.form.formRow(withTag: "textRecognition")!.value as! Int == 1 { + if fileType == "TXT" { + + var textFile = "" + for image in self.arrayImages { + + let requestHandler = VNImageRequestHandler(cgImage: image.cgImage!, options: [:]) + + let request = VNRecognizeTextRequest { request, _ in + guard let observations = request.results as? [VNRecognizedTextObservation] else { + NCActivityIndicator.shared.stop() + return + } + for observation in observations { + 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: fileUrl, atomically: true, encoding: .utf8) + } catch { + NCActivityIndicator.shared.stop() + let error = NKError(errorCode: NCGlobal.shared.errorCreationFile, errorDescription: "_error_creation_file_") + contentPresenter.showError(error: error) + return + } + } + + if fileType == "PDF" { + + let pdfData = NSMutableData() + + if !password.isEmpty { + for char in password.unicodeScalars { + if !char.isASCII { + NCActivityIndicator.shared.stop() + let error = NKError(errorCode: NCGlobal.shared.errorForbidden, errorDescription: "_password_ascii_") + contentPresenter.showError(error: error) + return + } + } + let info: [AnyHashable: Any] = [kCGPDFContextUserPassword as String: password, kCGPDFContextOwnerPassword as String: password] + UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, info) + } else { + UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil) + } + var fontColor = UIColor.clear +#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) + + //self.form.formRow(withTag: "textRecognition")!.value as! Int == 1 + if isPDFWithOCRSwitchOn { + + UIGraphicsBeginPDFPageWithInfo(bounds, nil) + image.draw(in: bounds) + + let requestHandler = VNImageRequestHandler(cgImage: image.cgImage!, options: [:]) + + let request = VNRecognizeTextRequest { request, _ in + guard let observations = request.results as? [VNRecognizedTextObservation] else { + NCActivityIndicator.shared.stop() + return + } + for observation in observations { + 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) + let rect = observation.boundingBox.applying(t) + let text = textLine.string + + 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() + + do { + try pdfData.write(to: fileUrl, options: .atomic) + } catch { + print("error catched") + } + } + + if fileType == "JPG" { + + //let image = changeCompressionImage(self.arrayImages[0]) + + for image in self.arrayImages { + // let image = changeCompressionImage(self.arrayImages[0]) + guard let data = image.jpegData(compressionQuality: CGFloat(0.5)) else { + NCActivityIndicator.shared.stop() + contentPresenter.messageNotification("_error_", error: NKError(errorCode: NCGlobal.shared.errorCreationFile, errorDescription: "_error_creation_file_"), delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info) + contentPresenter.messageNotification("_error_", error: NKError(errorCode: NCGlobal.shared.errorCreationFile, errorDescription: NSLocalizedString("_error_creation_file_", comment: "")), delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info) + return + } + + do { + try data.write(to: fileUrl, options: .atomic) + } catch { + NCActivityIndicator.shared.stop() + contentPresenter.messageNotification("_error_", error: NKError(errorCode: NCGlobal.shared.errorCreationFile, errorDescription: "_error_creation_file_"), delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info) + contentPresenter.messageNotification("_error_", error: NKError(errorCode: NCGlobal.shared.errorCreationFile, errorDescription: NSLocalizedString("_error_creation_file_", comment: "")), delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info) + return + } + } + + + } + + if fileType == "PNG" { + + //let image = changeCompressionImage(self.arrayImages[0]) + + for image in self.arrayImages { + // let image = changeCompressionImage(self.arrayImages[0]) + guard let data = image.jpegData(compressionQuality: CGFloat(0.5)) else { + NCActivityIndicator.shared.stop() + contentPresenter.messageNotification("_error_", error: NKError(errorCode: NCGlobal.shared.errorCreationFile, errorDescription: "_error_creation_file_"), delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info) + contentPresenter.messageNotification("_error_", error: NKError(errorCode: NCGlobal.shared.errorCreationFile, errorDescription: NSLocalizedString("_error_creation_file_", comment: "")), delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info) + return + } + + do { + try data.write(to: NSURL.fileURL(withPath: fileNameGenerateExport), options: .atomic) + } catch { + NCActivityIndicator.shared.stop() + contentPresenter.messageNotification("_error_", error: NKError(errorCode: NCGlobal.shared.errorCreationFile, errorDescription: "_error_creation_file_"), delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info) + contentPresenter.messageNotification("_error_", error: NKError(errorCode: NCGlobal.shared.errorCreationFile, errorDescription: NSLocalizedString("_error_creation_file_", comment: "")), delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info) + return + } + } + } + + metadata.size = utilityFileSystem.getFileSize(filePath: fileNameGenerateExport) + + NCActivityIndicator.shared.stop() + + NCNetworkingProcess.shared.createProcessUploads(metadatas: [metadata], completion: { _ in }) + + // 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) { [self] (_: UIAlertAction) in + + let path = utilityFileSystem.directoryScan + + do { + let filePaths = try FileManager.default.contentsOfDirectory(atPath: path) + for filePath in filePaths { + try FileManager.default.removeItem(atPath: path + "/" + filePath) + } + } 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) { (_: UIAlertAction) in + self.dismiss(animated: true, completion: nil) + } + + alertController.addAction(actionYes) + alertController.addAction(actionNo) + self.present(alertController, animated: true, completion: nil) + } + + + @objc func cancel() { + + self.dismiss(animated: true, completion: nil) + } + + @objc func changeDestinationFolder(_ sender: XLFormRowDescriptor) { + + self.deselectFormRow(sender) + let storyboard = UIStoryboard(name: "NCSelect", bundle: nil) + if 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 + + switch quality { + case .low: + baseHeight *= 1 + baseWidth *= 1 + compressionQuality = 0.3 + case .medium: + baseHeight *= 2 + baseWidth *= 2 + compressionQuality = 0.6 + case .high: + baseHeight *= 4 + baseWidth *= 4 + compressionQuality = 0.9 + } + + var newHeight = Float(image.size.height) + var newWidth = Float(image.size.width) + var imgRatio: Float = newWidth / newHeight + let baseRatio: Float = baseWidth / baseHeight + + if newHeight > baseHeight || newWidth > baseWidth { + if imgRatio < baseRatio { + imgRatio = baseHeight / newHeight + newWidth = imgRatio * newWidth + newHeight = baseHeight + } else if imgRatio > baseRatio { + imgRatio = baseWidth / newWidth + newHeight = imgRatio * newHeight + newWidth = baseWidth + } 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) + let img = UIGraphicsGetImageFromCurrentImageContext() + let imageData = img?.jpegData(compressionQuality: CGFloat(compressionQuality)) + 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] + 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 size = text.size(withAttributes: attributesTmp).width + if size <= bounds.width { + attributes = attributesTmp + } else { + break + } + } + + return attributes + } + + func isAtleastOneFiletypeSelected() -> Bool{ + if(isPDFWithOCRSwitchOn + || isPDFWithoutOCRSwitchOn + || isTextFileSwitchOn + || isPNGFormatSwitchOn + || isJPGFormatSwitchOn){ + + return true + }else{ + return false + } + } + + func getPasswordFromField() -> String? { + if let setPasswordInputField : XLFormRowDescriptor = self.form.formRow(withTag: "SetPasswordInputField") { + var password = "" + if let indexPath = self.form.indexPath(ofFormRow: setPasswordInputField) { + let cell = tableView.cellForRow(at: indexPath) as? PasswordInputField + password = cell?.fileNameInputTextField.text ?? "" + } + return password + } + return nil + } +} + diff --git a/iOSClient/Scan document/NMC Views/FileNameInputTextField.swift b/iOSClient/Scan document/NMC Views/FileNameInputTextField.swift new file mode 100644 index 0000000000..e18ed84451 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/FileNameInputTextField.swift @@ -0,0 +1,67 @@ +// +// FileNameInputTextField.swift +// Nextcloud +// +// Created by Sumit on 03/06/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation +import XLForm + +class FileNameInputTextField: XLFormBaseCell,UITextFieldDelegate { + + @IBOutlet weak var fileNameInputTextField: UITextField! + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + + fileNameInputTextField.delegate = self + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + } + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + + if fileNameInputTextField == textField { + if let rowDescriptor = rowDescriptor, let text = self.fileNameInputTextField.text { + + if (text + " ").isEmpty == false { + rowDescriptor.value = self.fileNameInputTextField.text! + string + } else { + rowDescriptor.value = nil + } + } + } + + self.formViewController().textField(textField, shouldChangeCharactersIn: range, replacementString: string) + + return true + } + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + self.formViewController()?.textFieldShouldReturn(fileNameInputTextField) + return true + } + + func textFieldShouldClear(_ textField: UITextField) -> Bool { + self.formViewController()?.textFieldShouldClear(fileNameInputTextField) + return true + } + + override class func formDescriptorCellHeight(for rowDescriptor: XLFormRowDescriptor!) -> CGFloat { + return 45 + } +} diff --git a/iOSClient/Scan document/NMC Views/FileNameInputTextField.xib b/iOSClient/Scan document/NMC Views/FileNameInputTextField.xib new file mode 100644 index 0000000000..173862a3ae --- /dev/null +++ b/iOSClient/Scan document/NMC Views/FileNameInputTextField.xib @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Scan document/NMC Views/JPGImageSaveSwitchView.swift b/iOSClient/Scan document/NMC Views/JPGImageSaveSwitchView.swift new file mode 100644 index 0000000000..ba1ddd8537 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/JPGImageSaveSwitchView.swift @@ -0,0 +1,44 @@ +// +// JPGmageSaveSwitchView.swift +// Nextcloud +// +// Created by Sumit on 04/06/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation + +import XLForm + +class JPGImageSaveSwitchView: XLFormBaseCell{ + @IBOutlet weak var cellLabel: UILabel! + @IBOutlet weak var switchControl: UISwitch! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + self.selectionStyle = .none + switchControl.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged) + + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + } + + @objc func switchChanged(mySwitch: UISwitch) { + let value = mySwitch.isOn + // Do something + + if value { + //on + self.rowDescriptor.value = value + }else{ + self.rowDescriptor.value = value + } + } +} diff --git a/iOSClient/Scan document/NMC Views/JPGImageSaveSwitchView.xib b/iOSClient/Scan document/NMC Views/JPGImageSaveSwitchView.xib new file mode 100644 index 0000000000..8658100453 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/JPGImageSaveSwitchView.xib @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Scan document/NMC Views/PNGImageSaveSwitchView.swift b/iOSClient/Scan document/NMC Views/PNGImageSaveSwitchView.swift new file mode 100644 index 0000000000..3c90b4d943 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/PNGImageSaveSwitchView.swift @@ -0,0 +1,44 @@ +// +// PNGImageSaveSwitchView.swift +// Nextcloud +// +// Created by Sumit on 09/06/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation + +import XLForm + +class PNGImageSaveSwitchView: XLFormBaseCell{ + @IBOutlet weak var cellLabel: UILabel! + @IBOutlet weak var switchControl: UISwitch! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + self.selectionStyle = .none + switchControl.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged) + + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + } + + @objc func switchChanged(mySwitch: UISwitch) { + let value = mySwitch.isOn + // Do something + + if value { + //on + self.rowDescriptor.value = value + }else{ + self.rowDescriptor.value = value + } + } +} diff --git a/iOSClient/Scan document/NMC Views/PNGImageSaveSwitchView.xib b/iOSClient/Scan document/NMC Views/PNGImageSaveSwitchView.xib new file mode 100644 index 0000000000..d3c7312316 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/PNGImageSaveSwitchView.xib @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Scan document/NMC Views/PasswordInputField.swift b/iOSClient/Scan document/NMC Views/PasswordInputField.swift new file mode 100644 index 0000000000..43117f09f3 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/PasswordInputField.swift @@ -0,0 +1,73 @@ +// +// PasswordInputField.swift +// Nextcloud +// +// Created by Sumit on 10/06/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation +import XLForm + +class PasswordInputField: XLFormBaseCell,UITextFieldDelegate { + + @IBOutlet weak var fileNameInputTextField: UITextField! + @IBOutlet weak var separatorBottom: UIView! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + fileNameInputTextField.isSecureTextEntry = true + fileNameInputTextField.delegate = self + separatorBottom.backgroundColor = NCBrandColor.shared.systemGray4 + self.selectionStyle = .none + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + + override func configure() { + super.configure() + // fileNameInputTextField.isEnabled = false + + } + + override func update() { + super.update() + } + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + + if fileNameInputTextField == textField { + if let rowDescriptor = rowDescriptor, let text = self.fileNameInputTextField.text { + + if (text + " ").isEmpty == false { + rowDescriptor.value = self.fileNameInputTextField.text! + string + } else { + rowDescriptor.value = nil + } + } + } + + self.formViewController().textField(textField, shouldChangeCharactersIn: range, replacementString: string) + + return true + } + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + self.formViewController()?.textFieldShouldReturn(fileNameInputTextField) + return true + } + + func textFieldShouldClear(_ textField: UITextField) -> Bool { + self.formViewController()?.textFieldShouldClear(fileNameInputTextField) + return true + } + + override class func formDescriptorCellHeight(for rowDescriptor: XLFormRowDescriptor!) -> CGFloat { + return 45 + } +} diff --git a/iOSClient/Scan document/NMC Views/PasswordInputField.xib b/iOSClient/Scan document/NMC Views/PasswordInputField.xib new file mode 100644 index 0000000000..26914e0760 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/PasswordInputField.xib @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Scan document/NMC Views/PdfWithOcrSwitchView.swift b/iOSClient/Scan document/NMC Views/PdfWithOcrSwitchView.swift new file mode 100644 index 0000000000..5b0e76ddcc --- /dev/null +++ b/iOSClient/Scan document/NMC Views/PdfWithOcrSwitchView.swift @@ -0,0 +1,43 @@ +// +// PdfWithOcrSwitchView.swift +// Nextcloud +// +// Created by Sumit on 04/06/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation +import XLForm + +class PdfWithOcrSwitchView: XLFormBaseCell{ + @IBOutlet weak var cellLabel: UILabel! + @IBOutlet weak var switchControl: UISwitch! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + self.selectionStyle = .none + switchControl.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged) + + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + } + + @objc func switchChanged(mySwitch: UISwitch) { + let value = mySwitch.isOn + // Do something + + if value { + //on + self.rowDescriptor.value = value + }else{ + self.rowDescriptor.value = value + } + } +} diff --git a/iOSClient/Scan document/NMC Views/PdfWithOcrSwitchView.xib b/iOSClient/Scan document/NMC Views/PdfWithOcrSwitchView.xib new file mode 100644 index 0000000000..06cdcae9b6 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/PdfWithOcrSwitchView.xib @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Scan document/NMC Views/PdfWithoutOcrSwitchView.swift b/iOSClient/Scan document/NMC Views/PdfWithoutOcrSwitchView.swift new file mode 100644 index 0000000000..7f0130f7c4 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/PdfWithoutOcrSwitchView.swift @@ -0,0 +1,44 @@ +// +// PdfWithoutOcrSwitchView.swift +// Nextcloud +// +// Created by Sumit on 04/06/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation + +import XLForm + +class PdfWithoutOcrSwitchView: XLFormBaseCell{ + @IBOutlet weak var cellLabel: UILabel! + @IBOutlet weak var switchControl: UISwitch! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + self.selectionStyle = .none + switchControl.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged) + + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + } + + @objc func switchChanged(mySwitch: UISwitch) { + let value = mySwitch.isOn + // Do something + + if value { + //on + self.rowDescriptor.value = value + }else{ + self.rowDescriptor.value = value + } + } +} diff --git a/iOSClient/Scan document/NMC Views/PdfWithoutOcrSwitchView.xib b/iOSClient/Scan document/NMC Views/PdfWithoutOcrSwitchView.xib new file mode 100644 index 0000000000..46ebf565f7 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/PdfWithoutOcrSwitchView.xib @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Scan document/NMC Views/ScanDocumentPathView.swift b/iOSClient/Scan document/NMC Views/ScanDocumentPathView.swift new file mode 100644 index 0000000000..666e4805fd --- /dev/null +++ b/iOSClient/Scan document/NMC Views/ScanDocumentPathView.swift @@ -0,0 +1,34 @@ +// +// ScanDocumentPathView.swift +// Nextcloud +// +// Created by Sumit on 03/06/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation +import XLForm + +class ScanDocumentPathView: XLFormButtonCell{ + + @IBOutlet weak var photoLabel: UILabel! + @IBOutlet weak var folderImage: UIImageView! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + + + } + + override func configure() { + super.configure() + + + } + + override func update() { + super.update() + } + +} diff --git a/iOSClient/Scan document/NMC Views/ScanDocumentPathView.xib b/iOSClient/Scan document/NMC Views/ScanDocumentPathView.xib new file mode 100644 index 0000000000..fa30321541 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/ScanDocumentPathView.xib @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Scan document/NMC Views/SetPDFPasswordSwitchView.swift b/iOSClient/Scan document/NMC Views/SetPDFPasswordSwitchView.swift new file mode 100644 index 0000000000..6090b4e787 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/SetPDFPasswordSwitchView.swift @@ -0,0 +1,53 @@ +// +// SetPDFPasswordSwitchView.swift +// Nextcloud +// +// Created by Sumit on 10/06/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation +import XLForm + +class SetPDFPasswordSwitchView: XLFormBaseCell{ + @IBOutlet weak var cellLabel: UILabel! + @IBOutlet weak var switchControl: UISwitch! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + self.selectionStyle = .none + switchControl.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged) + + } + + override func configure() { + super.configure() + self.switchControl.isEnabled = false + } + + override func update() { + super.update() + + if let rowValue = rowDescriptor.value as? String { + if (rowValue == "disable_switch"){ + self.switchControl.isEnabled = false + self.switchControl.isOn = false + }else if(rowValue == "enable_switch"){ + self.switchControl.isEnabled = true + } + } + } + + @objc func switchChanged(mySwitch: UISwitch) { + let value = mySwitch.isOn + // Do something + + if value { + //on + self.rowDescriptor.value = value + }else{ + self.rowDescriptor.value = value + } + } +} diff --git a/iOSClient/Scan document/NMC Views/SetPDFPasswordSwitchView.xib b/iOSClient/Scan document/NMC Views/SetPDFPasswordSwitchView.xib new file mode 100644 index 0000000000..e0ddc1ca1a --- /dev/null +++ b/iOSClient/Scan document/NMC Views/SetPDFPasswordSwitchView.xib @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Scan document/NMC Views/TextFileWithOcrSwitchView.swift b/iOSClient/Scan document/NMC Views/TextFileWithOcrSwitchView.swift new file mode 100644 index 0000000000..9ecac2bf75 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/TextFileWithOcrSwitchView.swift @@ -0,0 +1,41 @@ +// +// TextFileWithOcrSwitchView.swift +// Nextcloud +// +// Created by Sumit on 04/06/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation +import XLForm + +class TextFileWithOcrSwitchView: XLFormBaseCell{ + @IBOutlet weak var switchControl: UISwitch! + @IBOutlet weak var cellLabel: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + self.selectionStyle = .none + switchControl.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged) + } + + override func configure() { + super.configure() + + } + + override func update() { + super.update() + } + + @objc func switchChanged(mySwitch: UISwitch) { + let value = mySwitch.isOn + if value { + //on + self.rowDescriptor.value = value + }else{ + self.rowDescriptor.value = value + } + } + +} diff --git a/iOSClient/Scan document/NMC Views/TextFileWithOcrSwitchView.xib b/iOSClient/Scan document/NMC Views/TextFileWithOcrSwitchView.xib new file mode 100644 index 0000000000..5f0ff73601 --- /dev/null +++ b/iOSClient/Scan document/NMC Views/TextFileWithOcrSwitchView.xib @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Settings/AnalysisDataCollectionSwitch.swift b/iOSClient/Settings/AnalysisDataCollectionSwitch.swift new file mode 100644 index 0000000000..58f2d55d8d --- /dev/null +++ b/iOSClient/Settings/AnalysisDataCollectionSwitch.swift @@ -0,0 +1,35 @@ +// +// AnalysisDataCollectionSwitch.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import UIKit +import XLForm + +class AnalysisDataCollectionSwitch: XLFormBaseCell { + + @IBOutlet weak var cellLabel: UILabel! + @IBOutlet weak var analysisDataCollectionSwitchControl: UISwitch! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + analysisDataCollectionSwitchControl.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged) + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + } + + @objc func switchChanged(mySwitch: UISwitch) { + self.rowDescriptor.value = mySwitch.isOn + } +} + diff --git a/iOSClient/Settings/AnalysisDataCollectionSwitch.xib b/iOSClient/Settings/AnalysisDataCollectionSwitch.xib new file mode 100644 index 0000000000..45530193f6 --- /dev/null +++ b/iOSClient/Settings/AnalysisDataCollectionSwitch.xib @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Settings/CCAdvanced.h b/iOSClient/Settings/CCAdvanced.h new file mode 100755 index 0000000000..7f9845888f --- /dev/null +++ b/iOSClient/Settings/CCAdvanced.h @@ -0,0 +1,29 @@ +// +// CCAdvanced.h +// Nextcloud +// +// Created by Marino Faggiana on 12/04/17. +// Copyright (c) 2017 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +#import +#import + +@interface CCAdvanced : XLFormViewController + +@end diff --git a/iOSClient/Settings/CCAdvanced.m b/iOSClient/Settings/CCAdvanced.m new file mode 100755 index 0000000000..3c7477e5a3 --- /dev/null +++ b/iOSClient/Settings/CCAdvanced.m @@ -0,0 +1,635 @@ +// +// CCManageHelp.m +// Nextcloud +// +// Created by Marino Faggiana on 06/11/15. +// Copyright (c) 2015 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +#import "CCAdvanced.h" +#import "CCUtility.h" +#import "NCBridgeSwift.h" +#import "AdjustHelper.h" +//#import + +@interface CCAdvanced () +{ + AppDelegate *appDelegate; + XLFormSectionDescriptor *sectionSize; + TealiumHelper *tealium; + AdjustHelper *adjust; +} +@end + +@implementation CCAdvanced + +- (void)initializeForm +{ + XLFormDescriptor *form = [XLFormDescriptor formDescriptor]; + XLFormSectionDescriptor *section; + XLFormRowDescriptor *row; + + // Section HIDDEN FILES ------------------------------------------------- + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"showHiddenFiles" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_show_hidden_files_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + if ([[[NCKeychain alloc] init] showHiddenFiles]) row.value = @"1"; + else row.value = @"0"; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + [section addFormRow:row]; + + // Format Compatibility + Live Photo + Delete asset + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + section.footerTitle = [NSString stringWithFormat:@"%@\n%@\n%@", NSLocalizedString(@"_format_compatibility_footer_", nil), NSLocalizedString(@"_upload_mov_livephoto_footer_", nil), NSLocalizedString(@"_remove_photo_CameraRoll_desc_", nil)]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"formatCompatibility" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_format_compatibility_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + if ([[[NCKeychain alloc] init] formatCompatibility]) row.value = @"1"; + else row.value = @"0"; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"livePhoto" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_upload_mov_livephoto_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + if ([[[NCKeychain alloc] init] livePhoto]) row.value = @"1"; + else row.value = @"0"; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"removePhotoCameraRoll" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_remove_photo_CameraRoll_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + if ([[[NCKeychain alloc] init] removePhotoCameraRoll]) row.value = @"1"; + else row.value = @0; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [section addFormRow:row]; + + // Section : Files App -------------------------------------------------------------- + + if (![NCBrandOptions shared].disable_openin_file) { + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + section.footerTitle = NSLocalizedString(@"_disable_files_app_footer_", nil); + + // Disable Files App + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"disablefilesapp" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_disable_files_app_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + if ([[NCKeychain alloc] init].disableFilesApp) row.value = @"1"; + else row.value = @"0"; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + [section addFormRow:row]; + } + + // Section : Privacy -------------------------------------------------------------- + + if (!NCBrandOptions.shared.disable_crash_service) { + + section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_privacy_", nil)]; + [form addFormSection:section]; + section.footerTitle = NSLocalizedString(@"_privacy_footer_", nil); + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"crashservice" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_crashservice_title_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"crashservice"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + if ([[[NCKeychain alloc] init] disableCrashservice]) row.value = @"1"; + else row.value = @"0"; + [section addFormRow:row]; + } + +#ifdef DEBUG +//#ifdef DEBUG + // Section DIAGNOSTICS ------------------------------------------------- + + section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_diagnostics_", nil)]; + [form addFormSection:section]; + +// if ([[NSFileManager defaultManager] fileExistsAtPath:NextcloudKit.shared.nkCommonInstance.filenamePathLog] && NCBrandOptions.shared.disable_log == false) { + if ([[NSFileManager defaultManager] fileExistsAtPath:@""] && NCBrandOptions.shared.disable_log == false) { + if ([[NSFileManager defaultManager] fileExistsAtPath:NextcloudKit.shared.nkCommonInstance.filenamePathLog] && NCBrandOptions.shared.disable_log == false) { + + if ([[NSFileManager defaultManager] fileExistsAtPath:NextcloudKit.shared.nkCommonInstance.filenamePathLog] && NCBrandOptions.shared.disable_log == false) { + // with Nextcloudkit latest version will uncomment below line once updated to latest Nextcloudkit version +// if ([[NSFileManager defaultManager] fileExistsAtPath:NKLogFileManager.shared.logDirectory.path] && NCBrandOptions.shared.disable_log == false) { +// if (NCBrandOptions.shared.disable_log) { + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"log" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_view_log_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"log"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + row.action.formBlock = ^(XLFormRowDescriptor * sender) { + + [self deselectFormRow:sender]; +// NCViewerQuickLook *viewerQuickLook = [[NCViewerQuickLook alloc] initWith:[NSURL fileURLWithPath:NextcloudKit.shared.nkCommonInstance.filenamePathLog] fileNameSource:@"" isEditingEnabled:false metadata:nil]; + NCViewerQuickLook *viewerQuickLook = [[NCViewerQuickLook alloc] initWith:[NSURL fileURLWithPath:@""] fileNameSource:@"" isEditingEnabled:false metadata:nil]; + NCViewerQuickLook *viewerQuickLook = [[NCViewerQuickLook alloc] initWith:[NSURL fileURLWithPath:NextcloudKit.shared.nkCommonInstance.filenamePathLog] isEditingEnabled:false metadata:nil]; + +// NSURL *logFilePath = [self getLogFilePath]; +// if (logFilePath) { +// // Use the log file path (e.g., to write logs) +// NSLog(@"Log file path: %@", logFilePath.path); +// NCViewerQuickLook *viewerQuickLook = [[NCViewerQuickLook alloc] initWith:logFilePath fileNameSource:@"" isEditingEnabled:false metadata:nil]; +// [self presentViewController:viewerQuickLook animated:YES completion:nil]; +// } else { +// // Handle error (logs folder could not be created) +// NSLog(@"Failed to get log file path."); +// } + + NCViewerQuickLook *viewerQuickLook = [[NCViewerQuickLook alloc] initWith:[NSURL fileURLWithPath:NextcloudKit.shared.nkCommonInstance.filenamePathLog] fileNameSource:@"" isEditingEnabled:false metadata:nil]; + // with Nextcloudkit latest version will uncomment below line once updated to latest Nextcloudkit version +// NCViewerQuickLook *viewerQuickLook = [[NCViewerQuickLook alloc] initWith:[NSURL fileURLWithPath:NKLogFileManager.shared.logDirectory.path] fileNameSource:NKLogFileManager.shared.logFileName isEditingEnabled:false metadata:nil]; +// NCViewerQuickLook *viewerQuickLook = [[NCViewerQuickLook alloc] initWith:[NSURL fileURLWithPath:@""] fileNameSource:@"" isEditingEnabled:false metadata:nil]; + [self presentViewController:viewerQuickLook animated:YES completion:nil]; + }; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"logLevel" rowType:XLFormRowDescriptorTypeSelectorPush title:NSLocalizedString(@"_set_log_level_", nil)]; + NSInteger logLevel = [[NCKeychain alloc] init].logLevel; + row.value = @(logLevel); + switch ([[NCKeychain alloc] init].logLevel) { + case 0: + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:NSLocalizedString(@"_disabled_", nil)]; + break; + case 1: + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:NSLocalizedString(@"_standard_", nil)]; + break; + case 2: + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:NSLocalizedString(@"_maximum_", nil)]; + break; + default: + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:NSLocalizedString(@"_standard_", nil)]; + break; + } + + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.cellConfigForSelector[@"tintColor"] = NCBrandColor.shared.customer; + row.selectorTitle = NSLocalizedString(@"_set_log_level_", nil); + row.selectorOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:NSLocalizedString(@"_disabled_", nil)], + [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:NSLocalizedString(@"_standard_", nil)], + [XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:NSLocalizedString(@"_maximum_", nil)], + ]; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"clearlog" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_clear_log_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"clear"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + row.action.formBlock = ^(XLFormRowDescriptor * sender) { + + [self deselectFormRow:sender]; + +// [[[NextcloudKit shared] nkCommonInstance] clearFileLog]; + [[[NextcloudKit shared] nkCommonInstance] clearFileLog]; + [[[NextcloudKit shared] nkCommonInstance] clearFileLog]; + // with Nextcloudkit latest version will uncomment below line once updated to latest Nextcloudkit version +// [[NKLogFileManager shared] clearLogFiles]; +// [self createLogFiles]; + + NSInteger logLevel = [[NCKeychain alloc] init].logLevel; + BOOL isSimulatorOrTestFlight = [[[NCUtility alloc] init] isSimulatorOrTestFlight]; + NSString *versionNextcloudiOS = [NSString stringWithFormat:[NCBrandOptions shared].textCopyrightNextcloudiOS, [[[NCUtility alloc] init] getVersionAppWithBuild:true]]; +// if (isSimulatorOrTestFlight) { +// [[[NextcloudKit shared] nkCommonInstance] writeLog:[NSString stringWithFormat:@"[INFO] Clear log with level %lu %@ (Simulator / TestFlight)", (unsigned long)logLevel, versionNextcloudiOS]]; +// } else { +// [[[NextcloudKit shared] nkCommonInstance] writeLog:[NSString stringWithFormat:@"[INFO] Clear log with level %lu %@", (unsigned long)logLevel, versionNextcloudiOS]]; +// } + if (isSimulatorOrTestFlight) { + [[[NextcloudKit shared] nkCommonInstance] writeLog:[NSString stringWithFormat:@"[INFO] Clear log with level %lu %@ (Simulator / TestFlight)", (unsigned long)logLevel, versionNextcloudiOS]]; + } else { + [[[NextcloudKit shared] nkCommonInstance] writeLog:[NSString stringWithFormat:@"[INFO] Clear log with level %lu %@", (unsigned long)logLevel, versionNextcloudiOS]]; + } + }; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"logLevel" rowType:XLFormRowDescriptorTypeSlider title:NSLocalizedString(@"_level_log_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:@(NSTextAlignmentCenter) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + NSInteger logLevel = [[NCKeychain alloc] init].logLevel; + row.value = @(logLevel); + [row.cellConfigAtConfigure setObject:@(2) forKey:@"slider.maximumValue"]; + [row.cellConfigAtConfigure setObject:@(0) forKey:@"slider.minimumValue"]; + [row.cellConfigAtConfigure setObject:@(2) forKey:@"steps"]; + [section addFormRow:row]; + } + + // with Nextcloudkit latest version will uncomment below line once updated to latest Nextcloudkit version +// if (isSimulatorOrTestFlight) { +// [[NKLogFileManager shared] writeLogWithInfo:[NSString stringWithFormat:@"[INFO] Clear log with level %lu %@ (Simulator / TestFlight)", (unsigned long)logLevel, versionNextcloudiOS]]; +// } else { +// [[NKLogFileManager shared] writeLogWithInfo:[NSString stringWithFormat:@"[INFO] Clear log with level %lu %@", (unsigned long)logLevel, versionNextcloudiOS]]; +// } + }; + [section addFormRow:row]; + + } + +#ifdef DEBUG + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"capabilities" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_capabilities_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"capabilities"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + row.action.formBlock = ^(XLFormRowDescriptor * sender) { + + [self deselectFormRow:sender]; + + UIViewController *vc = [[NCHostingCapabilitiesView alloc] makeShipDetailsUI]; + [self.navigationController pushViewController:vc animated:YES]; + }; + [section addFormRow:row]; +#endif + + // Section : Delete files / Clear cache -------------------------------------------------------------- + + sectionSize = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_delete_files_desc_", nil)]; + [form addFormSection:sectionSize]; + sectionSize.footerTitle = NSLocalizedString(@"_clear_cache_footer_", nil); + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"deleteoldfiles" rowType:XLFormRowDescriptorTypeSelectorPush title:NSLocalizedString(@"_delete_old_files_", nil)]; + + switch ([[NCKeychain alloc] init].cleanUpDay) { + case 0: + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:NSLocalizedString(@"_never_", nil)]; + break; + case 365: + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(365) displayText:NSLocalizedString(@"_1_year_", nil)]; + break; + case 180: + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(180) displayText:NSLocalizedString(@"_6_months_", nil)]; + break; + case 90: + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(90) displayText:NSLocalizedString(@"_3_months_", nil)]; + break; + case 30: + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(30) displayText:NSLocalizedString(@"_1_month_", nil)]; + break; + case 7: + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(7) displayText:NSLocalizedString(@"_1_week_", nil)]; + break; + case 1: + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:NSLocalizedString(@"_1_day_", nil)]; + break; + default: + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:NSLocalizedString(@"_never_", nil)]; + break; + } + + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.cellConfigForSelector[@"tintColor"] = NCBrandColor.shared.customer; + row.selectorTitle = NSLocalizedString(@"_delete_old_files_", nil); + row.selectorOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:NSLocalizedString(@"_never_", nil)], + [XLFormOptionsObject formOptionsObjectWithValue:@(365) displayText:NSLocalizedString(@"_1_year_", nil)], + [XLFormOptionsObject formOptionsObjectWithValue:@(180) displayText:NSLocalizedString(@"_6_months_", nil)], + [XLFormOptionsObject formOptionsObjectWithValue:@(90) displayText:NSLocalizedString(@"_3_months_", nil)], + [XLFormOptionsObject formOptionsObjectWithValue:@(30) displayText:NSLocalizedString(@"_1_month_", nil)], + [XLFormOptionsObject formOptionsObjectWithValue:@(7) displayText:NSLocalizedString(@"_1_week_", nil)], + ]; + [sectionSize addFormRow:row]; + + // Clear cache + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"azzeracache" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_clear_cache_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"trashIcon"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + row.action.formSelector = @selector(clearCacheRequest:); + [sectionSize addFormRow:row]; + + // Section EXIT -------------------------------------------------------- + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + section.footerTitle = NSLocalizedString(@"_exit_footer_", nil); + + // Exit + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"esci" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_exit_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:[UIColor redColor] forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"xmark"] imageWithColor:[UIColor redColor] size:25] forKey:@"imageView.image"]; + row.action.formSelector = @selector(exitNextcloud:); + [section addFormRow:row]; + + self.tableView.showsVerticalScrollIndicator = NO; + self.form = form; +} + +// MARK: - View Life Cycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.title = NSLocalizedString(@"_advanced_", nil); + appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; + self.view.backgroundColor = UIColor.systemGroupedBackgroundColor; + + adjust = [[AdjustHelper alloc] init]; + self.tableView.backgroundColor = UIColor.systemGroupedBackgroundColor; + + [self initializeForm]; + [self calculateSize]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + appDelegate.activeViewController = self; +} + +#pragma mark - + +- (void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)rowDescriptor oldValue:(id)oldValue newValue:(id)newValue +{ + [super formRowDescriptorValueHasChanged:rowDescriptor oldValue:oldValue newValue:newValue]; + + if ([rowDescriptor.tag isEqualToString:@"showHiddenFiles"]) { + + [[NCKeychain alloc] init].showHiddenFiles = [[rowDescriptor.value valueData] boolValue]; + } + + if ([rowDescriptor.tag isEqualToString:@"formatCompatibility"]) { + + [[NCKeychain alloc] init].formatCompatibility = [[rowDescriptor.value valueData] boolValue]; + } + + if ([rowDescriptor.tag isEqualToString:@"livePhoto"]) { + + [[NCKeychain alloc] init].livePhoto = [[rowDescriptor.value valueData] boolValue]; + } + + if ([rowDescriptor.tag isEqualToString:@"removePhotoCameraRoll"]) { + + [[NCKeychain alloc] init].removePhotoCameraRoll = [[rowDescriptor.value valueData] boolValue]; + } + + if ([rowDescriptor.tag isEqualToString:@"disablefilesapp"]) { + + [[NCKeychain alloc] init].disableFilesApp = [[rowDescriptor.value valueData] boolValue]; + } + + if ([rowDescriptor.tag isEqualToString:@"crashservice"]) { + + [[NCKeychain alloc] init].disableCrashservice = [[rowDescriptor.value valueData] boolValue]; + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_crashservice_title_", nil) message:NSLocalizedString(@"_crashservice_alert_", nil) preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"_ok_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + exit(0); + }]; + + [alertController addAction:okAction]; + [self presentViewController:alertController animated:YES completion:nil]; + } + + if ([rowDescriptor.tag isEqualToString:@"logLevel"]) { + + NSInteger levelLog = [[rowDescriptor.value valueData] intValue]; + [[NCKeychain alloc] init].logLevel = levelLog; +// [[[NextcloudKit shared] nkCommonInstance] setLevelLog:levelLog]; + [[[NextcloudKit shared] nkCommonInstance] setLevelLog:levelLog]; + } + + if ([rowDescriptor.tag isEqualToString:@"deleteoldfiles"]) { + + NSInteger days = [[rowDescriptor.value valueData] intValue]; + [[NCKeychain alloc] init].cleanUpDay = days; + } +} + +#pragma mark - Log files + +- (NSURL *)getLogFilePath { + // Define the log file name + NSString *logFileName = @"log.txt"; + + // Get the documents directory URL + NSArray *documentURLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; + NSURL *documentsDirectory = [documentURLs firstObject]; + + // Define the logs folder URL + NSURL *logsFolder = [documentsDirectory URLByAppendingPathComponent:@"Logs" isDirectory:YES]; + + // Check if the "Logs" folder exists + if (![[NSFileManager defaultManager] fileExistsAtPath:logsFolder.path]) { + NSError *error = nil; + // Create the "Logs" folder if it doesn't exist + BOOL success = [[NSFileManager defaultManager] createDirectoryAtURL:logsFolder withIntermediateDirectories:YES attributes:nil error:&error]; + if (!success) { + NSLog(@"Failed to create Logs folder: %@", error.localizedDescription); + return nil; // Return nil in case of error + } + } + + // Create the full log file path + NSURL *logPath = [logsFolder URLByAppendingPathComponent:logFileName]; + + // Return the log file path + return logPath; +} + +// Method to create log files +- (void)createLogFiles { + + // Property to control whether to copy log to the Documents directory + BOOL copyLogToDocumentDirectory; + + copyLogToDocumentDirectory = (!NCBrandOptions.shared.disable_log) ? YES : NO; + + // Define log file paths + NSString *filenamePathLog = @"/log.txt"; // Set your desired path for the log file + NSString *filenameLog = @"log.txt"; // This will be the filename to copy + + // Create the log file at the given path + BOOL success = [[NSFileManager defaultManager] createFileAtPath:filenamePathLog contents:nil attributes:nil]; + if (!success) { + NSLog(@"Failed to create file at path: %@", filenamePathLog); + } + + // If we want to copy the log file to the Documents directory + if (copyLogToDocumentDirectory) { // Check the property value + NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentDirectory = [documentPaths firstObject]; + + // Create the path to copy the log file in Documents directory + NSString *filenameCopyToDocumentDirectory = [documentDirectory stringByAppendingPathComponent:filenameLog]; + + // Create the log file at the new path in the Documents directory + success = [[NSFileManager defaultManager] createFileAtPath:filenameCopyToDocumentDirectory contents:nil attributes:nil]; + if (!success) { + NSLog(@"Failed to create file at Documents path: %@", filenameCopyToDocumentDirectory); + } + } +} + + +#pragma mark - Clear Cache + +- (void)clearCache:(NSString *)account +{ + [[NCNetworking shared] cancelAllTask]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) { + + NCUtilityFileSystem *ufs = [[NCUtilityFileSystem alloc] init]; + + [[NSURLCache sharedURLCache] setMemoryCapacity:0]; + [[NSURLCache sharedURLCache] setDiskCapacity:0]; + + [[NCManageDatabase shared] clearDatabaseWithAccount:account removeAccount:false]; + [[NCManageDatabase shared] clearDatabaseWithAccount:account removeAccount:false removeAutoUpload:false]; +// [[NCManageDatabase shared] clearDatabaseWithAccount:account removeAccount:false]; + + [ufs removeGroupDirectoryProviderStorage]; + [ufs removeGroupLibraryDirectory]; + + [ufs removeDocumentsDirectory]; + [ufs removeTemporaryDirectory]; + + [ufs createDirectoryStandard]; + + [[NCAutoUpload shared] alignPhotoLibraryWithController:self account:appDelegate.account]; + [[NCAutoUpload shared] alignPhotoLibraryWithViewController:self]; +// [[NCAutoUpload shared] alignPhotoLibraryWithViewController:self]; + + [[NCImageCache shared] createMediaCacheWithAccount:appDelegate.account withCacheSize:true]; + + [[NCActivityIndicator shared] stop]; + tealium = [[TealiumHelper alloc] init]; + [tealium trackEventWithTitle:@"magentacloud-app.settings.reset" data:nil]; + [adjust trackEvent:ResetsApp]; + [self calculateSize]; + }); +} + +- (void)clearCacheRequest:(XLFormRowDescriptor *)sender +{ + [self deselectFormRow:sender]; + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:NSLocalizedString(@"_want_delete_cache_", nil) preferredStyle:UIAlertControllerStyleActionSheet]; + + [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_yes_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + [[NCActivityIndicator shared] startActivityWithBackgroundView:nil style: UIActivityIndicatorViewStyleLarge blurEffect:true]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) { + [self clearCache:appDelegate.account]; + }); + }]]; + + [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_cancel_", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { + }]]; + + alertController.popoverPresentationController.sourceView = self.view; + NSIndexPath *indexPath = [self.form indexPathOfFormRow:sender]; + CGRect cellRect = [self.tableView rectForRowAtIndexPath:indexPath]; + alertController.popoverPresentationController.sourceRect = CGRectOffset(cellRect, -self.tableView.contentOffset.x, -self.tableView.contentOffset.y); + + [self presentViewController:alertController animated:YES completion:nil]; +} + + +- (void)clearAllCacheRequest:(XLFormRowDescriptor *)sender +{ + [self deselectFormRow:sender]; + + [[NCActivityIndicator shared] startActivityWithBackgroundView:nil style: UIActivityIndicatorViewStyleLarge blurEffect:true]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) { + [self clearCache:nil]; + }); +} + +- (void)calculateSize +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NCUtilityFileSystem *ufs = [[NCUtilityFileSystem alloc] init]; + NSString *directory = [ufs directoryProviderStorage]; + int64_t totalSize = [ufs getDirectorySizeWithDirectory:directory]; + sectionSize.footerTitle = [NSString stringWithFormat:@"%@. (%@ %@)", NSLocalizedString(@"_clear_cache_footer_", nil), NSLocalizedString(@"_used_space_", nil), [ufs transformedSize:totalSize]]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.tableView reloadData]; + }); + }); +} + +#pragma mark - Exit Nextcloud + +- (void)exitNextcloud:(XLFormRowDescriptor *)sender +{ + [self deselectFormRow:sender]; + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:NSLocalizedString(@"_want_exit_", nil) preferredStyle:UIAlertControllerStyleActionSheet]; + + [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_ok_", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { + tealium = [[TealiumHelper alloc] init]; + [tealium trackEventWithTitle:@"magentacloud-app.settings.logout" data:nil]; + [adjust trackEvent:Logout]; + [appDelegate resetApplication]; + }]]; + + [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_cancel_", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { + }]]; + + alertController.popoverPresentationController.sourceView = self.view; + NSIndexPath *indexPath = [self.form indexPathOfFormRow:sender]; + CGRect cellRect = [self.tableView rectForRowAtIndexPath:indexPath]; + alertController.popoverPresentationController.sourceRect = CGRectOffset(cellRect, -self.tableView.contentOffset.x, -self.tableView.contentOffset.y); + + [self presentViewController:alertController animated:YES completion:nil]; +} + +#pragma mark - + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + + if (indexPath.section == 4 && indexPath.row == 2) { + return 80; + } else { + return NCGlobal.shared.heightCellSettings; + } +} + +@end diff --git a/iOSClient/Settings/CCManageAccount.h b/iOSClient/Settings/CCManageAccount.h new file mode 100644 index 0000000000..48a072c44f --- /dev/null +++ b/iOSClient/Settings/CCManageAccount.h @@ -0,0 +1,28 @@ +// +// CCManageAccount.h +// Nextcloud +// +// Created by Marino Faggiana on 12/03/15. +// Copyright (c) 2015 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +#import + +@interface CCManageAccount : XLFormViewController + +@end diff --git a/iOSClient/Settings/CCManageAccount.m b/iOSClient/Settings/CCManageAccount.m new file mode 100644 index 0000000000..8c06b8e244 --- /dev/null +++ b/iOSClient/Settings/CCManageAccount.m @@ -0,0 +1,443 @@ +// +// CCManageAccount.m +// Nextcloud +// +// Created by Marino Faggiana on 12/03/15. +// Copyright (c) 2015 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +#import "CCManageAccount.h" +#import "NCBridgeSwift.h" +#import "CCUtility.h" + +#define actionSheetCancellaAccount 1 + +@interface CCManageAccount () +{ + AppDelegate *appDelegate; +} +@end + +@implementation CCManageAccount + +- (void)initializeForm +{ + XLFormDescriptor *form = [XLFormDescriptor formDescriptor]; + XLFormSectionDescriptor *section; + XLFormRowDescriptor *row; + + NSArray *accounts = [[NCManageDatabase shared] getAllTableAccount]; + tableAccount *activeAccount = [[NCManageDatabase shared] getActiveTableAccount]; + + // Section : ACCOUNTS ------------------------------------------- + + section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_accounts_", nil) sectionOptions:XLFormSectionOptionCanDelete]; + [form addFormSection:section]; + + for (tableAccount *account in accounts) { + + NSString *title = [NSString stringWithFormat:@"%@ %@", account.user, [NSURL URLWithString:account.urlBase].host]; + row = [XLFormRowDescriptor formRowDescriptorWithTag:account.account rowType:XLFormRowDescriptorTypeBooleanCheck title:title]; + + // Avatar + UIImage *avatar = [[[NCUtility alloc] init] loadUserImageFor:account.user displayName:account.displayName urlBase:account.urlBase]; + + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:13.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:avatar forKey:@"imageView.image"]; + if (account.active) { + row.value = @"YES"; + } + [section addFormRow:row]; + } + + // Section : ALIAS -------------------------------------------------- + + section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_alias_", nil)]; + section.footerTitle = NSLocalizedString(@"_alias_footer_", nil); + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"alias" rowType:XLFormRowDescriptorTypeText]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[[UIImage imageNamed:@"form-textbox"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textField.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textField.textColor"]; + row.value = activeAccount.alias; + [section addFormRow:row]; + + // Section : MANAGE ACCOUNT ------------------------------------------- + + if ([NCBrandOptions shared].disable_multiaccount == NO) { + + section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_manage_account_", nil)]; + [form addFormSection:section]; + + if ([NCBrandOptions shared].disable_multiaccount == NO) { + + // New Account nextcloud + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"addAccount" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_add_account_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[[UIImage systemImageNamed:@"plus"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.action.formSelector = @selector(addAccount:); + [section addFormRow:row]; + } + + // Set user status + + BOOL userStatus = [[NCGlobal shared] capabilityUserStatusEnabled]; + if (userStatus) { + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"setUserStatus" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_set_user_status_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"userStatusAway"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + row.action.formSelector = @selector(setUserStatus:); + if (accounts.count == 0) row.disabled = @YES; + [section addFormRow:row]; + } + + if ([NCBrandOptions shared].disable_multiaccount == NO) { + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"accountRequest" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_settings_account_request_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[[UIImage imageNamed:@"users"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + if ([[NCKeychain alloc] init].accountRequest) row.value = @1; + else row.value = @0; + [section addFormRow:row]; + } + } + + // Section : CERIFICATES ------------------------------------------- + + section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_certificates_", nil)]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"certificateDetails" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_certificate_details_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"lock"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.action.formSelector = @selector(certificateDetails:); + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"certificatePNDetails" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_certificate_pn_details_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"lock"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.action.formSelector = @selector(certificatePNDetails:); + [section addFormRow:row]; + + // Section : USER INFORMATION ------------------------------------------- + + section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_personal_information_", nil)]; + [form addFormSection:section]; + + // Full Name + if ([activeAccount.displayName length] > 0) { + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"userfullname" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_full_name_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"user"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + row.value = activeAccount.displayName; + [section addFormRow:row]; + } + + // Address + if ([activeAccount.address length] > 0) { + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"useraddress" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_address_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"address"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + row.value = activeAccount.address; + [section addFormRow:row]; + } + + // City + zip + if ([activeAccount.city length] > 0) { + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"usercity" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_city_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"city"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + row.value = activeAccount.city; + if ([activeAccount.zip length] > 0) { + row.value = [NSString stringWithFormat:@"%@ %@", row.value, activeAccount.zip]; + } + [section addFormRow:row]; + } + + // Country + if ([activeAccount.country length] > 0) { + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"usercountry" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_country_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"country"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + row.value = [[NSLocale systemLocale] displayNameForKey:NSLocaleCountryCode value:activeAccount.country]; + [section addFormRow:row]; + } + + // Phone + if ([activeAccount.phone length] > 0) { + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"userphone" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_phone_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"phone"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + row.value = activeAccount.phone; + [section addFormRow:row]; + } + + // Email + if ([activeAccount.email length] > 0) { + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"useremail" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_email_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"email"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + row.value = activeAccount.email; + [section addFormRow:row]; + } + + // Web + if ([activeAccount.website length] > 0) { + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"userweb" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_web_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"network"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + row.value = activeAccount.website; + [section addFormRow:row]; + } + + // Twitter + if ([activeAccount.twitter length] > 0) { + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"usertwitter" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_twitter_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"twitter"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + row.value = activeAccount.twitter; + [section addFormRow:row]; + } + + self.tableView.showsVerticalScrollIndicator = NO; + self.form = form; + + // Open Login + if (accounts.count == 0) { + [appDelegate openLoginWithViewController:self selector:NCGlobal.shared.introLogin openLoginWeb:false]; + } +} + +// MARK: - View Life Cycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.title = NSLocalizedString(@"_credentials_", nil); + appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; + + self.view.backgroundColor = UIColor.systemGroupedBackgroundColor; + + self.tableView.backgroundColor = UIColor.systemGroupedBackgroundColor; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeUser) name:NCGlobal.shared.notificationCenterChangeUser object:nil]; + + [self initializeForm]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + appDelegate.activeViewController = self; +} + +#pragma mark - NotificationCenter + +- (void)changeUser +{ + [self initializeForm]; +} + +#pragma mark - + +-(void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)rowDescriptor oldValue:(id)oldValue newValue:(id)newValue +{ + [super formRowDescriptorValueHasChanged:rowDescriptor oldValue:oldValue newValue:newValue]; + + if ([rowDescriptor.tag isEqualToString:@"accountRequest"]) { + + if ([[rowDescriptor.value valueData] boolValue] == YES) { + [[NCKeychain alloc] init].accountRequest = true; + } else { + [[NCKeychain alloc] init].accountRequest = false; + } + } + + else if ([rowDescriptor.tag isEqualToString:@"alias"]) { + + if ([newValue isEqual:[NSNull null]]) { + [[NCManageDatabase shared] setAccountAlias:@""]; + } else { + [[NCManageDatabase shared] setAccountAlias:newValue]; + } + } + + else { + + NSArray *accounts = [[NCManageDatabase shared] getAllTableAccount]; + tableAccount *activeAccount = [[NCManageDatabase shared] getActiveTableAccount]; + + for (tableAccount *account in accounts) { + if ([rowDescriptor.tag isEqualToString:account.account]) { + if (![account.account isEqualToString:activeAccount.account]) { + [appDelegate changeAccount:account.account userProfile:nil]; + } + } + } + + [self initializeForm]; + } +} + +-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return NSLocalizedString(@"_remove_local_account_", nil); +} + +-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { + [super tableView:tableView commitEditingStyle:editingStyle forRowAtIndexPath:indexPath]; + + if (editingStyle == UITableViewCellEditingStyleDelete) { + + [self initializeForm]; + + NSArray *accounts = [[NCManageDatabase shared] getAllTableAccount]; + tableAccount *tableAccountForDelete = accounts[indexPath.row]; + tableAccount *tableActiveAccount = [[NCManageDatabase shared] getActiveTableAccount]; + + NSString *accountForDelete = tableAccountForDelete.account; + NSString *activeAccount = tableActiveAccount.account; + + NSString *title = [NSString stringWithFormat:NSLocalizedString(@"_want_delete_account_",nil), accountForDelete]; + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleActionSheet]; + + [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_remove_local_account_", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { + + if (accountForDelete) { + [appDelegate deleteAccount:accountForDelete wipe:false]; + } + + NSArray *listAccount = [[NCManageDatabase shared] getAccounts]; + if ([listAccount count] > 0) { + if ([accountForDelete isEqualToString:activeAccount]) { + [appDelegate changeAccount:listAccount[0] userProfile:nil]; + } + } + + [self initializeForm]; + }]]; + + [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_cancel_", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { }]]; + + alertController.popoverPresentationController.sourceView = self.view; + alertController.popoverPresentationController.sourceRect = [self.tableView rectForRowAtIndexPath:indexPath]; + + [self presentViewController:alertController animated:YES completion:nil]; + } +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + if (indexPath.section == 0) { + return 60; + } else { + return NCGlobal.shared.heightCellSettings; + } +} + +#pragma mark - + +- (void)addAccount:(XLFormRowDescriptor *)sender +{ + [self deselectFormRow:sender]; + +// [appDelegate openLoginWithViewController:self selector:NCGlobal.shared.introLogin openLoginWeb:false]; +} + +#pragma mark - + +- (void)setUserStatus:(XLFormRowDescriptor *)sender +{ + [self deselectFormRow:sender]; + + UINavigationController *navigationController = [[UIStoryboard storyboardWithName:@"NCUserStatus" bundle:nil] instantiateInitialViewController]; + [self presentViewController:navigationController animated:YES completion:nil]; +} + +#pragma mark - + +- (void)certificateDetails:(XLFormRowDescriptor *)sender +{ + [self deselectFormRow:sender]; + + UINavigationController *navigationController = [[UIStoryboard storyboardWithName:@"NCViewCertificateDetails" bundle:nil] instantiateInitialViewController]; + NCViewCertificateDetails *viewController = (NCViewCertificateDetails *)navigationController.topViewController; + + NSURL *url = [NSURL URLWithString:appDelegate.urlBase]; + viewController.host = [url host]; + + [self presentViewController:navigationController animated:YES completion:nil]; +} + +- (void)certificatePNDetails:(XLFormRowDescriptor *)sender +{ + [self deselectFormRow:sender]; + + UINavigationController *navigationController = [[UIStoryboard storyboardWithName:@"NCViewCertificateDetails" bundle:nil] instantiateInitialViewController]; + NCViewCertificateDetails *viewController = (NCViewCertificateDetails *)navigationController.topViewController; + + NSURL *url = [NSURL URLWithString: NCBrandOptions.shared.pushNotificationServerProxy]; + viewController.host = [url host]; + viewController.certificateTitle = NSLocalizedString(@"_certificate_pn_view_", nil); + + [self presentViewController:navigationController animated:YES completion:nil]; +} + +@end diff --git a/iOSClient/Settings/CCManageAutoUpload.h b/iOSClient/Settings/CCManageAutoUpload.h new file mode 100644 index 0000000000..1e6b701cfc --- /dev/null +++ b/iOSClient/Settings/CCManageAutoUpload.h @@ -0,0 +1,28 @@ +// +// CCManageAutoUpload.h +// Nextcloud +// +// Created by Marino Faggiana on 01/09/15. +// Copyright (c) 2015 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +#import + +@interface CCManageAutoUpload : XLFormViewController + +@end diff --git a/iOSClient/Settings/CCManageAutoUpload.m b/iOSClient/Settings/CCManageAutoUpload.m new file mode 100644 index 0000000000..8f78acc6f1 --- /dev/null +++ b/iOSClient/Settings/CCManageAutoUpload.m @@ -0,0 +1,547 @@ +// +// CCManageAutoUpload.m +// Nextcloud +// +// Created by Marino Faggiana on 01/09/15. +// Copyright (c) 2015 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +#import +#import "CCManageAutoUpload.h" +#import "CCUtility.h" +#import "NCBridgeSwift.h" +#import "AdjustHelper.h" + +@interface CCManageAutoUpload () +{ + AppDelegate *appDelegate; + AdjustHelper *adjust; + TealiumHelper *tealium; +} +@end + +@implementation CCManageAutoUpload + +- (void)initializeForm +{ + XLFormDescriptor *form = [XLFormDescriptor formDescriptor]; + XLFormSectionDescriptor *section; + XLFormRowDescriptor *row; + + tableAccount *activeAccount = [[NCManageDatabase shared] getActiveTableAccount]; + tableAccount *activeAccount = [[NCManageDatabase shared] getActiveAccount]; + + + // Auto Upload + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + section.footerTitle = NSLocalizedString(@"_autoupload_description_", nil); + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"autoUpload" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_autoupload_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + if (activeAccount.autoUpload) row.value = @1; + else row.value = @0; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + [section addFormRow:row]; + + // Auto Upload Directory + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"autoUploadDirectory" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_autoupload_select_folder_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"foldersOnTop"] imageWithColor:NCBrandColor.shared.iconImageColor size:25] forKey:@"imageView.image"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"foldersOnTop"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + //[row.cellConfig setObject:@(UITableViewCellAccessoryDisclosureIndicator) forKey:@"accessoryType"]; + row.action.formSelector = @selector(selectAutomaticUploadFolder); + [section addFormRow:row]; + + // Auto Upload Photo + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"autoUploadImage" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_autoupload_photos_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + if (activeAccount.autoUploadImage) row.value = @1; + else row.value = @0; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"autoUploadWWAnPhoto" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_wifi_only_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + if (activeAccount.autoUploadWWAnPhoto) row.value = @1; + else row.value = @0; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + [section addFormRow:row]; + + // Auto Upload Video + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"autoUploadVideo" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_autoupload_videos_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + if (activeAccount.autoUploadVideo) row.value = @1; + else row.value = @0; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"autoUploadWWAnVideo" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_wifi_only_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + if (activeAccount.autoUploadWWAnVideo) row.value = @1; + else row.value = @0; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + [section addFormRow:row]; + + // Delete asset remove photo camera roll + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"removePhotoCameraRoll" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_remove_photo_CameraRoll_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + if ([[[NCKeychain alloc] init] removePhotoCameraRoll]) row.value = @"1"; + else row.value = @0; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + [section addFormRow:row]; + + // Auto Upload Full + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + NSString *title = NSLocalizedString(@"_autoupload_fullphotos_", nil); + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"autoUploadFull" rowType:XLFormRowDescriptorTypeBooleanSwitch title:title]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + row.value = 0; + if (activeAccount.autoUploadFull) row.value = @1; + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"autoUploadStart" rowType:XLFormRowDescriptorTypeBooleanSwitch title:title]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + row.value = 0; + if (activeAccount.autoUploadStart) row.value = @1; + else row.value = @0; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + [section addFormRow:row]; + + // Auto Upload create subfolder + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"autoUploadCreateSubfolder" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_autoupload_create_subfolder_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + if (activeAccount.autoUploadCreateSubfolder) row.value = @1; + else row.value = @0; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"autoUploadSubfolderGranularity" rowType:XLFormRowDescriptorTypeSelectorPush title:NSLocalizedString(@"_autoupload_subfolder_granularity_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + row.cellConfigForSelector[@"tintColor"] = NCBrandColor.shared.customer; + row.selectorOptions = @[ + [XLFormOptionsObject formOptionsObjectWithValue:@(NCGlobal.shared.subfolderGranularityYearly) displayText:NSLocalizedString(@"_yearly_", nil)], + [XLFormOptionsObject formOptionsObjectWithValue:@(NCGlobal.shared.subfolderGranularityMonthly) displayText:NSLocalizedString(@"_monthly_", nil)], + [XLFormOptionsObject formOptionsObjectWithValue:@(NCGlobal.shared.subfolderGranularityDaily) displayText:NSLocalizedString(@"_daily_", nil)] + ]; + row.value = row.selectorOptions[activeAccount.autoUploadSubfolderGranularity]; + row.required = true; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [section addFormRow:row]; + + // Auto Upload file name + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"autoUploadFileName" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_autoupload_filenamemask_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.action.viewControllerClass = [NCManageAutoUploadFileName class]; + [section addFormRow:row]; + + // end + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + self.tableView.showsVerticalScrollIndicator = NO; + self.form = form; +} + +// MARK: - View Life Cycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.title = NSLocalizedString(@"_settings_autoupload_", nil); + appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; + self.view.backgroundColor = UIColor.systemGroupedBackgroundColor; + + adjust = [[AdjustHelper alloc] init]; + [adjust configAdjust]; + tealium = [[TealiumHelper alloc] init]; + self.tableView.backgroundColor = UIColor.systemGroupedBackgroundColor; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeUser) name:NCGlobal.shared.notificationCenterChangeUser object:nil]; + + [self initializeForm]; + [self reloadForm]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + appDelegate.activeViewController = self; + [[[NCAskAuthorization alloc] init] askAuthorizationPhotoLibraryWithController:self completion:^(BOOL status) { }]; + [[[NCAskAuthorization alloc] init] askAuthorizationPhotoLibraryWithViewController:self completion:^(BOOL status) { }]; + appDelegate.account = [[[NCKeychain alloc] init] getAccountName] ; + [[[NCAskAuthorization alloc] init] askAuthorizationPhotoLibraryWithController:self completion:^(BOOL status) { }]; +} + +- (void)changeUser +{ + // [[self navigationController] popViewControllerAnimated:YES]; + [self initializeForm]; + [self reloadForm]; +} + +#pragma mark - NotificationCenter + + +#pragma mark - + +-(void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)rowDescriptor oldValue:(id)oldValue newValue:(id)newValue +{ + [super formRowDescriptorValueHasChanged:rowDescriptor oldValue:oldValue newValue:newValue]; + + tableAccount *activeAccount = [[NCManageDatabase shared] getActiveTableAccount]; + tableAccount *activeAccount = [[NCManageDatabase shared] getActiveAccount]; + + + if ([rowDescriptor.tag isEqualToString:@"autoUpload"]) { + + if ([[rowDescriptor.value valueData] boolValue] == YES) { + + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUpload" state:YES]; + + // Default + [[NCManageDatabase shared] setAccountAutoUploadFileName:nil]; + [[NCManageDatabase shared] setAccountAutoUploadDirectory:nil urlBase:appDelegate.urlBase userId:appDelegate.userId account:appDelegate.account]; + + // verifichiamo che almeno uno dei servizi (foto video) siano attivi, in caso contrario attiviamo le foto + if (activeAccount.autoUploadImage == NO && activeAccount.autoUploadVideo == NO) { + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadImage" state:YES]; + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadVideo" state:YES]; + } + + [[NCAutoUpload shared] alignPhotoLibraryWithController:self account:appDelegate.account]; + + [[NCAutoUpload shared] alignPhotoLibraryWithViewController:self]; +// [[NCAutoUpload shared] alignPhotoLibraryWithViewController:self]; + + } else { + + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUpload" state:NO]; + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadFull" state:NO]; + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadStart" state:NO]; + + // remove + [[NCManageDatabase shared] clearMetadatasUploadWithAccount:appDelegate.account]; + } + + [self reloadForm]; + } + + if ([rowDescriptor.tag isEqualToString:@"removePhotoCameraRoll"]) { + + [[NCKeychain alloc] init].removePhotoCameraRoll = [[rowDescriptor.value valueData] boolValue]; + } + + if ([rowDescriptor.tag isEqualToString:@"autoUploadFull"]) { + if ([rowDescriptor.tag isEqualToString:@"autoUploadStart"]) { + + if ([[rowDescriptor.value valueData] boolValue] == YES) { + + [[NCAutoUpload shared] autoUploadFullPhotosWithController:self log:@"Auto upload full" account:appDelegate.account]; + [[NCAutoUpload shared] autoUploadFullPhotosWithViewController:self log:@"Auto upload full"]; + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadFull" state:YES]; +// [[NCAutoUpload shared] autoUploadFullPhotosWithViewController:self log:@"Auto upload full"]; + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadStart" state:YES]; + + } else { + + [[NCManageDatabase shared] clearMetadatasUploadWithAccount:appDelegate.account]; + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadFull" state:NO]; + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadStart" state:NO]; + } + } + + if ([rowDescriptor.tag isEqualToString:@"autoUploadImage"]) { + + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadImage" state:[[rowDescriptor.value valueData] boolValue]]; + + if ([[rowDescriptor.value valueData] boolValue] == YES) { + [[NCAutoUpload shared] alignPhotoLibraryWithController:self account:appDelegate.account]; + [[NCAutoUpload shared] alignPhotoLibraryWithViewController:self]; +// [[NCAutoUpload shared] alignPhotoLibraryWithViewController:self]; + } + } + + if ([rowDescriptor.tag isEqualToString:@"autoUploadWWAnPhoto"]) { + + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadWWAnPhoto" state:[[rowDescriptor.value valueData] boolValue]]; + } + + if ([rowDescriptor.tag isEqualToString:@"autoUploadVideo"]) { + + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadVideo" state:[[rowDescriptor.value valueData] boolValue]]; + + if ([[rowDescriptor.value valueData] boolValue] == YES){ + [[NCAutoUpload shared] alignPhotoLibraryWithController:self account:appDelegate.account]; + [[NCAutoUpload shared] alignPhotoLibraryWithViewController:self]; +// [[NCAutoUpload shared] alignPhotoLibraryWithViewController:self]; + } + } + + if ([rowDescriptor.tag isEqualToString:@"autoUploadWWAnVideo"]) { + + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadWWAnVideo" state:[[rowDescriptor.value valueData] boolValue]]; + } + + if ([rowDescriptor.tag isEqualToString:@"autoUploadCreateSubfolder"]) { + + [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadCreateSubfolder" state:[[rowDescriptor.value valueData] boolValue]]; + } + + if ([rowDescriptor.tag isEqualToString:@"autoUploadSubfolderGranularity"]) { + + [[NCManageDatabase shared] setAccountAutoUploadGranularity:@"autoUploadSubfolderGranularity" state:[[rowDescriptor.value valueData] integerValue]]; + } +} + +- (void)done:(XLFormRowDescriptor *)sender +{ + [self dismissViewControllerAnimated:YES completion:nil]; +} + +- (void)reloadForm +{ + self.form.delegate = nil; + + XLFormRowDescriptor *rowAutoUpload = [self.form formRowWithTag:@"autoUpload"]; + + XLFormRowDescriptor *rowAutoUploadImage = [self.form formRowWithTag:@"autoUploadImage"]; + XLFormRowDescriptor *rowAutoUploadWWAnPhoto = [self.form formRowWithTag:@"autoUploadWWAnPhoto"]; + + XLFormRowDescriptor *rowAutoUploadVideo = [self.form formRowWithTag:@"autoUploadVideo"]; + XLFormRowDescriptor *rowAutoUploadWWAnVideo = [self.form formRowWithTag:@"autoUploadWWAnVideo"]; + XLFormRowDescriptor *rowRemovePhotoCameraRoll = [self.form formRowWithTag:@"removePhotoCameraRoll"]; + + XLFormRowDescriptor *rowAutoUploadFull = [self.form formRowWithTag:@"autoUploadFull"]; + XLFormRowDescriptor *rowAutoUploadFull = [self.form formRowWithTag:@"autoUploadStart"]; + + XLFormRowDescriptor *rowAutoUploadCreateSubfolder = [self.form formRowWithTag:@"autoUploadCreateSubfolder"]; + + XLFormRowDescriptor *rowAutoUploadSubfolderGranularity = [self.form formRowWithTag:@"autoUploadSubfolderGranularity"]; + + XLFormRowDescriptor *rowAutoUploadFileName = [self.form formRowWithTag:@"autoUploadFileName"]; + + // - STATUS --------------------- + tableAccount *activeAccount = [[NCManageDatabase shared] getActiveTableAccount]; + tableAccount *activeAccount = [[NCManageDatabase shared] getActiveAccount]; + + if (activeAccount.autoUpload) + [rowAutoUpload setValue:@1]; else [rowAutoUpload setValue:@0]; + + if (activeAccount.autoUploadImage) + [rowAutoUploadImage setValue:@1]; else [rowAutoUploadImage setValue:@0]; + + if (activeAccount.autoUploadWWAnPhoto) + [rowAutoUploadWWAnPhoto setValue:@1]; else [rowAutoUploadWWAnPhoto setValue:@0]; + + if ([[[NCKeychain alloc] init] removePhotoCameraRoll]) + [rowRemovePhotoCameraRoll setValue:@1]; else [rowRemovePhotoCameraRoll setValue:@0]; + + if (activeAccount.autoUploadVideo) + [rowAutoUploadVideo setValue:@1]; else [rowAutoUploadVideo setValue:@0]; + + if (activeAccount.autoUploadWWAnVideo) + [rowAutoUploadWWAnVideo setValue:@1]; else [rowAutoUploadWWAnVideo setValue:@0]; + + if (activeAccount.autoUploadFull) + if (activeAccount.autoUploadStart) + [rowAutoUploadFull setValue:@1]; else [rowAutoUploadFull setValue:@0]; + + if (activeAccount.autoUploadCreateSubfolder) + [rowAutoUploadCreateSubfolder setValue:@1]; else [rowAutoUploadCreateSubfolder setValue:@0]; + + [rowAutoUploadSubfolderGranularity setValue:rowAutoUploadSubfolderGranularity.selectorOptions[activeAccount.autoUploadSubfolderGranularity]]; + + // - HIDDEN -------------------------------------------------------------------------- + + rowAutoUploadImage.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + rowAutoUploadWWAnPhoto.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + + rowAutoUploadVideo.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + rowAutoUploadWWAnVideo.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + rowRemovePhotoCameraRoll.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + + rowAutoUploadFull.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + + rowAutoUploadCreateSubfolder.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + + rowAutoUploadSubfolderGranularity.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + + rowAutoUploadFileName.hidden = [NSString stringWithFormat:@"$%@==0", @"autoUpload"]; + + // ----------------------------------------------------------------------------------- + + [self.tableView reloadData]; + + self.form.delegate = self; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return NCGlobal.shared.heightCellSettings; +} + +- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section +{ + tableAccount *activeAccount = [[NCManageDatabase shared] getActiveTableAccount]; + tableAccount *activeAccount = [[NCManageDatabase shared] getActiveAccount]; + NSString *sectionName; + NSString *autoUploadPath = [NSString stringWithFormat:@"%@/%@", [[NCManageDatabase shared] getAccountAutoUploadDirectoryWithUrlBase:appDelegate.urlBase userId:appDelegate.userId account:appDelegate.account], [[NCManageDatabase shared] getAccountAutoUploadFileName]]; + + switch (section) + { + case 0: + sectionName = NSLocalizedString(@"_autoupload_description_", nil); + break; + case 1: + if (activeAccount.autoUpload) sectionName = [NSString stringWithFormat:@"%@: %@", NSLocalizedString(@"_autoupload_current_folder_", nil), [self returnPathfromServerUrl:autoUploadPath urlBase:appDelegate.urlBase userId:appDelegate.userId account:appDelegate.account]]; + else sectionName = @""; + break; + case 4: + if (activeAccount.autoUpload) sectionName = NSLocalizedString(@"_remove_photo_CameraRoll_desc_", nil); + else sectionName = @""; + break; + case 5: + if (activeAccount.autoUpload) sectionName = NSLocalizedString(@"_autoupload_description_background_", nil); + else sectionName = @""; + break; + case 6: + if (activeAccount.autoUpload) sectionName = NSLocalizedString(@"_autoupload_create_subfolder_footer_", nil); + else sectionName = @""; + break; + case 7: + if (activeAccount.autoUpload) sectionName = NSLocalizedString(@"_autoupload_fullphotos_footer_", nil); + if (activeAccount.autoUpload) sectionName = NSLocalizedString(@"_autoupload_fullphotos_footer_", nil); + else sectionName = @""; + break; + case 5: + if (activeAccount.autoUpload) sectionName = NSLocalizedString(@"_autoupload_create_subfolder_footer_", nil); + else sectionName = @""; + break; + case 6: + if (activeAccount.autoUpload) sectionName = NSLocalizedString(@"_autoupload_filenamemask_footer_", nil); + else sectionName = @""; + break; + } + return sectionName; +} + +- (void)dismissSelectWithServerUrl:(NSString * _Nullable)serverUrl metadata:(tableMetadata * _Nullable)metadata type:(NSString * _Nonnull)type items:(NSArray * _Nonnull)items overwrite:(BOOL)overwrite copy:(BOOL)copy move:(BOOL)move +- (void)dismissSelectWithServerUrl:(NSString * _Nullable)serverUrl metadata:(tableMetadata * _Nullable)metadata type:(NSString * _Nonnull)type items:(NSArray * _Nonnull)items overwrite:(BOOL)overwrite copy:(BOOL)copy move:(BOOL)move +{ + if (serverUrl != nil) { + + NSString* home = [[[NCUtilityFileSystem alloc] init] getHomeServerWithUrlBase:appDelegate.urlBase userId:appDelegate.userId]; + if ([serverUrl isEqualToString:home]) { +// NKError *error = [[NKError alloc] initWithErrorCode:NCGlobal.shared.errorInternalError errorDescription:@"_autoupload_error_select_folder_"];// responseData:nil]; +// [[[NCContentPresenter alloc] init] messageNotification:@"_error_" error:error delay:[[NCGlobal shared] dismissAfterSecond] type:messageTypeError afterDelay:0]; + NKError *error = [[NKError alloc] initWithErrorCode:NCGlobal.shared.errorInternalError errorDescription:@"_autoupload_error_select_folder_" responseData:nil]; + [[[NCContentPresenter alloc] init] messageNotification:@"_error_" error:error delay:[[NCGlobal shared] dismissAfterSecond] type:messageTypeError afterDelay:0]; + return; + } + + // Settings new folder Automatatic upload + [[NCManageDatabase shared] setAccountAutoUploadFileName:serverUrl.lastPathComponent]; + NSString *path = [[[NCUtilityFileSystem alloc] init] deleteLastPathWithServerUrlPath:serverUrl home:home]; + if (path != nil) { + [[NCManageDatabase shared] setAccountAutoUploadDirectory:path urlBase:appDelegate.urlBase userId:appDelegate.userId account:appDelegate.account]; + } + // Reload + [self.tableView reloadData]; + } +} + +- (void)selectAutomaticUploadFolder + { + UINavigationController *navigationController = [[UIStoryboard storyboardWithName:@"NCSelect" bundle:nil] instantiateInitialViewController]; + NCSelect *viewController = (NCSelect *)navigationController.topViewController; + + viewController.delegate = self; + viewController.typeOfCommandView = 1; + + [self presentViewController:navigationController animated:YES completion:^{ + [self.tableView reloadData]; + }]; + } + +- (NSString *)returnPathfromServerUrl:(NSString *)serverUrl urlBase:(NSString *)urlBase userId:(NSString *)userId account:(NSString *)account +{ + NSString *homeServer = [[[NCUtilityFileSystem alloc] init] getHomeServerWithUrlBase:urlBase userId:userId]; + NSString *path = [serverUrl stringByReplacingOccurrencesOfString:homeServer withString:@""]; + return path; +} + +@end diff --git a/iOSClient/Settings/HelpViewController.swift b/iOSClient/Settings/HelpViewController.swift new file mode 100644 index 0000000000..eb91d7b4cf --- /dev/null +++ b/iOSClient/Settings/HelpViewController.swift @@ -0,0 +1,57 @@ +// +// HelpViewController.swift +// Nextcloud +// +// Created by A200073704 on 11/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import UIKit +import WebKit + +class HelpViewController: UIViewController, WKNavigationDelegate, WKUIDelegate { + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view, typically from a nib. + + self.title = NSLocalizedString("_help_", comment: "") + let myWebView:WKWebView = WKWebView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.width, height:UIScreen.main.bounds.height)) + myWebView.uiDelegate = self + myWebView.navigationDelegate = self + myWebView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + self.view.addSubview(myWebView) + + + //1. Load web site into my web view + let myURL = URL(string: "https://cloud.telekom-dienste.de/hilfe") + let myURLRequest:URLRequest = URLRequest(url: myURL!) + NCActivityIndicator.shared.start() + myWebView.load(myURLRequest) + + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + NCActivityIndicator.shared.stop() + } + + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + if navigationAction.navigationType == .linkActivated { + if let url = navigationAction.request.url, + UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url) + decisionHandler(.cancel) + } else { + decisionHandler(.allow) + } + } else { + decisionHandler(.allow) + } + } +} + diff --git a/iOSClient/Settings/ImprintViewController.swift b/iOSClient/Settings/ImprintViewController.swift new file mode 100644 index 0000000000..819a86599d --- /dev/null +++ b/iOSClient/Settings/ImprintViewController.swift @@ -0,0 +1,70 @@ +// +// ImprintViewController.swift +// Nextcloud +// +// Created by A200073704 on 11/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import UIKit +import WebKit + +class ImprintViewController: UIViewController, WKNavigationDelegate, WKUIDelegate { + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view, typically from a nib. + self.title = NSLocalizedString("_imprint_", comment: "") + + let myWebView:WKWebView = WKWebView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.width, height:UIScreen.main.bounds.height)) + myWebView.uiDelegate = self + myWebView.navigationDelegate = self + myWebView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + self.view.addSubview(myWebView) + + + //1. Load web site into my web view + let myURL = URL(string: "https://www.telekom.de/impressum") + let myURLRequest:URLRequest = URLRequest(url: myURL!) + NCActivityIndicator.shared.start() + myWebView.load(myURLRequest) + + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + NCActivityIndicator.shared.stop() + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + + if UIDevice.current.orientation.isLandscape { + print("Landscape") + } + if UIDevice.current.orientation.isFlat { + print("Flat") + } else { + print("Portrait") + } + } + + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + if navigationAction.navigationType == .linkActivated { + if let url = navigationAction.request.url, + UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url) + decisionHandler(.cancel) + } else { + decisionHandler(.allow) + } + } else { + decisionHandler(.allow) + } + } +} + diff --git a/iOSClient/Settings/InitialPrivacySettingsViewController.swift b/iOSClient/Settings/InitialPrivacySettingsViewController.swift new file mode 100644 index 0000000000..8ae7b2e186 --- /dev/null +++ b/iOSClient/Settings/InitialPrivacySettingsViewController.swift @@ -0,0 +1,171 @@ +// +// InitialPrivacySettingsViewController.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import Foundation +import AppTrackingTransparency +import AdSupport +import UIKit +import XLForm + +class InitialPrivacySettingsViewController: UIViewController { + + @IBOutlet weak var dataPrivacyImage: UIImageView! + @IBOutlet weak var acceptButton: UIButton! + @IBOutlet weak var privacySettingsHelpText: UITextView! + @IBOutlet weak var privacySettingsTitle: UILabel! + @IBOutlet weak var widthPriavacyHelpView: NSLayoutConstraint! + var privacyHelpText = "" + + override func viewDidLoad() { + super.viewDidLoad() + + privacySettingsTitle.text = NSLocalizedString("_privacy_settings_title_", comment: "") + privacyHelpText = NSLocalizedString("_privacy_help_text_after_login_", comment: "") + privacySettingsHelpText.text = privacyHelpText + dataPrivacyImage.image = UIImage(named: "dataPrivacy")!.image(color: NCBrandColor.shared.brand, size: 60) + privacySettingsHelpText.delegate = self + privacySettingsHelpText.textColor = .label + privacySettingsHelpText.hyperLink(originalText: privacyHelpText, + linkTextsAndTypes: [NSLocalizedString("_key_privacy_help_", comment: ""): LinkType.privacyPolicy.rawValue, + NSLocalizedString("_key_reject_help_", comment: ""): LinkType.reject.rawValue, + NSLocalizedString("_key_settings_help_", comment: ""): LinkType.settings.rawValue]) + + acceptButton.backgroundColor = NCBrandColor.shared.brand + acceptButton.tintColor = UIColor.white + acceptButton.layer.cornerRadius = 5 + acceptButton.layer.borderWidth = 1 + acceptButton.layer.borderColor = NCBrandColor.shared.brand.cgColor + acceptButton.setTitle(NSLocalizedString("_accept_button_title_", comment: ""), for: .normal) + privacySettingsHelpText.centerText() + privacySettingsHelpText.font = UIFont(name: privacySettingsHelpText.font!.fontName, size: 16) + self.navigationItem.leftBarButtonItem?.tintColor = NCBrandColor.shared.brand + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.navigationController?.navigationBar.isHidden = true + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + self.navigationController?.navigationBar.isHidden = false + } + + override func viewDidLayoutSubviews(){ + if UIDevice.current.userInterfaceIdiom == .pad { + widthPriavacyHelpView.constant = UIScreen.main.bounds.width - 100 + } + } + + @IBAction func onAcceptButtonClicked(_ sender: Any) { + requestPermission() + } + + //NEWLY ADDED PERMISSIONS FOR iOS 14 + func requestPermission() { + UserDefaults.standard.set(true, forKey: "isInitialPrivacySettingsShowed") + UserDefaults.standard.set(true, forKey: "isAnalysisDataCollectionSwitchOn") + if #available(iOS 14, *) { + ATTrackingManager.requestTrackingAuthorization { status in + switch status { + case .authorized: + // Tracking authorization dialog was shown + // and we are authorized + print("Authorized") + // Now that we are authorized we can get the IDFA + print(ASIdentifierManager.shared().advertisingIdentifier) + case .denied: + UserDefaults.standard.set(true, forKey: "isInitialPrivacySettingsShowed") + UserDefaults.standard.set(false, forKey: "isAnalysisDataCollectionSwitchOn") + print("Denied") + case .notDetermined: + // Tracking authorization dialog has not been shown + print("Not Determined") + case .restricted: + print("Restricted") + @unknown default: + print("Unknown") + } + } + } else { + UserDefaults.standard.set(true, forKey: "isInitialPrivacySettingsShowed") + UserDefaults.standard.set(true, forKey: "isAnalysisDataCollectionSwitchOn") + } + self.dismiss(animated: true, completion: nil) + } +} +// MARK: - UITextViewDelegate +extension InitialPrivacySettingsViewController: UITextViewDelegate { + func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool { + if let linkType = LinkType(rawValue: URL.absoluteString) { + // TODO: handle linktype here with switch or similar. + switch linkType { + case LinkType.privacyPolicy: + //let storyBoard: UIStoryboard = UIStoryboard(name: "NCSettings", bundle: nil) + let privacyViewController = PrivacyPolicyViewController() + self.navigationController?.pushViewController(privacyViewController, animated: true) + case LinkType.reject: + UserDefaults.standard.set(false, forKey: "isAnalysisDataCollectionSwitchOn") + UserDefaults.standard.set(true, forKey: "isInitialPrivacySettingsShowed") + self.dismiss(animated: true, completion: nil) + case LinkType.settings: + let privacySettingsViewController = PrivacySettingsViewController() + UserDefaults.standard.set(true, forKey: "showSettingsButton") + self.navigationController?.pushViewController(privacySettingsViewController, animated: true) + } + print("handle link:: \(linkType)") + } + return false + } +} + +public extension UITextView { + + func hyperLink(originalText: String, linkTextsAndTypes: [String: String]) { + + let style = NSMutableParagraphStyle() + style.alignment = .left + + let attributedOriginalText = NSMutableAttributedString(string: originalText) + + let fullRange = NSRange(location: 0, length: attributedOriginalText.length) + attributedOriginalText.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.label, range: fullRange) + for linkTextAndType in linkTextsAndTypes { + let linkRange = attributedOriginalText.mutableString.range(of: linkTextAndType.key) + attributedOriginalText.addAttribute(NSAttributedString.Key.link, value: linkTextAndType.value, range: linkRange) + attributedOriginalText.addAttribute(NSAttributedString.Key.paragraphStyle, value: style, range: fullRange) + attributedOriginalText.addAttribute(NSAttributedString.Key.foregroundColor, value: NCBrandColor.shared.brand, range: linkRange) + attributedOriginalText.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 10), range: fullRange) + } + + self.linkTextAttributes = [NSAttributedString.Key.foregroundColor: NCBrandColor.shared.brand] + self.attributedText = attributedOriginalText + } + + func centerText() { + self.textAlignment = .justified + let fittingSize = CGSize(width: 300, height: CGFloat.greatestFiniteMagnitude) + let size = sizeThatFits(fittingSize) + let topOffset = (bounds.size.height - size.height * zoomScale) / 2 + let positiveTopOffset = max(1, topOffset) + contentOffset.y = -positiveTopOffset + } +} + +enum LinkType: String { + case reject + case privacyPolicy + case settings +} + + diff --git a/iOSClient/Settings/MagentaCloudVersionView.swift b/iOSClient/Settings/MagentaCloudVersionView.swift new file mode 100644 index 0000000000..925d4a8f50 --- /dev/null +++ b/iOSClient/Settings/MagentaCloudVersionView.swift @@ -0,0 +1,32 @@ +// +// MagentaCloudVersionView.swift +// Nextcloud +// +// Created by A200073704 on 11/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import Foundation + +import XLForm + +class MagentaCloudVersionView: XLFormBaseCell{ + + + @IBOutlet weak var cellLabel: UILabel! + @IBOutlet weak var versionLabel: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + self.selectionStyle = .none + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + } +} diff --git a/iOSClient/Settings/MagentaCloudVersionView.xib b/iOSClient/Settings/MagentaCloudVersionView.xib new file mode 100644 index 0000000000..9c9d06adfe --- /dev/null +++ b/iOSClient/Settings/MagentaCloudVersionView.xib @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Settings/NCManageAutoUploadFileName.swift b/iOSClient/Settings/NCManageAutoUploadFileName.swift new file mode 100644 index 0000000000..41356f7ea7 --- /dev/null +++ b/iOSClient/Settings/NCManageAutoUploadFileName.swift @@ -0,0 +1,234 @@ +// +// NCManageAutoUploadFileName.swift +// Nextcloud +// +// Created by Marino Faggiana on 19/07/17. +// Copyright (c) 2017 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import UIKit +import Photos +import NextcloudKit +import XLForm + +class NCManageAutoUploadFileName: XLFormViewController { + + let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + let dateExample = Date() + + func initializeForm() { + + let form: XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + 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 = NCKeychain().getOriginalFileName(key: NCGlobal.shared.keyFileNameOriginalAutoUpload) + row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.brand; + row.cellConfig["backgroundColor"] = UIColor.secondarySystemGroupedBackground + + row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["textLabel.textColor"] = UIColor.label + + section.addFormRow(row) + + // Add File Name Type + + row = XLFormRowDescriptor(tag: "addFileNameType", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_add_filenametype_", comment: "")) + row.value = NCKeychain().getFileNameType(key: NCGlobal.shared.keyFileNameAutoUploadType) + row.hidden = "$\("maintainOriginalFileName") == 1" + row.cellConfig["backgroundColor"] = UIColor.secondarySystemGroupedBackground + row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.brand; + + row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["textLabel.textColor"] = UIColor.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 = NCKeychain().getFileNameMask(key: NCGlobal.shared.keyFileNameAutoUploadMask) + if !fileNameMask.isEmpty { + row.cellConfig["textField.text"] = fileNameMask + row.value = fileNameMask + }else{ + let placeholderText = CCUtility.createFileName("IMG_0001.JPG", fileDate: dateExample, fileType: PHAssetMediaType.image, keyFileName: nil, keyFileNameType: NCGlobal.shared.keyFileNameAutoUploadType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginalAutoUpload, forcedNewFileName: false) + row.cellConfig["textField.text"] = placeholderText + row.value = "" + } + row.hidden = "$\("maintainOriginalFileName") == 1" + row.cellConfig["backgroundColor"] = UIColor.secondarySystemGroupedBackground + + row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["textLabel.textColor"] = UIColor.label + + row.cellConfig["textField.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["textField.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["textField.textColor"] = UIColor.label + + section.addFormRow(row) + + // Section: Preview File Name + + row = XLFormRowDescriptor(tag: "previewFileName", rowType: XLFormRowDescriptorTypeTextView, title: "") + row.height = 180 + row.disabled = true + row.cellConfig["backgroundColor"] = UIColor.secondarySystemGroupedBackground + + row.cellConfig["textView.backgroundColor"] = UIColor.secondarySystemGroupedBackground + row.cellConfig["textView.font"] = UIFont.systemFont(ofSize: 14.0) + row.cellConfig["textView.textColor"] = UIColor.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 = .systemGroupedBackground + + tableView.backgroundColor = .systemGroupedBackground + + initializeForm() + reloadForm() + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + appDelegate.activeViewController = self + } + + // MARK: XLForm + + func reloadForm() { + + self.form.delegate = nil + + 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) + let placeholderText = CCUtility.createFileName("IMG_0001.JPG", fileDate: dateExample, fileType: PHAssetMediaType.image, keyFileName: nil, keyFileNameType: NCGlobal.shared.keyFileNameAutoUploadType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginalAutoUpload, forcedNewFileName: false) + let fileNameMask : String = NCKeychain().getFileNameMask(key: NCGlobal.shared.keyFileNameAutoUploadMask) + if fileNameMask.count > 0 { + maskFileName.cellConfig["textField.text"] = fileNameMask + }else { + maskFileName.cellConfig["textField.text"] = placeholderText + } + 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" { + NCKeychain().setFileNameType(key: NCGlobal.shared.keyFileNameAutoUploadType, prefix: (formRow.value! as AnyObject).boolValue) + self.reloadForm() + } else if formRow.tag == "maintainOriginalFileName" { + NCKeychain().setOriginalFileName(key: NCGlobal.shared.keyFileNameOriginalAutoUpload, value: (formRow.value! as AnyObject).boolValue) + self.reloadForm() + } else if formRow.tag == "maskFileName" { + + let fileName = formRow.value as? String + + self.form.delegate = nil + + if let fileName = fileName { + formRow.value = NCUtility().removeForbiddenCharacters(fileName) + formRow.value = FileAutoRenamer.rename(fileName, account: appDelegate.account) + } + + self.form.delegate = self + + 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) + + let errorDescription = String(format: NSLocalizedString("_forbidden_characters_", comment: ""), NCGlobal.shared.forbiddenCharacters.joined(separator: " ")) + let error = NKError(errorCode: NCGlobal.shared.errorConflict, errorDescription: errorDescription) + NCContentPresenter().showInfo(error: error) + } + } + + self.reloadFormRow(previewFileName) + } + } + + // MARK: - Utility + + func previewFileName(valueRename: String?) -> String { + + var returnString: String = "" + + if NCKeychain().getOriginalFileName(key: NCGlobal.shared.keyFileNameOriginalAutoUpload) { + + return (NSLocalizedString("_filename_", comment: "") + ": IMG_0001.JPG") + + } else if let valueRename = valueRename { + + let valueRenameTrimming = valueRename.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + + if valueRenameTrimming.isEmpty { + + NCKeychain().setFileNameMask(key: NCGlobal.shared.keyFileNameAutoUploadMask, mask: "") + returnString = CCUtility.createFileName("IMG_0001.JPG", fileDate: dateExample, fileType: PHAssetMediaType.image, keyFileName: nil, keyFileNameType: NCGlobal.shared.keyFileNameAutoUploadType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginalAutoUpload, forcedNewFileName: false) + + } else { + + self.form.delegate = nil + NCKeychain().setFileNameMask(key: NCGlobal.shared.keyFileNameAutoUploadMask, mask: valueRename) + 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 { + + NCKeychain().setFileNameMask(key: NCGlobal.shared.keyFileNameAutoUploadMask, mask: "") + 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 + } +} diff --git a/iOSClient/Settings/NCManageE2EE.swift b/iOSClient/Settings/NCManageE2EE.swift new file mode 100644 index 0000000000..6cab2b6839 --- /dev/null +++ b/iOSClient/Settings/NCManageE2EE.swift @@ -0,0 +1,374 @@ +// +// NCManageE2EE.swift +// Nextcloud +// +// Created by Marino Faggiana on 17/11/22. +// Copyright © 2022 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import SwiftUI +import NextcloudKit +import TOPasscodeViewController +import LocalAuthentication + +@objc class NCManageE2EEInterface: NSObject { + + @objc func makeShipDetailsUI(account: String) -> UIViewController { + + let details = NCViewE2EE(account: account) + let vc = UIHostingController(rootView: details) + vc.title = NSLocalizedString("_e2e_settings_", comment: "") + return vc + } +} + +class NCManageE2EE: NSObject, ObservableObject, NCEndToEndInitializeDelegate, TOPasscodeViewControllerDelegate { + + let endToEndInitialize = NCEndToEndInitialize() + let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + var passcodeType = "" + + @Published var isEndToEndEnabled: Bool = false + @Published var statusOfService: String = NSLocalizedString("_status_in_progress_", comment: "") + + override init() { + super.init() + + endToEndInitialize.delegate = self + isEndToEndEnabled = NCKeychain().isEndToEndEnabled(account: appDelegate.account) + if isEndToEndEnabled { + statusOfService = NSLocalizedString("_status_e2ee_configured_", comment: "") + } else { + endToEndInitialize.statusOfService { error in + if error == .success { + self.statusOfService = NSLocalizedString("_status_e2ee_on_server_", comment: "") + } else { + self.statusOfService = NSLocalizedString("_status_e2ee_not_setup_", comment: "") + } + } + } + } + + // MARK: - Delegate + + func endToEndInitializeSuccess() { + isEndToEndEnabled = true + } + + // MARK: - Passcode + + @objc func requestPasscodeType(_ passcodeType: String) { + + let laContext = LAContext() + var error: NSError? + + let passcodeViewController = TOPasscodeViewController(passcodeType: .sixDigits, allowCancel: true) + passcodeViewController.delegate = self + passcodeViewController.keypadButtonShowLettering = false + if NCKeychain().touchFaceID, 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 + passcodeViewController.automaticallyPromptForBiometricValidation = true + } + } + + self.passcodeType = passcodeType + appDelegate.window?.rootViewController?.present(passcodeViewController, animated: true) + } + + @objc func correctPasscode() { + + switch self.passcodeType { + case "startE2E": + endToEndInitialize.initEndToEndEncryption() + case "readPassphrase": + if let e2ePassphrase = NCKeychain().getEndToEndPassphrase(account: appDelegate.account) { + print("[INFO]Passphrase: " + e2ePassphrase) + let message = "\n" + NSLocalizedString("_e2e_settings_the_passphrase_is_", comment: "") + "\n\n\n" + e2ePassphrase + let alertController = UIAlertController(title: NSLocalizedString("_info_", comment: ""), message: message, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_copy_passphrase_", comment: ""), style: .default, handler: { _ in + UIPasteboard.general.string = e2ePassphrase + })) + appDelegate.window?.rootViewController?.present(alertController, animated: true) + } + case "removeLocallyEncryption": + let alertController = UIAlertController(title: NSLocalizedString("_e2e_settings_remove_", comment: ""), message: NSLocalizedString("_e2e_settings_remove_message_", comment: ""), preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_remove_", comment: ""), style: .default, handler: { _ in + NCKeychain().clearAllKeysEndToEnd(account: self.appDelegate.account) + self.isEndToEndEnabled = NCKeychain().isEndToEndEnabled(account: self.appDelegate.account) + })) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .default, handler: { _ in })) + appDelegate.window?.rootViewController?.present(alertController, animated: true) + default: + break + } + } + + func passcodeViewController(_ passcodeViewController: TOPasscodeViewController, isCorrectCode code: String) -> Bool { + + if code == NCKeychain().passcode { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + self.correctPasscode() + } + return true + } else { + return false + } + } + + func didPerformBiometricValidationRequest(in passcodeViewController: TOPasscodeViewController) { + + LAContext().evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: NCBrandOptions.shared.brand) { success, _ in + if success { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + passcodeViewController.dismiss(animated: true) + self.correctPasscode() + } + } + } + } + + func didTapCancel(in passcodeViewController: TOPasscodeViewController) { + passcodeViewController.dismiss(animated: true) + } +} + +// MARK: Views + +struct NCViewE2EE: View { + + @ObservedObject var manageE2EE = NCManageE2EE() + @State var account: String = "" + + var body: some View { + + VStack { + + if manageE2EE.isEndToEndEnabled { + + List { + + Section(header: Text(""), footer: Text("End-to-End Encryption " + NCGlobal.shared.capabilityE2EEApiVersion)) { + Label { + Text(NSLocalizedString("_e2e_settings_activated_", comment: "")) + } icon: { + Image(systemName: "checkmark.circle.fill") + .resizable() + .scaledToFit() + .foregroundColor(.green) + } + } + + Section(header: Text(""), footer: Text(NSLocalizedString("_read_passphrase_description_", comment: ""))) { + Label { + Text(NSLocalizedString("_e2e_settings_read_passphrase_", comment: "")) + } icon: { + Image(systemName: "eye") + .resizable() + .scaledToFit() + .foregroundColor(Color(NCBrandColor.shared.iconColor)) + .frame(width: 20, height: 30) + } + .onTapGesture { + if NCKeychain().passcode != nil { + manageE2EE.requestPasscodeType("readPassphrase") + } else { + NCContentPresenter().showInfo(error: NKError(errorCode: 0, errorDescription: "_e2e_settings_lock_not_active_")) + } + } + } + + let removeStrDesc1 = NSLocalizedString("_remove_passphrase_desc_1_", comment: "") + let removeStrDesc2 = NSLocalizedString("_remove_passphrase_desc_2_", comment: "") + let removeStrDesc = String(format: "%@\n\n%@", removeStrDesc1, removeStrDesc2) + Section(header: Text(""), footer: Text(removeStrDesc)) { + Label { + Text(NSLocalizedString("_e2e_settings_remove_", comment: "")) + } icon: { + Image(systemName: "trash") + .resizable() + .scaledToFit() + .foregroundColor(Color(NCBrandColor.shared.iconColor)) + .frame(width: 20, height: 30) + } + .onTapGesture { + if NCKeychain().passcode != nil { + manageE2EE.requestPasscodeType("removeLocallyEncryption") + } else { + NCContentPresenter().showInfo(error: NKError(errorCode: 0, errorDescription: "_e2e_settings_lock_not_active_")) + } + } + } +#if DEBUG + DeleteCerificateSection() +#endif + } + + } else { + + List { + let startE2EDesc1 = NSLocalizedString("_start_e2e_encryption_1_", comment: ""); + let startE2EDesc2 = NSLocalizedString("_start_e2e_encryption_2_", comment: ""); + let startE2EDesc3 = NSLocalizedString("_start_e2e_encryption_3_", comment: ""); + let startE2EDesc = String(format: "%@\n\n%@\n\n%@",startE2EDesc1,startE2EDesc2,startE2EDesc3) + Section(header: Text(""), footer: Text(startE2EDesc)) { + HStack { + Label { + Text(NSLocalizedString("_e2e_settings_start_", comment: "")) + } icon: { + } + Spacer() + } + .contentShape(Rectangle()) + .onTapGesture { + if let passcode = NCKeychain().passcode { + manageE2EE.requestPasscodeType("startE2E") + } else { + NCContentPresenter().showInfo(error: NKError(errorCode: 0, errorDescription: "_e2e_settings_lock_not_active_")) + } + } + } + +#if DEBUG + DeleteCerificateSection() +#endif + } + .listStyle(GroupedListStyle()) + } + } + .background(Color(UIColor.systemGroupedBackground)) + } +} + +struct DeleteCerificateSection: View { + + var body: some View { + + Section(header: Text("Delete Server keys"), footer: Text("Available only in debug mode")) { + + HStack { + Label { + Text("Delete Certificate") + } icon: { + Image(systemName: "exclamationmark.triangle") + .resizable() + .scaledToFit() + .foregroundColor(Color(UIColor.systemGray)) + } + Spacer() + } + .contentShape(Rectangle()) + .onTapGesture { + NextcloudKit.shared.deleteE2EECertificate { _, error in + if error == .success { + NCContentPresenter().messageNotification("E2E delete certificate", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .success) + } else { + NCContentPresenter().messageNotification("E2E delete certificate", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .error) + } + } + } + + HStack { + Label { + Text("Delete PrivateKey") + } icon: { + Image(systemName: "exclamationmark.triangle") + .resizable() + .scaledToFit() + .foregroundColor(Color(UIColor.systemGray)) + } + Spacer() + } + .contentShape(Rectangle()) + .onTapGesture { + NextcloudKit.shared.deleteE2EEPrivateKey { _, error in + if error == .success { + NCContentPresenter().messageNotification("E2E delete privateKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .success) + } else { + NCContentPresenter().messageNotification("E2E delete privateKey", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .error) + } + } + } + } + } +} + +// MARK: - Preview / Test + +struct SectionView: View { + + @State var height: CGFloat = 0 + @State var text: String = "" + + var body: some View { + HStack { + Text(text) + } + .frame(maxWidth: .infinity, minHeight: height, alignment: .bottomLeading) + } +} + +struct NCViewE2EETest: View { + + var body: some View { + + VStack { + List { + Section(header: SectionView(height: 50, text: "Section Header View")) { + Label { + Text(NSLocalizedString("_e2e_settings_activated_", comment: "")) + } icon: { + Image(systemName: "checkmark.circle.fill") + .resizable() + .scaledToFit() + .frame(width: 25, height: 25) + .foregroundColor(.green) + } + } + Section(header: SectionView(text: "Section Header View 42")) { + Label { + Text(NSLocalizedString("_e2e_settings_activated_", comment: "")) + } icon: { + Image(systemName: "checkmark.circle.fill") + .resizable() + .scaledToFit() + .frame(width: 25, height: 25) + .foregroundColor(.red) + } + } + } + } + } +} + +struct NCViewE2EE_Previews: PreviewProvider { + static var previews: some View { + + // swiftlint:disable force_cast + let account = (UIApplication.shared.delegate as! AppDelegate).account + NCViewE2EE(account: account) + // swiftlint:enable force_cast + } +} diff --git a/iOSClient/Settings/NCSettings.h b/iOSClient/Settings/NCSettings.h new file mode 100644 index 0000000000..e06a29f1ac --- /dev/null +++ b/iOSClient/Settings/NCSettings.h @@ -0,0 +1,33 @@ +// +// NCSettings.h +// Nextcloud +// +// Created by Marino Faggiana on 24/11/14. +// Copyright (c) 2014 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +#import +#import +#import +#import "CCUtility.h" + +@interface NCSettings : XLFormViewController + +- (void)reloadForm; + +@end diff --git a/iOSClient/Settings/NCSettings.m b/iOSClient/Settings/NCSettings.m new file mode 100644 index 0000000000..62abc39c87 --- /dev/null +++ b/iOSClient/Settings/NCSettings.m @@ -0,0 +1,436 @@ +// +// NCSettings.m +// Nextcloud +// +// Created by Marino Faggiana on 24/11/14. +// Copyright (c) 2014 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +#import "NCSettings.h" +#import "CCAdvanced.h" +#import "CCManageAccount.h" +#import "CCManageAutoUpload.h" +#import "NCBridgeSwift.h" +#import +#import +//#import + +#define alertViewEsci 1 +#define alertViewAzzeraCache 2 + +@interface NCSettings () +{ + AppDelegate *appDelegate; + TOPasscodeViewController *passcodeViewController; + TOPasscodeSettingsViewController *passcodeSettingsViewController; + + NSString *versionServer; + NSString *themingName; + NSString *themingSlogan; +} +@end + +@implementation NCSettings + +- (void)initializeForm +{ + XLFormDescriptor *form = [XLFormDescriptor formDescriptor]; + XLFormSectionDescriptor *section; + XLFormRowDescriptor *row; + + form.rowNavigationOptions = XLFormRowNavigationOptionNone; + + // Section AUTO UPLOAD OF CAMERA IMAGES ---------------------------- + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"autoUpload" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_settings_autoupload_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"autoUpload"] imageWithColor:NCBrandColor.shared.iconImageColor size:25] forKey:@"imageView.image"]; + row.action.viewControllerClass = [CCManageAutoUpload class]; + [section addFormRow:row]; + + // Section : SECURITY -------------------------------------------------------------- + + section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_security_", nil)]; + [form addFormSection:section]; + + // Lock active YES/NO + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"bloccopasscode" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_lock_not_active_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[[UIImage imageNamed:@"lock_open"] imageWithColor:NCBrandColor.shared.iconImageColor size:25] forKey:@"imageView.image"]; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + //[row.cellConfig setObject:@(UITableViewCellAccessoryDisclosureIndicator) forKey:@"accessoryType"]; + row.action.formSelector = @selector(passcode:); + [section addFormRow:row]; + // Enable Touch ID + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"enableTouchDaceID" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_enable_touch_face_id_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.cellConfig[@"switchControl.onTintColor"] = NCBrandColor.shared.brand; + if([[NCKeychain alloc] init].passcode){ + row.disabled = @NO; + }else{ + row.disabled = @YES; + } + [section addFormRow:row]; + + // Section : E2EEncryption -------------------------------------------------------------- + + BOOL isE2EEEnabled = [[NCGlobal shared] capabilityE2EEEnabled]; + NSString *versionE2EE = [[NCGlobal shared] capabilityE2EEApiVersion]; + + if (isE2EEEnabled == YES && [NCGlobal.shared.e2eeVersions containsObject:versionE2EE]) { + + // EndToEnd Encryption + NSString *title = [NSString stringWithFormat:@"%@",NSLocalizedString(@"_e2e_settings_", nil)]; + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"e2eEncryption" rowType:XLFormRowDescriptorTypeButton title:title]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"lock"] imageWithColor:NCBrandColor.shared.iconImageColor size:25] forKey:@"imageView.image"]; + row.action.formSelector = @selector(manageE2EE:); + [section addFormRow:row]; + } + + // Section Advanced ------------------------------------------------- + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + // Advanced + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"advanced" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_advanced_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:[[UIImage imageNamed:@"gear"] imageWithColor:NCBrandColor.shared.iconImageColor size:25] forKey:@"imageView.image"]; + row.action.viewControllerClass = [CCAdvanced class]; + [section addFormRow:row]; + + // Section : DATA PROTECTION ------------------------------------------------ + + section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_data_protection_", nil)]; + [form addFormSection:section]; + + // Privacy Settings + PrivacySettingsViewController *privacySettingsViewController = [[PrivacySettingsViewController alloc] init]; + privacySettingsViewController.isShowSettingsButton = true; + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"showSettingsButton"]; + [[NSUserDefaults standardUserDefaults] synchronize]; + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"privacySettings" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_privacy_settings_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.action.viewControllerClass = [privacySettingsViewController class]; + [section addFormRow:row]; + + // Privacy Policy + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"advanced" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_privacy_policy_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + row.action.viewControllerClass = [PrivacyPolicyViewController class]; + [section addFormRow:row]; + + // Used OpenSource Software + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"buttonLeftAligned" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_used_opensource_software_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.action.viewControllerClass = [OpenSourceSoftwareViewController class]; + [section addFormRow:row]; + + + // Section : SERVICE ------------------------------------------------ + + section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_service_", nil)]; + [form addFormSection:section]; + + // HELP + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"buttonLeftAligned" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_help_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.action.viewControllerClass = [HelpViewController class]; + [section addFormRow:row]; + + // Imprint + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"buttonLeftAligned" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_imprint_", nil)]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; + [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; + row.action.viewControllerClass = [ImprintViewController class]; + [section addFormRow:row]; + + // Section : INFO ------------------------------------------------ + + section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_info_", nil)]; + [form addFormSection:section]; + + //MagentaCloud Version + + //custom cell + + [[XLFormViewController cellClassesForRowDescriptorTypes] setObject:[MagentaCloudVersionView class] forKey:@"kNMCCustomCellType"]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"disablefilesapp" rowType:@"kNMCCustomCellType" title:NSLocalizedString(@"_magentacloud_version_", nil)]; + NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleInfoDictionaryVersion"]; + row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; + row.cellConfigAtConfigure[@"cellLabel.text"] = NSLocalizedString(@"_magentacloud_version_", nil); + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"cellLabel.font"]; + [row.cellConfig setObject:UIColor.labelColor forKey:@"cellLabel.textColor"]; + row.cellConfigAtConfigure[@"versionLabel.text"] = appVersion; + [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"versionLabel.font"]; + [row.cellConfig setObject:UIColor.systemGrayColor forKey:@"versionLabel.textColor"]; + [section addFormRow:row]; + + self.tableView.showsVerticalScrollIndicator = NO; + self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 35, 0); + self.form = form; +} + +// MARK: - View Life Cycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.title = NSLocalizedString(@"_settings_", nil); + self.view.backgroundColor = UIColor.systemGroupedBackgroundColor; + self.tableView.backgroundColor = UIColor.systemGroupedBackgroundColor; + appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground) name:NCGlobal.shared.notificationCenterApplicationDidEnterBackground object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeUser) name:NCGlobal.shared.notificationCenterInitialize object:nil]; + + [self initializeForm]; + [self reloadForm]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + appDelegate.activeViewController = self; + + versionServer = [[NCGlobal shared] capabilityServerVersion]; + themingName = [[NCGlobal shared] capabilityThemingName]; + themingSlogan = [[NCGlobal shared] capabilityThemingSlogan]; +} + +#pragma mark - NotificationCenter + +- (void)changeUser +{ + [self initializeForm]; + [self reloadForm]; +} + +- (void)applicationDidEnterBackground +{ + if (passcodeViewController.view.window != nil) { + [passcodeViewController dismissViewControllerAnimated:true completion:nil]; + } + if (passcodeSettingsViewController.view.window != nil) { + [passcodeSettingsViewController dismissViewControllerAnimated:true completion:nil]; + } + + [[self navigationController] popToRootViewControllerAnimated:false]; +} + +#pragma mark - + +- (void)reloadForm +{ + self.form.delegate = nil; + + // ------------------------------------------------------------------ + + XLFormRowDescriptor *rowBloccoPasscode = [self.form formRowWithTag:@"bloccopasscode"]; + XLFormRowDescriptor *rowNotPasscodeAtStart = [self.form formRowWithTag:@"notPasscodeAtStart"]; + XLFormRowDescriptor *rowEnableTouchDaceID = [self.form formRowWithTag:@"enableTouchDaceID"]; + + // ------------------------------------------------------------------ + + if ([[NCKeychain alloc] init].passcode) { + rowBloccoPasscode.title = NSLocalizedString(@"_lock_active_", nil); + [rowBloccoPasscode.cellConfig setObject:[[UIImage imageNamed:@"lock"] imageWithColor:NCBrandColor.shared.iconImageColor size:25] forKey:@"imageView.image"]; + rowEnableTouchDaceID.disabled = @NO; + rowNotPasscodeAtStart.disabled = @NO; + } else { + rowBloccoPasscode.title = NSLocalizedString(@"_lock_not_active_", nil); + [rowBloccoPasscode.cellConfig setObject:[[UIImage imageNamed:@"lock_open"] imageWithColor:NCBrandColor.shared.iconImageColor size:25] forKey:@"imageView.image"]; + rowEnableTouchDaceID.disabled = @YES; + rowNotPasscodeAtStart.disabled = @YES; + } + + if ([[NCKeychain alloc] init].touchFaceID) [rowEnableTouchDaceID setValue:@1]; else [rowEnableTouchDaceID setValue:@0]; + if ([[NCKeychain alloc] init].requestPasscodeAtStart) [rowNotPasscodeAtStart setValue:@0]; else [rowNotPasscodeAtStart setValue:@1]; + + + // ----------------------------------------------------------------- + + [self.tableView reloadData]; + + self.form.delegate = self; +} + +- (void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)rowDescriptor oldValue:(id)oldValue newValue:(id)newValue +{ + [super formRowDescriptorValueHasChanged:rowDescriptor oldValue:oldValue newValue:newValue]; + + if ([rowDescriptor.tag isEqualToString:@"notPasscodeAtStart"]) { + + if ([[rowDescriptor.value valueData] boolValue] == YES) { + [[NCKeychain alloc] init].requestPasscodeAtStart = false; + } else { + [[NCKeychain alloc] init].requestPasscodeAtStart = true; + } + } + + if ([rowDescriptor.tag isEqualToString:@"enableTouchDaceID"]) { + + if ([[rowDescriptor.value valueData] boolValue] == YES) { + [[NCKeychain alloc] init].touchFaceID = true; + } else { + [[NCKeychain alloc] init].touchFaceID = false; + } + } +} + +#pragma mark - + +- (void)manageE2EE:(XLFormRowDescriptor *)sender +{ + [self deselectFormRow:sender]; + + UIViewController *vc = [[NCManageE2EEInterface alloc] makeShipDetailsUIWithAccount:appDelegate.account]; + [self.navigationController pushViewController:vc animated:YES]; +} + +#pragma mark - Passcode + +- (void)didPerformBiometricValidationRequestInPasscodeViewController:(TOPasscodeViewController *)passcodeViewController +{ + [[LAContext new] evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:[[NCBrandOptions shared] brand] reply:^(BOOL success, NSError * _Nullable error) { + if (success) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) { + [[NCKeychain alloc] init].passcode = nil; + [passcodeViewController dismissViewControllerAnimated:YES completion:nil]; + [self reloadForm]; + }); + } + }]; +} + +- (void)passcodeSettingsViewController:(TOPasscodeSettingsViewController *)passcodeSettingsViewController didChangeToNewPasscode:(NSString *)passcode ofType:(TOPasscodeType)type +{ + [[NCKeychain alloc] init].passcode = passcode; + [passcodeSettingsViewController dismissViewControllerAnimated:YES completion:nil]; + + [self reloadForm]; +} + +- (void)didTapCancelInPasscodeViewController:(TOPasscodeViewController *)passcodeViewController +{ + [passcodeViewController dismissViewControllerAnimated:YES completion:nil]; +} + +- (BOOL)passcodeViewController:(TOPasscodeViewController *)passcodeViewController isCorrectCode:(NSString *)code +{ + if ([code isEqualToString:[[NCKeychain alloc] init].passcode]) { + [[NCKeychain alloc] init].passcode = nil; + [self reloadForm]; + + return YES; + } + + return NO; +} + +- (void)passcode:(XLFormRowDescriptor *)sender +{ + LAContext *laContext = [LAContext new]; + NSError *error; + + [self deselectFormRow:sender]; + + if ([[NCKeychain alloc] init].passcode) { + + passcodeViewController = [[TOPasscodeViewController alloc] initPasscodeType:TOPasscodeTypeSixDigits allowCancel:true]; + passcodeViewController.delegate = self; + passcodeViewController.keypadButtonShowLettering = false; + + if ([[NCKeychain alloc] init].touchFaceID && [laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) { + if (error == NULL) { + if (laContext.biometryType == LABiometryTypeFaceID) { + passcodeViewController.biometryType = TOPasscodeBiometryTypeFaceID; + passcodeViewController.allowBiometricValidation = true; + passcodeViewController.automaticallyPromptForBiometricValidation = true; + } else if (laContext.biometryType == LABiometryTypeTouchID) { + passcodeViewController.biometryType = TOPasscodeBiometryTypeTouchID; + passcodeViewController.allowBiometricValidation = true; + passcodeViewController.automaticallyPromptForBiometricValidation = true; + } else { + NSLog(@"No Biometric support"); + } + } + } + + [self presentViewController:passcodeViewController animated:YES completion:nil]; + + } else { + + passcodeSettingsViewController = [[TOPasscodeSettingsViewController alloc] init]; + passcodeSettingsViewController.hideOptionsButton = YES; + passcodeSettingsViewController.requireCurrentPasscode = NO; + passcodeSettingsViewController.passcodeType = TOPasscodeTypeSixDigits; + passcodeSettingsViewController.delegate = self; + + [self presentViewController:passcodeSettingsViewController animated:YES completion:nil]; + } +} + +#pragma mark - + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return NCGlobal.shared.heightCellSettings; +} + +- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section +{ + NSString *sectionName; + NSInteger numSections = [tableView numberOfSections] - 1; + + return sectionName; +} + +@end diff --git a/iOSClient/Settings/NCSettings.storyboard b/iOSClient/Settings/NCSettings.storyboard new file mode 100644 index 0000000000..19a320515b --- /dev/null +++ b/iOSClient/Settings/NCSettings.storyboard @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Settings/NCSettingsBundleHelper.swift b/iOSClient/Settings/NCSettingsBundleHelper.swift index c169d58bc1..8b0169890f 100644 --- a/iOSClient/Settings/NCSettingsBundleHelper.swift +++ b/iOSClient/Settings/NCSettingsBundleHelper.swift @@ -1,6 +1,25 @@ -// SPDX-FileCopyrightText: Nextcloud GmbH -// SPDX-FileCopyrightText: 2021 Marino Faggiana -// SPDX-License-Identifier: GPL-3.0-or-later +// +// NCSettingsBundleHelper.swift +// Nextcloud +// +// Created by Marino Faggiana on 17/02/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// import Foundation import UIKit diff --git a/iOSClient/Settings/OpenSourceSoftwareViewController.swift b/iOSClient/Settings/OpenSourceSoftwareViewController.swift new file mode 100644 index 0000000000..e4cd131f83 --- /dev/null +++ b/iOSClient/Settings/OpenSourceSoftwareViewController.swift @@ -0,0 +1,56 @@ +// +// OpenSourceSoftwareViewController.swift +// Nextcloud +// +// Created by A200073704 on 11/05/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import UIKit +import WebKit + +class OpenSourceSoftwareViewController: UIViewController, WKNavigationDelegate, WKUIDelegate { + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view, typically from a nib. + + self.title = NSLocalizedString("_used_opensource_software_", comment: "") + let myWebView:WKWebView = WKWebView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.width, height:UIScreen.main.bounds.height)) + myWebView.uiDelegate = self + myWebView.navigationDelegate = self + myWebView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + self.view.addSubview(myWebView) + + + //1. Load web site into my web view + let myURL = URL(string: "https://static.magentacloud.de/licences/ios.html") + let myURLRequest:URLRequest = URLRequest(url: myURL!) + NCActivityIndicator.shared.start() + myWebView.load(myURLRequest) + + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + NCActivityIndicator.shared.stop() + } + + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + if navigationAction.navigationType == .linkActivated { + if let url = navigationAction.request.url, + UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url) + decisionHandler(.cancel) + } else { + decisionHandler(.allow) + } + } else { + decisionHandler(.allow) + } + } +} diff --git a/iOSClient/Settings/PrivacyPolicyViewController.swift b/iOSClient/Settings/PrivacyPolicyViewController.swift new file mode 100644 index 0000000000..141c444fca --- /dev/null +++ b/iOSClient/Settings/PrivacyPolicyViewController.swift @@ -0,0 +1,62 @@ +// +// PrivacyPolicyViewController.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import Foundation +import UIKit +import WebKit + +class PrivacyPolicyViewController: UIViewController, WKNavigationDelegate, WKUIDelegate { + + var myWebView = WKWebView() + + override func viewDidLoad() { + super.viewDidLoad() + + self.title = NSLocalizedString("_privacy_policy_", comment: "") + + myWebView = WKWebView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.width, height:UIScreen.main.bounds.height)) + myWebView.uiDelegate = self + myWebView.navigationDelegate = self + myWebView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + self.view.addSubview(myWebView) + + //1. Load web site into my web view + let myURL = URL(string: "https://static.magentacloud.de/privacy/datenschutzhinweise_app.htm") + let myURLRequest:URLRequest = URLRequest(url: myURL!) + NCActivityIndicator.shared.start() + myWebView.load(myURLRequest) + self.navigationController?.navigationBar.tintColor = NCBrandColor.shared.brand + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + myWebView = WKWebView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.width, height:UIScreen.main.bounds.height)) + } + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + NCActivityIndicator.shared.stop() + } + + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + if navigationAction.navigationType == .linkActivated { + if let url = navigationAction.request.url, + UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url) + decisionHandler(.cancel) + } else { + decisionHandler(.allow) + } + } else { + decisionHandler(.allow) + } + } +} diff --git a/iOSClient/Settings/PrivacySettingsViewController.swift b/iOSClient/Settings/PrivacySettingsViewController.swift new file mode 100644 index 0000000000..757d5532d5 --- /dev/null +++ b/iOSClient/Settings/PrivacySettingsViewController.swift @@ -0,0 +1,148 @@ +// +// PrivacySettingsViewController.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import Foundation +import AppTrackingTransparency +import AdSupport +import XLForm + +class PrivacySettingsViewController: XLFormViewController{ + + @objc public var isShowSettingsButton: Bool = false + + override func viewDidLoad() { + super.viewDidLoad() + self.title = NSLocalizedString("_privacy_settings_title_", comment: "") + + NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil) + + let nib = UINib(nibName: "CustomSectionHeader", bundle: nil) + self.tableView.register(nib, forHeaderFooterViewReuseIdentifier: "customSectionHeader") + isShowSettingsButton = UserDefaults.standard.bool(forKey: "showSettingsButton") + self.navigationController?.navigationBar.tintColor = NCBrandColor.shared.brand + changeTheming() + } + + @objc func changeTheming() { + tableView.backgroundColor = .systemGroupedBackground + tableView.separatorColor = .none + tableView.separatorColor = .clear + tableView.reloadData() + initializeForm() + } + + + + //MARK: XLForm + + func initializeForm() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + // Section: Destination Folder + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("", comment: "").uppercased()) + section.footerTitle = " " + form.addFormSection(section) + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("", comment: "").uppercased()) + section.footerTitle = NSLocalizedString("_privacy_settings_help_text_", comment: "") + form.addFormSection(section) + + + //custom cell + section = XLFormSectionDescriptor.formSection(withTitle: "") + section.footerTitle = NSLocalizedString("_required_data_collection_help_text_", comment: "") + form.addFormSection(section) + + + XLFormViewController.cellClassesForRowDescriptorTypes()["RequiredDataCollectionCustomCellType"] = RequiredDataCollectionSwitch.self + + + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: "RequiredDataCollectionCustomCellType", title: "") + row.cellConfig["requiredDataCollectionSwitchControl.onTintColor"] = NCBrandColor.shared.brand + row.cellConfig["cellLabel.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["cellLabel.textColor"] = UIColor.label //photos + row.cellConfig["cellLabel.text"] = NSLocalizedString("_required_data_collection_", comment: "") + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("", comment: "").uppercased()) + section.footerTitle = NSLocalizedString("_analysis_data_acqusition_help_text_", comment: "") + form.addFormSection(section) + + XLFormViewController.cellClassesForRowDescriptorTypes()["AnalysisDataCollectionCustomCellType"] = AnalysisDataCollectionSwitch.self + + + row = XLFormRowDescriptor(tag: "AnalysisDataCollectionSwitch", rowType: "AnalysisDataCollectionCustomCellType", title: "") + row.cellConfig["analysisDataCollectionSwitchControl.onTintColor"] = NCBrandColor.shared.brand + row.cellConfig["cellLabel.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["cellLabel.textColor"] = UIColor.label //photos + row.cellConfig["cellLabel.text"] = NSLocalizedString("_analysis_data_acqusition_", comment: "") + if(UserDefaults.standard.bool(forKey: "isAnalysisDataCollectionSwitchOn")){ + row.cellConfigAtConfigure["analysisDataCollectionSwitchControl.on"] = 1 + }else { + row.cellConfigAtConfigure["analysisDataCollectionSwitchControl.on"] = 0 + } + + section.addFormRow(row) + + + XLFormViewController.cellClassesForRowDescriptorTypes()["SaveSettingsButton"] = SaveSettingsCustomButtonCell.self + + section = XLFormSectionDescriptor.formSection(withTitle: "") + form.addFormSection(section) + + + row = XLFormRowDescriptor(tag: "SaveSettingsButton", rowType: "SaveSettingsButton", title: "") + row.cellConfig["backgroundColor"] = UIColor.clear + + if(isShowSettingsButton){ + 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 == "SaveSettingsButton" { + print("save settings clicked") + //TODO save button state and leave the page + self.navigationController?.popViewController(animated: true) + + } + if formRow.tag == "AnalysisDataCollectionSwitch"{ + if (formRow.value! as AnyObject).boolValue { + if #available(iOS 14, *) { + ATTrackingManager.requestTrackingAuthorization(completionHandler: { (status) in + if status == .denied { + guard let url = URL(string: UIApplication.openSettingsURLString) else { + return + } + if UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url, options: [:]) + } + } + }) + } + } + UserDefaults.standard.set((formRow.value! as AnyObject).boolValue, forKey: "isAnalysisDataCollectionSwitchOn") + } + + } + +} diff --git a/iOSClient/Settings/RequiredDataCollectionSwitch.swift b/iOSClient/Settings/RequiredDataCollectionSwitch.swift new file mode 100644 index 0000000000..0d5a34732f --- /dev/null +++ b/iOSClient/Settings/RequiredDataCollectionSwitch.swift @@ -0,0 +1,34 @@ +// +// RequiredDataCollectionSwitch.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import UIKit +import XLForm + +class RequiredDataCollectionSwitch: XLFormBaseCell { + + @IBOutlet weak var cellLabel: UILabel! + @IBOutlet weak var requiredDataCollectionSwitchControl: UISwitch! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + //requiredDataCollectionSwitchControl.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged) + + } + + override func configure() { + super.configure() + + requiredDataCollectionSwitchControl.isOn = true + requiredDataCollectionSwitchControl.isEnabled = false + } + + override func update() { + super.update() + } +} diff --git a/iOSClient/Settings/RequiredDataCollectionSwitch.xib b/iOSClient/Settings/RequiredDataCollectionSwitch.xib new file mode 100644 index 0000000000..66156c6e06 --- /dev/null +++ b/iOSClient/Settings/RequiredDataCollectionSwitch.xib @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Settings/SaveSettingsCustomButtonCell.swift b/iOSClient/Settings/SaveSettingsCustomButtonCell.swift new file mode 100644 index 0000000000..1332b1f92a --- /dev/null +++ b/iOSClient/Settings/SaveSettingsCustomButtonCell.swift @@ -0,0 +1,47 @@ +// +// SaveSettingsCustomButtonCell.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import UIKit +import XLForm + + +class SaveSettingsCustomButtonCell: XLFormButtonCell { + + @IBOutlet weak var saveSettingsButton: UIButton! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + self.selectionStyle = .none + self.separatorInset = UIEdgeInsets(top: 0, left: .greatestFiniteMagnitude, bottom: 0, right: .greatestFiniteMagnitude) + saveSettingsButton.setTitle(NSLocalizedString("_save_settings_", comment: ""), for: .normal) + saveSettingsButton.addTarget(self, action: #selector(saveButtonClicked), for: .touchUpInside) + + } + + override func configure() { + super.configure() + saveSettingsButton.backgroundColor = NCBrandColor.shared.brand + saveSettingsButton.tintColor = UIColor.white + saveSettingsButton.layer.cornerRadius = 5 + saveSettingsButton.layer.borderWidth = 1 + saveSettingsButton.layer.borderColor = NCBrandColor.shared.brand.cgColor + + } + + override func update() { + super.update() + + } + + @objc func saveButtonClicked(sender: UIButton) { + self.rowDescriptor.value = sender + + } + +} diff --git a/iOSClient/Settings/SaveSettingsCustomButtonCell.xib b/iOSClient/Settings/SaveSettingsCustomButtonCell.xib new file mode 100644 index 0000000000..0dd197da31 --- /dev/null +++ b/iOSClient/Settings/SaveSettingsCustomButtonCell.xib @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Settings/Settings.bundle/Root.plist b/iOSClient/Settings/Settings.bundle/Root.plist new file mode 100644 index 0000000000..1184bfbc77 --- /dev/null +++ b/iOSClient/Settings/Settings.bundle/Root.plist @@ -0,0 +1,31 @@ + + + + + StringsTable + Root + PreferenceSpecifiers + + + Type + PSToggleSwitchSpecifier + Title + _reset_application_ + Key + reset_application + DefaultValue + + + + Type + PSTitleValueSpecifier + Title + _version_ + Key + version_preference + DefaultValue + 0 + + + + diff --git a/iOSClient/Settings/Settings.bundle/en.lproj/Root.strings b/iOSClient/Settings/Settings.bundle/en.lproj/Root.strings new file mode 100644 index 0000000000..6b57b356ce Binary files /dev/null and b/iOSClient/Settings/Settings.bundle/en.lproj/Root.strings differ diff --git a/iOSClient/Share/NCShareEmailFieldCell.swift b/iOSClient/Share/NCShareEmailFieldCell.swift new file mode 100644 index 0000000000..48cdcb1774 --- /dev/null +++ b/iOSClient/Share/NCShareEmailFieldCell.swift @@ -0,0 +1,188 @@ +// +// NCShareEmailFieldCell.swift +// Nextcloud +// +// Created by A200020526 on 01/06/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import UIKit +import MarqueeLabel +import NextcloudKit + +enum Tag { + static let searchField = 999 +} + +class NCShareEmailFieldCell: UITableViewCell { + + @IBOutlet weak var searchField: UITextField! + @IBOutlet weak var labelOrLink: UILabel! + @IBOutlet weak var btnContact: UIButton! + @IBOutlet weak var labelSeparator1: UILabel! + @IBOutlet weak var labelSeparator2: UILabel! + @IBOutlet weak var labelSendLinkByMail: UILabel! + @IBOutlet weak var labelSharedWithBy: UILabel! + @IBOutlet weak var labelResharingAllowed: UILabel! + @IBOutlet weak var topConstraintResharingView: NSLayoutConstraint! + @IBOutlet weak var viewOrLinkSeparator: UIView! + + var ocId = "" + + override func awakeFromNib() { + super.awakeFromNib() + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + if previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle { + setupCellAppearance() + } + } + + func setupCell(with metadata: tableMetadata) { +// contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground + ocId = metadata.ocId + + setupCellAppearance() + updateCanReshareUI() + + setNeedsLayout() + layoutIfNeeded() + } + + func setupCellAppearance() { + configureSearchField() + configureContactButton() + configureLabels() + } + + private func configureSearchField() { + searchField.layer.cornerRadius = 5 + searchField.layer.masksToBounds = true + searchField.layer.borderWidth = 1 + searchField.layer.borderColor = NCBrandColor.shared.label.cgColor + searchField.text = "" + searchField.textColor = NCBrandColor.shared.label + searchField.attributedPlaceholder = NSAttributedString( + string: NSLocalizedString("_shareLinksearch_placeholder_", comment: ""), + attributes: [.foregroundColor: NCBrandColor.shared.gray60] + ) + searchField.tag = Tag.searchField + setDoneButton(sender: searchField) + } + + private func configureContactButton() { + btnContact.layer.cornerRadius = 5 + btnContact.layer.masksToBounds = true + btnContact.layer.borderWidth = 1 + btnContact.layer.borderColor = NCBrandColor.shared.label.cgColor + if let image = UIImage(named: "Contacts")?.withRenderingMode(.alwaysTemplate) { + btnContact.setImage(image, for: .normal) + } + btnContact.tintColor = NCBrandColor.shared.label + + } + + private func configureLabels() { + labelOrLink.text = NSLocalizedString("_share_or_", comment: "") + labelSendLinkByMail.text = NSLocalizedString("_share_send_link_by_mail_", comment: "") + labelSharedWithBy.text = NSLocalizedString("_share_received_shares_text_", comment: "") + labelResharingAllowed.text = NSLocalizedString("_share_reshare_allowed_", comment: "") + + labelSendLinkByMail.textColor = NCBrandColor.shared.label + labelSharedWithBy.textColor = NCBrandColor.shared.label + labelResharingAllowed.textColor = NCBrandColor.shared.label + } + + func updateCanReshareUI() { + guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return } + + let isCurrentUser = NCShareCommon.isCurrentUserIsFileOwner(fileOwnerId: metadata.ownerId) + let canReshare = (metadata.sharePermissionsCollaborationServices & NCPermissions().permissionShareShare) != 0 + + labelSharedWithBy.isHidden = isCurrentUser + labelResharingAllowed.isHidden = isCurrentUser + + if !canReshare { + searchField.isUserInteractionEnabled = false + searchField.alpha = 0.5 + btnContact.isEnabled = false + btnContact.alpha = 0.5 + } + + if !isCurrentUser { + let ownerName = metadata.ownerDisplayName + let fullText = NSLocalizedString("_share_received_shares_text_", comment: "") + " " + ownerName + let attributed = NSMutableAttributedString(string: fullText) + + if let range = fullText.range(of: ownerName) { + let nsRange = NSRange(range, in: fullText) + attributed.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: 16), range: nsRange) + } + + labelSharedWithBy.attributedText = attributed + labelSharedWithBy.numberOfLines = 0 + + labelResharingAllowed.text = canReshare + ? NSLocalizedString("_share_reshare_allowed_", comment: "") + : NSLocalizedString("_share_reshare_not_allowed_", comment: "") + + topConstraintResharingView.constant = 15 + } else { + topConstraintResharingView.constant = 0 + } + + viewOrLinkSeparator.isHidden = !canReshare + } + + func updateShareUI(ocId: String, count: Int) { + guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return } + + let isCurrentUser = NCShareCommon.isCurrentUserIsFileOwner(fileOwnerId: metadata.ownerId) + let canReshare = (metadata.sharePermissionsCollaborationServices & NCPermissions().permissionShareShare) != 0 + + if !isCurrentUser { + if canReshare { + labelOrLink.isHidden = true + labelSeparator1.isHidden = true + labelSeparator2.isHidden = true + } + } + } + + @objc func cancelDatePicker() { + self.searchField.endEditing(true) + } + + private func setDoneButton(sender: UITextField) { + let toolbar = UIToolbar() + toolbar.sizeToFit() + let doneButton = UIBarButtonItem( + title: NSLocalizedString("_done_", comment: ""), + style: .plain, + target: self, + action: #selector(cancelDatePicker) + ) + let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) + toolbar.setItems([space, doneButton], animated: false) + sender.inputAccessoryView = toolbar + } + + @IBAction func touchUpInsideFavorite(_ sender: UIButton) { + // Hook for favorite action if needed + } + + @IBAction func touchUpInsideDetails(_ sender: UIButton) { + // Hook for toggling detail visibility if needed + } + + @objc func longTap(_ sender: UIGestureRecognizer) { + let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_copied_path_") + NCContentPresenter().showInfo(error: error) + } +} diff --git a/iOSClient/Share/NCShareEmailFieldCell.xib b/iOSClient/Share/NCShareEmailFieldCell.xib new file mode 100644 index 0000000000..8384397621 --- /dev/null +++ b/iOSClient/Share/NCShareEmailFieldCell.xib @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Share/ShareDownloadLimitNetwork.swift b/iOSClient/Share/ShareDownloadLimitNetwork.swift new file mode 100644 index 0000000000..06858464bf --- /dev/null +++ b/iOSClient/Share/ShareDownloadLimitNetwork.swift @@ -0,0 +1,156 @@ +// +// ShareDownloadLimitNetwork.swift +// Nextcloud +// +// Created by A118830248 on 11/11/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation +import SwiftyJSON +import NextcloudKit +import Alamofire + +class NMCCommunication: NSObject, XMLParserDelegate { + + public static let shared: NMCCommunication = { + let instance = NMCCommunication() + return instance + }() + + var message = "" + var foundCharacters = ""; + var downloadLimit = DownloadLimit() + private lazy var appDelegate = UIApplication.shared.delegate as? AppDelegate + var controller: NCMainTabBarController! + var session: NCSession.Session { + NCSession.shared.getSession(controller: controller) + } + + func getDownloadLimit(token: String, completion: @escaping (_ downloadLimit: DownloadLimit?, _ errorDescription: String) -> Void) { + let baseUrl = session.urlBase // NCBrandOptions.shared.loginBaseUrl + + func getDownloadLimit(token: String, completion: @escaping (_ downloadLimit: DownloadLimit?, _ errorDescription: String) -> Void) { + let baseUrl = session.urlBase // NCBrandOptions.shared.loginBaseUrl + let endPoint = "/ocs/v2.php/apps/files_downloadlimit/\(token)/limit" + let path = baseUrl+endPoint + do { + var urlRequest = try URLRequest(url: URL(string: path)!, method: .get) + urlRequest.addValue("true", forHTTPHeaderField: "OCS-APIREQUEST") + + let sessionConfiguration = URLSessionConfiguration.default + let urlSession = URLSession(configuration: sessionConfiguration) + + let task = urlSession.dataTask(with: urlRequest) { [self] (data, response, error) in + guard error == nil else { + completion(nil, error?.localizedDescription ?? "") + return + } + + if let httpResponse = response as? HTTPURLResponse { + let statusCode = httpResponse.statusCode + print("url: \(String(describing: httpResponse.url))\nStatus Code: \(statusCode)") + if httpResponse.statusCode == 200 { + let parser = XMLParser(data: data!) + parser.delegate = self + parser.parse() + completion(self.downloadLimit, self.message) + } else { + completion(nil, "Invalid Response code: \(statusCode)") + } + } else { + completion(nil, error?.localizedDescription ?? "Invalid Response") + } + } + task.resume() + } catch { + completion(nil, error.localizedDescription) + } + } + + func setDownloadLimit(deleteLimit: Bool, limit: String, token: String, completion: @escaping (_ success: Bool, _ errorDescription: String) -> Void) { + let baseUrl = session.urlBase //NCBrandOptions.shared.loginBaseUrl + let baseUrl = appDelegate?.urlBase ?? "" //NCBrandOptions.shared.loginBaseUrl + let endPoint = "/ocs/v2.php/apps/files_downloadlimit/\(token)/limit" + let path = baseUrl+endPoint + do { + + let method = deleteLimit ? HTTPMethod.delete : .put + var urlRequest = try URLRequest(url: URL(string: path)!, method: method) + + urlRequest.addValue("true", forHTTPHeaderField: "OCS-APIREQUEST") + urlRequest.addValue(authorizationToken(), forHTTPHeaderField: "Authorization") + urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type") + + let parameters = ["token": token, "limit": limit] + + let encoder = JSONEncoder() + let jsonData = try encoder.encode(parameters) + urlRequest.httpBody = jsonData + + let sessionConfiguration = URLSessionConfiguration.default + let urlSession = URLSession(configuration: sessionConfiguration) + + let task = urlSession.dataTask(with: urlRequest) { (data, response, error) in + guard error == nil else { + completion(false, error?.localizedDescription ?? "") + return + } + + if let httpResponse = response as? HTTPURLResponse { + let statusCode = httpResponse.statusCode + print("url: \(String(describing: httpResponse.url))\nStatus Code: \(statusCode)") + if httpResponse.statusCode == 200 { + completion(true, error?.localizedDescription ?? "") + } else { + completion(false, "Invalid Response code: \(statusCode)") + } + } else { + completion(false, error?.localizedDescription ?? "Invalid Response") + } + } + task.resume() + } catch { + completion(false, error.localizedDescription) + } + } + + public func authorizationToken() -> String { + let accountDetails = NCManageDatabase.shared.getAllTableAccount().first + let accountDetails = NCManageDatabase.shared.getAllAccount().first + let password = NCKeychain().getPassword(account: accountDetails?.account ?? "") + let password = NCKeychain().getPassword(account: accountDetails?.account ?? "") + let username = accountDetails?.user ?? "" + let credential = Data("\(username):\(password)".utf8).base64EncodedString() + return ("Basic \(credential)") + } + + + // MARK:- XML Parser Delegate + public func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { + + } + public func parser(_ parser: XMLParser, foundCharacters string: String) { + self.foundCharacters += string; + } + + public func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { + if elementName == "limit" { + let limit = self.foundCharacters.replacingOccurrences(of: "\n", with: "") + self.downloadLimit.limit = Int(limit.trimmingCharacters(in: .whitespaces)) + } + if elementName == "count" { + let count = self.foundCharacters.replacingOccurrences(of: "\n", with: "") + self.downloadLimit.count = Int(count.trimmingCharacters(in: .whitespaces)) + } + if elementName == "message"{ + self.message = self.foundCharacters + } + self.foundCharacters = "" + } +} + +//struct DownloadLimit: Codable { +// var limit: Int? +// var count: Int? +//}