From a37b32f0d0ac06846f05296eea31fd0207989261 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 4 Jun 2024 21:41:00 +0200 Subject: [PATCH] Revamp settings section (#2938) * Coding Signed-off-by: Marino Faggiana * normalized Signed-off-by: Marino Faggiana * Improve E2EE image Signed-off-by: Marino Faggiana * replace tabBarController with NCMainTabBarController Signed-off-by: Marino Faggiana * normalized Signed-off-by: Marino Faggiana --------- Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 308 ++++++---- .../Diagnostics/NCCapabilitiesView.swift | 203 ------ iOSClient/GUI/HUDView.swift | 2 +- .../CCAdvanced.h => GUI/LazyView.swift} | 22 +- iOSClient/GUI/ViewOnAppear.swift | 49 ++ .../Main/Create cloud/NCUploadAssets.swift | 577 ------------------ .../Upload Assets/NCUploadAssetsModel.swift | 289 +++++++++ .../Upload Assets/NCUploadAssetsView.swift | 277 +++++++++ iOSClient/Main/Main.storyboard | 27 +- iOSClient/Main/NCPickerViewController.swift | 6 +- .../{Settings => More}/CCManageAccount.h | 0 .../{Settings => More}/CCManageAccount.m | 0 iOSClient/More/NCMore.swift | 7 +- .../Scan document/NCUploadScanDocument.swift | 2 +- iOSClient/SceneDelegate.swift | 6 + iOSClient/Settings/Acknowledgements.h | 30 - iOSClient/Settings/Acknowledgements.m | 61 -- .../Capabilities/NCCapabilitiesModel.swift | 86 +++ .../Capabilities/NCCapabilitiesView.swift | 95 +++ .../Advanced/NCSettingsAdvancedModel.swift | 259 ++++++++ .../Advanced/NCSettingsAdvancedView.swift | 276 +++++++++ .../NCAutoUploadFileNamesModel.swift | 122 ++++ .../NCAutoUploadFileNamesView.swift | 112 ++++ .../AutoUpload/NCAutoUploadModel.swift | 201 ++++++ .../AutoUpload/NCAutoUploadView.swift | 167 +++++ iOSClient/Settings/CCAdvanced.m | 450 -------------- iOSClient/Settings/CCManageAutoUpload.h | 28 - iOSClient/Settings/CCManageAutoUpload.m | 461 -------------- .../Settings/Display/NCDisplayModel.swift | 53 ++ .../Settings/Display/NCDisplayView.swift | 78 +++ .../Helpers/NCAcknowledgementsView.swift | 86 +++ .../Settings/Helpers/NCWebBrowserView.swift | 101 +++ iOSClient/Settings/NCKeychain.swift | 34 +- .../Settings/NCManageAutoUploadFileName.swift | 214 ------- iOSClient/Settings/NCManageE2EE.swift | 390 ------------ iOSClient/Settings/NCSettings.h | 33 - iOSClient/Settings/NCSettings.m | 488 --------------- iOSClient/Settings/NCSettings.storyboard | 108 ---- .../E2EE}/NCEndToEndInitialize.swift | 0 .../Settings/E2EE/NCManageE2EEModel.swift | 152 +++++ .../Settings/E2EE/NCManageE2EEView.swift | 189 ++++++ .../Settings/Settings/NCSettingsModel.swift | 191 ++++++ .../Settings/Settings/NCSettingsView.swift | 276 +++++++++ .../en.lproj/Localizable.strings | 19 + ...Look.swift => NCViewerQuickLookView.swift} | 24 +- 45 files changed, 3362 insertions(+), 3197 deletions(-) delete mode 100644 iOSClient/Diagnostics/NCCapabilitiesView.swift rename iOSClient/{Settings/CCAdvanced.h => GUI/LazyView.swift} (63%) mode change 100755 => 100644 create mode 100644 iOSClient/GUI/ViewOnAppear.swift delete mode 100644 iOSClient/Main/Create cloud/NCUploadAssets.swift create mode 100644 iOSClient/Main/Create cloud/Upload Assets/NCUploadAssetsModel.swift create mode 100644 iOSClient/Main/Create cloud/Upload Assets/NCUploadAssetsView.swift rename iOSClient/{Settings => More}/CCManageAccount.h (100%) rename iOSClient/{Settings => More}/CCManageAccount.m (100%) delete mode 100644 iOSClient/Settings/Acknowledgements.h delete mode 100644 iOSClient/Settings/Acknowledgements.m create mode 100644 iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesModel.swift create mode 100644 iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesView.swift create mode 100644 iOSClient/Settings/Advanced/NCSettingsAdvancedModel.swift create mode 100644 iOSClient/Settings/Advanced/NCSettingsAdvancedView.swift create mode 100644 iOSClient/Settings/AutoUpload/AutoUploadFileNames/NCAutoUploadFileNamesModel.swift create mode 100644 iOSClient/Settings/AutoUpload/AutoUploadFileNames/NCAutoUploadFileNamesView.swift create mode 100644 iOSClient/Settings/AutoUpload/NCAutoUploadModel.swift create mode 100644 iOSClient/Settings/AutoUpload/NCAutoUploadView.swift delete mode 100755 iOSClient/Settings/CCAdvanced.m delete mode 100644 iOSClient/Settings/CCManageAutoUpload.h delete mode 100644 iOSClient/Settings/CCManageAutoUpload.m create mode 100644 iOSClient/Settings/Display/NCDisplayModel.swift create mode 100644 iOSClient/Settings/Display/NCDisplayView.swift create mode 100644 iOSClient/Settings/Helpers/NCAcknowledgementsView.swift create mode 100644 iOSClient/Settings/Helpers/NCWebBrowserView.swift delete mode 100644 iOSClient/Settings/NCManageAutoUploadFileName.swift delete mode 100644 iOSClient/Settings/NCManageE2EE.swift delete mode 100644 iOSClient/Settings/NCSettings.h delete mode 100644 iOSClient/Settings/NCSettings.m delete mode 100644 iOSClient/Settings/NCSettings.storyboard rename iOSClient/Settings/{ => Settings/E2EE}/NCEndToEndInitialize.swift (100%) create mode 100644 iOSClient/Settings/Settings/E2EE/NCManageE2EEModel.swift create mode 100644 iOSClient/Settings/Settings/E2EE/NCManageE2EEView.swift create mode 100644 iOSClient/Settings/Settings/NCSettingsModel.swift create mode 100644 iOSClient/Settings/Settings/NCSettingsView.swift rename iOSClient/Viewer/NCViewerQuickLook/{ViewerQuickLook.swift => NCViewerQuickLookView.swift} (90%) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index e0b33e3853..ce2fc00e5d 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -232,12 +232,6 @@ F7160A942BE933830034DCB3 /* Realm in Frameworks */ = {isa = PBXBuildFile; productRef = F7160A932BE933830034DCB3 /* Realm */; }; F717402D24F699A5000C87D5 /* NCFavorite.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F717402B24F699A5000C87D5 /* NCFavorite.storyboard */; }; F717402E24F699A5000C87D5 /* NCFavorite.swift in Sources */ = {isa = PBXBuildFile; fileRef = F717402C24F699A5000C87D5 /* NCFavorite.swift */; }; - F7183BD42AEBDCD6000CD020 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F760DE162AE66F350027D78A /* NCKeychain.swift */; }; - F7183BD52AEBDCD7000CD020 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F760DE162AE66F350027D78A /* NCKeychain.swift */; }; - F7183BD62AEBDCD7000CD020 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F760DE162AE66F350027D78A /* NCKeychain.swift */; }; - F7183BD72AEBDCD8000CD020 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F760DE162AE66F350027D78A /* NCKeychain.swift */; }; - F7183BD82AEBDCD8000CD020 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F760DE162AE66F350027D78A /* NCKeychain.swift */; }; - F7183BD92AEBDCD9000CD020 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F760DE162AE66F350027D78A /* NCKeychain.swift */; }; F718C24E254D507B00C5C256 /* NCViewerMediaDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F718C24D254D507B00C5C256 /* NCViewerMediaDetailView.swift */; }; F719D9E0288D37A300762E33 /* NCColorPicker.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F719D9DF288D37A300762E33 /* NCColorPicker.storyboard */; }; F719D9E2288D396100762E33 /* NCColorPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = F719D9E1288D396100762E33 /* NCColorPicker.swift */; }; @@ -261,7 +255,6 @@ F7245926289BB59300474787 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; }; F7245927289BB59300474787 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; }; F72685E727C78E490019EF5E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F72685E927C78E490019EF5E /* InfoPlist.strings */; }; - F726EEEC1FED1C820030B9C8 /* NCEndToEndInitialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F726EEEB1FED1C820030B9C8 /* NCEndToEndInitialize.swift */; }; F72944F22A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72944F12A84246400246839 /* NCEndToEndMetadataV20.swift */; }; F72944F32A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72944F12A84246400246839 /* NCEndToEndMetadataV20.swift */; }; F72944F52A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72944F42A8424F800246839 /* NCEndToEndMetadataV1.swift */; }; @@ -488,11 +481,9 @@ F758B460212C56A400515F55 /* NCScan.swift in Sources */ = {isa = PBXBuildFile; fileRef = F758B45F212C56A400515F55 /* NCScan.swift */; }; F75A9EE623796C6F0044CFCE /* NCNetworking.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75A9EE523796C6F0044CFCE /* NCNetworking.swift */; }; F75A9EE723796C6F0044CFCE /* NCNetworking.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75A9EE523796C6F0044CFCE /* NCNetworking.swift */; }; - F75AC2431F1F62450073EC19 /* NCManageAutoUploadFileName.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75AC2421F1F62450073EC19 /* NCManageAutoUploadFileName.swift */; }; F75B0ABD244C4DBB00E58DCA /* NCActionCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75B0ABC244C4DBB00E58DCA /* NCActionCenter.swift */; }; F75C0C4823D1FAE300163CC8 /* NCRichWorkspaceCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75C0C4723D1FAE300163CC8 /* NCRichWorkspaceCommon.swift */; }; F75CA1472962F13700B01130 /* HUDView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75CA1462962F13700B01130 /* HUDView.swift */; }; - F75CA1482962F13700B01130 /* HUDView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75CA1462962F13700B01130 /* HUDView.swift */; }; F75D19E325EFE09000D74598 /* NCTrash+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75D19E225EFE09000D74598 /* NCTrash+Menu.swift */; }; F75DD765290ABB25002EB562 /* Intent.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = F75DD769290ABB25002EB562 /* Intent.intentdefinition */; }; F75DD766290ABB25002EB562 /* Intent.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = F75DD769290ABB25002EB562 /* Intent.intentdefinition */; }; @@ -507,7 +498,6 @@ F760DE0B2AE66ED80027D78A /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = F760DE0A2AE66ED80027D78A /* KeychainAccess */; }; F760DE0D2AE66EDF0027D78A /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = F760DE0C2AE66EDF0027D78A /* KeychainAccess */; }; F760DE0F2AE66EE60027D78A /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = F760DE0E2AE66EE60027D78A /* KeychainAccess */; }; - F760DE172AE66F350027D78A /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F760DE162AE66F350027D78A /* NCKeychain.swift */; }; F761856A29E98543006EB3B0 /* NCIntro.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F761856629E98543006EB3B0 /* NCIntro.storyboard */; }; F761856B29E98543006EB3B0 /* NCIntroViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F761856729E98543006EB3B0 /* NCIntroViewController.swift */; }; F761856C29E98543006EB3B0 /* NCIntroCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F761856829E98543006EB3B0 /* NCIntroCollectionViewCell.swift */; }; @@ -530,13 +520,41 @@ F76687072B7D067400779E3F /* NCAudioRecorderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76687052B7D067400779E3F /* NCAudioRecorderViewController.swift */; }; F76687082B7D067400779E3F /* NCAudioRecorderViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F76687062B7D067400779E3F /* NCAudioRecorderViewController.storyboard */; }; F7682FE023C36B0500983A04 /* NCMainTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7682FDF23C36B0500983A04 /* NCMainTabBar.swift */; }; + F76882222C0DD1E7001CF441 /* NCCapabilitiesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882072C0DD1E7001CF441 /* NCCapabilitiesView.swift */; }; + F76882232C0DD1E7001CF441 /* NCCapabilitiesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882082C0DD1E7001CF441 /* NCCapabilitiesModel.swift */; }; + F76882242C0DD1E7001CF441 /* NCSettingsAdvancedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882092C0DD1E7001CF441 /* NCSettingsAdvancedView.swift */; }; + F76882252C0DD1E7001CF441 /* NCSettingsAdvancedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F768820A2C0DD1E7001CF441 /* NCSettingsAdvancedModel.swift */; }; + F76882262C0DD1E7001CF441 /* NCSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F768820C2C0DD1E7001CF441 /* NCSettingsView.swift */; }; + F76882272C0DD1E7001CF441 /* NCManageE2EEView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F768820E2C0DD1E7001CF441 /* NCManageE2EEView.swift */; }; + 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 */; }; + F768822B2C0DD1E7001CF441 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = F76882122C0DD1E7001CF441 /* Settings.bundle */; }; + 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 */; }; + F768822F2C0DD1E7001CF441 /* NCAutoUploadModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882172C0DD1E7001CF441 /* NCAutoUploadModel.swift */; }; + F76882302C0DD1E7001CF441 /* NCAutoUploadFileNamesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882192C0DD1E7001CF441 /* NCAutoUploadFileNamesModel.swift */; }; + F76882312C0DD1E7001CF441 /* NCAutoUploadFileNamesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F768821A2C0DD1E7001CF441 /* NCAutoUploadFileNamesView.swift */; }; + F76882322C0DD1E7001CF441 /* NCAutoUploadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F768821B2C0DD1E7001CF441 /* NCAutoUploadView.swift */; }; + F76882332C0DD1E7001CF441 /* NCDisplayModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F768821D2C0DD1E7001CF441 /* NCDisplayModel.swift */; }; + 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 /* 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 */; }; + F76882432C0DD3B4001CF441 /* CCManageAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = F76882422C0DD3B4001CF441 /* CCManageAccount.m */; }; F769453C22E9CFFF000A798A /* NCShareUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F769453B22E9CFFF000A798A /* NCShareUserCell.xib */; }; F769454022E9F077000A798A /* NCSharePaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769453F22E9F077000A798A /* NCSharePaging.swift */; }; F769454622E9F1B0000A798A /* NCShareCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769454522E9F1B0000A798A /* NCShareCommon.swift */; }; F769454822E9F20D000A798A /* NCShareNetworking.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769454722E9F20D000A798A /* NCShareNetworking.swift */; }; - F769CA172965AB7C00039397 /* NCUploadAssets.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769CA162965AB7C00039397 /* NCUploadAssets.swift */; }; F769CA192966EA3C00039397 /* ComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769CA182966EA3C00039397 /* ComponentView.swift */; }; - F769CA1A2966EA3C00039397 /* ComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769CA182966EA3C00039397 /* ComponentView.swift */; }; F76B3CCE1EAE01BD00921AC9 /* NCBrand.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */; }; F76B3CCF1EAE01BD00921AC9 /* NCBrand.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */; }; F76B649C2ADFFAED00014640 /* NCImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76B649B2ADFFAED00014640 /* NCImageCache.swift */; }; @@ -574,15 +592,8 @@ F77444F522281649000D5EB0 /* NCGridMediaCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77444F322281649000D5EB0 /* NCGridMediaCell.swift */; }; F77444F622281649000D5EB0 /* NCGridMediaCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F77444F422281649000D5EB0 /* NCGridMediaCell.xib */; }; F77444F8222816D5000D5EB0 /* NCPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77444F7222816D5000D5EB0 /* NCPickerViewController.swift */; }; - F77910A525DD517B00CEDB9E /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = F77910A425DD517B00CEDB9E /* Settings.bundle */; }; - F77910AB25DD53C700CEDB9E /* NCSettingsBundleHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77910AA25DD53C700CEDB9E /* NCSettingsBundleHelper.swift */; }; F77A697D250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77A697C250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift */; }; F77B0DF51D118A16002130FE /* CCUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = F7053E3D1C639DF500741EA5 /* CCUtility.m */; }; - F77B0E4F1D118A16002130FE /* CCManageAutoUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = F7ACE42F1BAC0268006C0017 /* CCManageAutoUpload.m */; }; - F77B0E5F1D118A16002130FE /* NCSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = F7ACE4311BAC0268006C0017 /* NCSettings.m */; }; - F77B0E981D118A16002130FE /* CCManageAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = F7ACE42D1BAC0268006C0017 /* CCManageAccount.m */; }; - F77B0ED11D118A16002130FE /* Acknowledgements.m in Sources */ = {isa = PBXBuildFile; fileRef = F7ACE42A1BAC0268006C0017 /* Acknowledgements.m */; }; - F77B0F611D118A16002130FE /* Acknowledgements.rtf in Resources */ = {isa = PBXBuildFile; fileRef = F7ACE42B1BAC0268006C0017 /* Acknowledgements.rtf */; }; F77B0F631D118A16002130FE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F7E70DE91A24DE4100E1B66A /* Localizable.strings */; }; F77B0F7D1D118A16002130FE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F7F67BB81A24D27800EE80DA /* Images.xcassets */; }; F77BB746289984CA0090FC19 /* UIViewController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77BB745289984CA0090FC19 /* UIViewController+Extension.swift */; }; @@ -702,8 +713,6 @@ F7A0D1362591FBC5008F8A13 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; }; F7A0D1372591FBC5008F8A13 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; }; F7A1050E29E587AF00FFD92B /* TagListView in Frameworks */ = {isa = PBXBuildFile; productRef = F7A1050D29E587AF00FFD92B /* TagListView */; }; - F7A321AD1E9E6AD50069AD1B /* CCAdvanced.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A321AC1E9E6AD50069AD1B /* CCAdvanced.m */; }; - F7A48413297022E000BD1B49 /* ViewerQuickLook.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A48412297022E000BD1B49 /* ViewerQuickLook.swift */; }; F7A48415297028FC00BD1B49 /* Nextcloud Hub.png in Resources */ = {isa = PBXBuildFile; fileRef = F7A48414297028FC00BD1B49 /* Nextcloud Hub.png */; }; F7A560422AE1593700BE8FD6 /* NCOperationSaveLivePhoto.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A560412AE1593700BE8FD6 /* NCOperationSaveLivePhoto.swift */; }; F7A560442AE15D2900BE8FD6 /* Queuer in Frameworks */ = {isa = PBXBuildFile; productRef = F7A560432AE15D2900BE8FD6 /* Queuer */; }; @@ -713,7 +722,6 @@ F7A60F87292D215000FCE1F2 /* NCShareAccounts.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7A60F85292D215000FCE1F2 /* NCShareAccounts.storyboard */; }; F7A76DC8256A71CD00119AB3 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B7504A2397D38E004E13EC /* UIImage+Extension.swift */; }; F7A76DCD256A71CE00119AB3 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B7504A2397D38E004E13EC /* UIImage+Extension.swift */; }; - F7A7FA6329265CF4000603EF /* NCManageE2EE.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A7FA6229265CF4000603EF /* NCManageE2EE.swift */; }; F7A846DE2BB01ACB0024816F /* NCTrashCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A846DD2BB01ACB0024816F /* NCTrashCellProtocol.swift */; }; F7A8D72428F1771B008BBE1C /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = F7A8D72328F1771B008BBE1C /* NextcloudKit */; }; F7A8D72828F17728008BBE1C /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F7A8D72728F17728008BBE1C /* RealmSwift */; }; @@ -790,7 +798,6 @@ 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 */; }; - F7CB68A0254169530050EC94 /* NCSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CB689F254169530050EC94 /* NCSettings.storyboard */; }; F7CBC1232BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7CBC1212BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib */; }; F7CBC1242BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7CBC1212BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib */; }; F7CBC1252BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CBC1222BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.swift */; }; @@ -856,8 +863,10 @@ F7F878AE1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */; }; F7F878AF1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */; }; F7F9D1BB25397CE000D9BFF5 /* NCViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F9D1BA25397CE000D9BFF5 /* NCViewer.swift */; }; + F7FA7FFC2C0F4EE40072FC60 /* NCViewerQuickLookView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7FA7FFB2C0F4EE40072FC60 /* NCViewerQuickLookView.swift */; }; + 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 */; }; - F7FC5EE12A1768D700D921F5 /* NCCapabilitiesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7FC5EE02A1768D700D921F5 /* NCCapabilitiesView.swift */; }; F7FF2CB12842159500EBB7A1 /* NCSectionHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7FF2CB02842159500EBB7A1 /* NCSectionHeader.xib */; }; /* End PBXBuildFile section */ @@ -1242,7 +1251,6 @@ F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreadSafeDictionary.swift; sourceTree = ""; }; F7267A81225DFCE100D6DB7D /* AFNetworking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AFNetworking.framework; path = Carthage/Build/iOS/AFNetworking.framework; sourceTree = ""; }; F72685E827C78E490019EF5E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - F726EEEB1FED1C820030B9C8 /* NCEndToEndInitialize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCEndToEndInitialize.swift; sourceTree = ""; }; F72944F12A84246400246839 /* NCEndToEndMetadataV20.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEndToEndMetadataV20.swift; sourceTree = ""; }; F72944F42A8424F800246839 /* NCEndToEndMetadataV1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEndToEndMetadataV1.swift; sourceTree = ""; }; F72A17D728B221E300F3F159 /* DashboardWidgetView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardWidgetView.swift; sourceTree = ""; }; @@ -1323,7 +1331,6 @@ F758B45D212C569C00515F55 /* NCScanCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCScanCell.swift; sourceTree = ""; }; F758B45F212C56A400515F55 /* NCScan.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCScan.swift; sourceTree = ""; }; F75A9EE523796C6F0044CFCE /* NCNetworking.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCNetworking.swift; sourceTree = ""; }; - F75AC2421F1F62450073EC19 /* NCManageAutoUploadFileName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCManageAutoUploadFileName.swift; sourceTree = ""; }; F75B0ABC244C4DBB00E58DCA /* NCActionCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActionCenter.swift; sourceTree = ""; }; F75B91E21ECAE17800199C96 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; F75B91F71ECAE26300199C96 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; @@ -1336,7 +1343,6 @@ F75EDFBE1E8C116D00E6F369 /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.tbd"; path = "usr/lib/libstdc++.tbd"; sourceTree = SDKROOT; }; F760329D252F0F8E0015A421 /* NCTransferCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NCTransferCell.swift; path = iOSClient/Transfers/NCTransferCell.swift; sourceTree = SOURCE_ROOT; }; F760329E252F0F8E0015A421 /* NCTransferCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = NCTransferCell.xib; path = iOSClient/Transfers/NCTransferCell.xib; sourceTree = SOURCE_ROOT; }; - F760DE162AE66F350027D78A /* NCKeychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCKeychain.swift; sourceTree = ""; }; F761856629E98543006EB3B0 /* NCIntro.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCIntro.storyboard; sourceTree = ""; }; F761856729E98543006EB3B0 /* NCIntroViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCIntroViewController.swift; sourceTree = ""; }; F761856829E98543006EB3B0 /* NCIntroCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCIntroCollectionViewCell.swift; sourceTree = ""; }; @@ -1355,11 +1361,35 @@ F76687052B7D067400779E3F /* NCAudioRecorderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCAudioRecorderViewController.swift; sourceTree = ""; }; F76687062B7D067400779E3F /* NCAudioRecorderViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCAudioRecorderViewController.storyboard; sourceTree = ""; }; F7682FDF23C36B0500983A04 /* NCMainTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMainTabBar.swift; sourceTree = ""; }; + F76882072C0DD1E7001CF441 /* NCCapabilitiesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCCapabilitiesView.swift; sourceTree = ""; }; + F76882082C0DD1E7001CF441 /* NCCapabilitiesModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCCapabilitiesModel.swift; sourceTree = ""; }; + F76882092C0DD1E7001CF441 /* NCSettingsAdvancedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCSettingsAdvancedView.swift; sourceTree = ""; }; + F768820A2C0DD1E7001CF441 /* NCSettingsAdvancedModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCSettingsAdvancedModel.swift; sourceTree = ""; }; + F768820C2C0DD1E7001CF441 /* NCSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCSettingsView.swift; sourceTree = ""; }; + F768820E2C0DD1E7001CF441 /* NCManageE2EEView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCManageE2EEView.swift; sourceTree = ""; }; + 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 = ""; }; + F76882122C0DD1E7001CF441 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; 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 = ""; }; + F76882172C0DD1E7001CF441 /* NCAutoUploadModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCAutoUploadModel.swift; sourceTree = ""; }; + F76882192C0DD1E7001CF441 /* NCAutoUploadFileNamesModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCAutoUploadFileNamesModel.swift; sourceTree = ""; }; + F768821A2C0DD1E7001CF441 /* NCAutoUploadFileNamesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCAutoUploadFileNamesView.swift; sourceTree = ""; }; + F768821B2C0DD1E7001CF441 /* NCAutoUploadView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCAutoUploadView.swift; sourceTree = ""; }; + F768821D2C0DD1E7001CF441 /* NCDisplayModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCDisplayModel.swift; sourceTree = ""; }; + F768821E2C0DD1E7001CF441 /* NCDisplayView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCDisplayView.swift; sourceTree = ""; }; + F76882202C0DD1E7001CF441 /* NCWebBrowserView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCWebBrowserView.swift; sourceTree = ""; }; + F76882212C0DD1E7001CF441 /* NCAcknowledgementsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCAcknowledgementsView.swift; sourceTree = ""; }; + F768823D2C0DD304001CF441 /* LazyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = ""; }; + F768823F2C0DD30B001CF441 /* ViewOnAppear.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewOnAppear.swift; sourceTree = ""; }; + F76882412C0DD3B4001CF441 /* CCManageAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCManageAccount.h; sourceTree = ""; }; + F76882422C0DD3B4001CF441 /* CCManageAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCManageAccount.m; sourceTree = ""; }; F769453B22E9CFFF000A798A /* NCShareUserCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareUserCell.xib; sourceTree = ""; }; F769453F22E9F077000A798A /* NCSharePaging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSharePaging.swift; sourceTree = ""; }; F769454522E9F1B0000A798A /* NCShareCommon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCommon.swift; sourceTree = ""; }; F769454722E9F20D000A798A /* NCShareNetworking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareNetworking.swift; sourceTree = ""; }; - F769CA162965AB7C00039397 /* NCUploadAssets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCUploadAssets.swift; sourceTree = ""; }; F769CA182966EA3C00039397 /* ComponentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComponentView.swift; sourceTree = ""; }; F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCBrand.swift; sourceTree = ""; }; F76B649B2ADFFAED00014640 /* NCImageCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCImageCache.swift; sourceTree = ""; }; @@ -1404,8 +1434,6 @@ F77444F322281649000D5EB0 /* NCGridMediaCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCGridMediaCell.swift; sourceTree = ""; }; F77444F422281649000D5EB0 /* NCGridMediaCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCGridMediaCell.xib; sourceTree = ""; }; F77444F7222816D5000D5EB0 /* NCPickerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCPickerViewController.swift; sourceTree = ""; }; - F77910A425DD517B00CEDB9E /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; - F77910AA25DD53C700CEDB9E /* NCSettingsBundleHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSettingsBundleHelper.swift; sourceTree = ""; }; F7792DE429EEE02D005930CE /* MobileVLCKit.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MobileVLCKit.xcframework; path = Carthage/Build/MobileVLCKit.xcframework; sourceTree = ""; }; F77A697C250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCCollectionViewCommon+Menu.swift"; sourceTree = ""; }; F77BB745289984CA0090FC19 /* UIViewController+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extension.swift"; sourceTree = ""; }; @@ -1462,14 +1490,10 @@ F79EDAA126B004980007D134 /* NCPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCPlayer.swift; sourceTree = ""; }; F79FFB252A97C24A0055EEA4 /* NCNetworkingE2EEMarkFolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNetworkingE2EEMarkFolder.swift; sourceTree = ""; }; F7A0D1342591FBC5008F8A13 /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = ""; }; - F7A321AB1E9E6AD50069AD1B /* CCAdvanced.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCAdvanced.h; sourceTree = ""; }; - F7A321AC1E9E6AD50069AD1B /* CCAdvanced.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCAdvanced.m; sourceTree = ""; }; - F7A48412297022E000BD1B49 /* ViewerQuickLook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewerQuickLook.swift; sourceTree = ""; }; F7A48414297028FC00BD1B49 /* Nextcloud Hub.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Nextcloud Hub.png"; sourceTree = SOURCE_ROOT; }; F7A560412AE1593700BE8FD6 /* NCOperationSaveLivePhoto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCOperationSaveLivePhoto.swift; sourceTree = ""; }; F7A60F84292D215000FCE1F2 /* NCShareAccounts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCShareAccounts.swift; sourceTree = ""; }; F7A60F85292D215000FCE1F2 /* NCShareAccounts.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCShareAccounts.storyboard; sourceTree = ""; }; - F7A7FA6229265CF4000603EF /* NCManageE2EE.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCManageE2EE.swift; sourceTree = ""; }; F7A846DD2BB01ACB0024816F /* NCTrashCellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTrashCellProtocol.swift; sourceTree = ""; }; F7A8D72228F176B6008BBE1C /* WidgetDashboardIntentHandler-Brinding-header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WidgetDashboardIntentHandler-Brinding-header.h"; sourceTree = ""; }; F7AA41B827C7CF4600494705 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -1516,15 +1540,6 @@ F7AA41E127C7CF8100494705 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/InfoPlist.strings"; sourceTree = ""; }; F7AC1CAF28AB94490032D99F /* Array+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extension.swift"; sourceTree = ""; }; F7AC9349296193050002BC0F /* Reasons to use Nextcloud.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "Reasons to use Nextcloud.pdf"; sourceTree = SOURCE_ROOT; }; - F7ACE4291BAC0268006C0017 /* Acknowledgements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Acknowledgements.h; sourceTree = ""; }; - F7ACE42A1BAC0268006C0017 /* Acknowledgements.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Acknowledgements.m; sourceTree = ""; }; - F7ACE42B1BAC0268006C0017 /* Acknowledgements.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Acknowledgements.rtf; sourceTree = ""; }; - F7ACE42C1BAC0268006C0017 /* CCManageAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCManageAccount.h; sourceTree = ""; }; - F7ACE42D1BAC0268006C0017 /* CCManageAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCManageAccount.m; sourceTree = ""; }; - F7ACE42E1BAC0268006C0017 /* CCManageAutoUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCManageAutoUpload.h; sourceTree = ""; }; - F7ACE42F1BAC0268006C0017 /* CCManageAutoUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCManageAutoUpload.m; sourceTree = ""; }; - F7ACE4301BAC0268006C0017 /* NCSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NCSettings.h; sourceTree = ""; }; - F7ACE4311BAC0268006C0017 /* NCSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NCSettings.m; sourceTree = ""; }; F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCLoginWeb.swift; sourceTree = ""; }; F7AE00F7230E81CB007ACF8A /* NCBrowserWeb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCBrowserWeb.swift; sourceTree = ""; }; F7AE00F9230E81EB007ACF8A /* NCBrowserWeb.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCBrowserWeb.storyboard; sourceTree = ""; }; @@ -1612,7 +1627,6 @@ 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 = ""; }; - F7CB689F254169530050EC94 /* NCSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCSettings.storyboard; sourceTree = ""; }; F7CBC1212BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCSectionHeaderEmptyData.xib; sourceTree = ""; }; F7CBC1222BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCSectionHeaderEmptyData.swift; sourceTree = ""; }; F7CC04E61F5AD50D00378CEF /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; @@ -1667,8 +1681,10 @@ 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 = ""; }; + F7FA7FFB2C0F4EE40072FC60 /* NCViewerQuickLookView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCViewerQuickLookView.swift; sourceTree = ""; }; + 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 = ""; }; - F7FC5EE02A1768D700D921F5 /* NCCapabilitiesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCapabilitiesView.swift; sourceTree = ""; }; F7FC7D551DC1F93800BB2C6A /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; F7FF2CB02842159500EBB7A1 /* NCSectionHeader.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCSectionHeader.xib; sourceTree = ""; }; /* End PBXFileReference section */ @@ -2104,8 +2120,8 @@ F723986A253C9C0E00257F49 /* NCViewerQuickLook */ = { isa = PBXGroup; children = ( + F7FA7FFB2C0F4EE40072FC60 /* NCViewerQuickLookView.swift */, F7C7B488245EBA4100D93E60 /* NCViewerQuickLook.swift */, - F7A48412297022E000BD1B49 /* ViewerQuickLook.swift */, ); path = NCViewerQuickLook; sourceTree = ""; @@ -2195,14 +2211,6 @@ path = NCViewerNextcloudText; sourceTree = ""; }; - F73FAEE224D2CA830090692E /* Diagnostics */ = { - isa = PBXGroup; - children = ( - F7FC5EE02A1768D700D921F5 /* NCCapabilitiesView.swift */, - ); - path = Diagnostics; - sourceTree = ""; - }; F74D3DB81BAC1941000BAE4B /* Networking */ = { isa = PBXGroup; children = ( @@ -2308,10 +2316,104 @@ path = AudioRecorder; sourceTree = ""; }; + F76882042C0DD1E7001CF441 /* Settings */ = { + isa = PBXGroup; + children = ( + F768820B2C0DD1E7001CF441 /* Settings */, + F76882162C0DD1E7001CF441 /* AutoUpload */, + F768821C2C0DD1E7001CF441 /* Display */, + F76882052C0DD1E7001CF441 /* Advanced */, + F768821F2C0DD1E7001CF441 /* Helpers */, + F76882142C0DD1E7001CF441 /* Acknowledgements.rtf */, + F76882132C0DD1E7001CF441 /* NCKeychain.swift */, + F76882152C0DD1E7001CF441 /* NCSettingsBundleHelper.swift */, + F76882122C0DD1E7001CF441 /* Settings.bundle */, + ); + path = Settings; + sourceTree = ""; + }; + F76882052C0DD1E7001CF441 /* Advanced */ = { + isa = PBXGroup; + children = ( + F76882062C0DD1E7001CF441 /* Capabilities */, + F76882092C0DD1E7001CF441 /* NCSettingsAdvancedView.swift */, + F768820A2C0DD1E7001CF441 /* NCSettingsAdvancedModel.swift */, + ); + path = Advanced; + sourceTree = ""; + }; + F76882062C0DD1E7001CF441 /* Capabilities */ = { + isa = PBXGroup; + children = ( + F76882072C0DD1E7001CF441 /* NCCapabilitiesView.swift */, + F76882082C0DD1E7001CF441 /* NCCapabilitiesModel.swift */, + ); + path = Capabilities; + sourceTree = ""; + }; + F768820B2C0DD1E7001CF441 /* Settings */ = { + isa = PBXGroup; + children = ( + F768820D2C0DD1E7001CF441 /* E2EE */, + F76882112C0DD1E7001CF441 /* NCSettingsModel.swift */, + F768820C2C0DD1E7001CF441 /* NCSettingsView.swift */, + ); + path = Settings; + sourceTree = ""; + }; + F768820D2C0DD1E7001CF441 /* E2EE */ = { + isa = PBXGroup; + children = ( + F768820F2C0DD1E7001CF441 /* NCEndToEndInitialize.swift */, + F76882102C0DD1E7001CF441 /* NCManageE2EEModel.swift */, + F768820E2C0DD1E7001CF441 /* NCManageE2EEView.swift */, + ); + path = E2EE; + sourceTree = ""; + }; + F76882162C0DD1E7001CF441 /* AutoUpload */ = { + isa = PBXGroup; + children = ( + F76882182C0DD1E7001CF441 /* AutoUploadFileNames */, + F76882172C0DD1E7001CF441 /* NCAutoUploadModel.swift */, + F768821B2C0DD1E7001CF441 /* NCAutoUploadView.swift */, + ); + path = AutoUpload; + sourceTree = ""; + }; + F76882182C0DD1E7001CF441 /* AutoUploadFileNames */ = { + isa = PBXGroup; + children = ( + F76882192C0DD1E7001CF441 /* NCAutoUploadFileNamesModel.swift */, + F768821A2C0DD1E7001CF441 /* NCAutoUploadFileNamesView.swift */, + ); + path = AutoUploadFileNames; + sourceTree = ""; + }; + F768821C2C0DD1E7001CF441 /* Display */ = { + isa = PBXGroup; + children = ( + F768821D2C0DD1E7001CF441 /* NCDisplayModel.swift */, + F768821E2C0DD1E7001CF441 /* NCDisplayView.swift */, + ); + path = Display; + sourceTree = ""; + }; + F768821F2C0DD1E7001CF441 /* Helpers */ = { + isa = PBXGroup; + children = ( + F76882202C0DD1E7001CF441 /* NCWebBrowserView.swift */, + F76882212C0DD1E7001CF441 /* NCAcknowledgementsView.swift */, + ); + path = Helpers; + sourceTree = ""; + }; F769CA1B2966EF4F00039397 /* GUI */ = { isa = PBXGroup; children = ( F769CA182966EA3C00039397 /* ComponentView.swift */, + F768823D2C0DD304001CF441 /* LazyView.swift */, + F768823F2C0DD30B001CF441 /* ViewOnAppear.swift */, F75CA1462962F13700B01130 /* HUDView.swift */, ); path = GUI; @@ -2522,31 +2624,6 @@ path = Activity; sourceTree = ""; }; - F7ACE4281BAC0268006C0017 /* Settings */ = { - isa = PBXGroup; - children = ( - F7ACE4291BAC0268006C0017 /* Acknowledgements.h */, - F7ACE42A1BAC0268006C0017 /* Acknowledgements.m */, - F7ACE42B1BAC0268006C0017 /* Acknowledgements.rtf */, - F7A321AB1E9E6AD50069AD1B /* CCAdvanced.h */, - F7A321AC1E9E6AD50069AD1B /* CCAdvanced.m */, - F7ACE42C1BAC0268006C0017 /* CCManageAccount.h */, - F7ACE42D1BAC0268006C0017 /* CCManageAccount.m */, - F7ACE42E1BAC0268006C0017 /* CCManageAutoUpload.h */, - F7ACE42F1BAC0268006C0017 /* CCManageAutoUpload.m */, - F726EEEB1FED1C820030B9C8 /* NCEndToEndInitialize.swift */, - F760DE162AE66F350027D78A /* NCKeychain.swift */, - F75AC2421F1F62450073EC19 /* NCManageAutoUploadFileName.swift */, - F7A7FA6229265CF4000603EF /* NCManageE2EE.swift */, - F7ACE4301BAC0268006C0017 /* NCSettings.h */, - F7ACE4311BAC0268006C0017 /* NCSettings.m */, - F7CB689F254169530050EC94 /* NCSettings.storyboard */, - F77910AA25DD53C700CEDB9E /* NCSettingsBundleHelper.swift */, - F77910A425DD517B00CEDB9E /* Settings.bundle */, - ); - path = Settings; - sourceTree = ""; - }; F7AE00F6230E8191007ACF8A /* BrowserWeb */ = { isa = PBXGroup; children = ( @@ -2720,6 +2797,8 @@ F3BB46502A39EC2D00461F6E /* Cells */, F7CB68992541676B0050EC94 /* NCMore.storyboard */, F73F537E1E929C8500F8678D /* NCMore.swift */, + F76882412C0DD3B4001CF441 /* CCManageAccount.h */, + F76882422C0DD3B4001CF441 /* CCManageAccount.m */, ); path = More; sourceTree = ""; @@ -2727,7 +2806,7 @@ F7DFB7E9219C5A0500680748 /* Create cloud */ = { isa = PBXGroup; children = ( - F769CA162965AB7C00039397 /* NCUploadAssets.swift */, + F7FA7FFD2C0F4F3B0072FC60 /* Upload Assets */, F704B5E22430AA6F00632F5F /* NCCreateFormUploadConflict.storyboard */, F704B5E42430AA8000632F5F /* NCCreateFormUploadConflict.swift */, F704B5E82430C0B800632F5F /* NCCreateFormUploadConflictCell.swift */, @@ -2846,7 +2925,6 @@ F7AE00F6230E8191007ACF8A /* BrowserWeb */, F70B866A2642A21300ED5349 /* Color */, F7BAAD951ED5A63D00B7EAD4 /* Data */, - F73FAEE224D2CA830090692E /* Diagnostics */, F7A0D14E259229FA008F8A13 /* Extensions */, F7A3214D1E9E2A070069AD1B /* Favorites */, F7725A5D251F33BB00D125E0 /* Files */, @@ -2862,9 +2940,9 @@ F765F72E25237E3F00391DBE /* Recent */, F70D87CC25EE6E58008CBBBD /* Rename file */, F7CADB3D23CCDDA1000EEC78 /* RichWorkspace */, + F76882042C0DD1E7001CF441 /* Settings */, F758B41E212C516300515F55 /* Scan document */, F79A65C12191D8DC00FF6DCC /* Select */, - F7ACE4281BAC0268006C0017 /* Settings */, F728CE741BF6322C00E69702 /* Share */, F7169A161EE590930086BD69 /* Shares */, F7E9C41320F4CA870040CF18 /* Transfers */, @@ -2888,6 +2966,15 @@ path = iOSClient; sourceTree = ""; }; + F7FA7FFD2C0F4F3B0072FC60 /* Upload Assets */ = { + isa = PBXGroup; + children = ( + F7FA7FFE2C0F4F3B0072FC60 /* NCUploadAssetsModel.swift */, + F7FA7FFF2C0F4F3B0072FC60 /* NCUploadAssetsView.swift */, + ); + path = "Upload Assets"; + sourceTree = ""; + }; F7FC7D541DC1F93700BB2C6A /* Frameworks */ = { isa = PBXGroup; children = ( @@ -3610,6 +3697,7 @@ F7F4F10C27ECDBDB008676F9 /* Inconsolata-Regular.ttf in Resources */, F7B8B83025681C3400967775 /* GoogleService-Info.plist in Resources */, F7381EE5218218C9000B1560 /* NCOffline.storyboard in Resources */, + F768822D2C0DD1E7001CF441 /* Acknowledgements.rtf in Resources */, F7E0CDCF265CE8610044854E /* NCUserStatus.storyboard in Resources */, F76D3CF32428B94E005DFA87 /* NCViewerPDFSearchCell.xib in Resources */, F7CA212E25F1333300826ABB /* NCAccountRequest.storyboard in Resources */, @@ -3635,7 +3723,6 @@ F7BC287E26663F6C004D46C5 /* NCViewCertificateDetails.storyboard in Resources */, F78ACD54219047D40088454D /* NCSectionFooter.xib in Resources */, F704B5E32430AA6F00632F5F /* NCCreateFormUploadConflict.storyboard in Resources */, - F77B0F611D118A16002130FE /* Acknowledgements.rtf in Resources */, F7EDE509262DA9D600414FE6 /* NCSelectCommandViewSelect.xib in Resources */, F732D23327CF8AED000B0F1B /* NCPlayerToolBar.xib in Resources */, F73D11FA253C5F4800DF9BEC /* NCViewerNextcloudText.storyboard in Resources */, @@ -3647,14 +3734,13 @@ F774264A22EB4D0000B23912 /* NCSearchUserDropDownCell.xib in Resources */, F7CB689A2541676B0050EC94 /* NCMore.storyboard in Resources */, F77B0F7D1D118A16002130FE /* Images.xcassets in Resources */, + F768822B2C0DD1E7001CF441 /* Settings.bundle in Resources */, F73CB3B222E072A000AD728E /* NCShareHeaderView.xib in Resources */, F7AE00FA230E81EB007ACF8A /* NCBrowserWeb.storyboard in Resources */, F7EDE514262DC2CD00414FE6 /* NCSelectCommandViewSelect+CreateFolder.xib in Resources */, F7B398422A6A91D5007538D6 /* NCSectionHeaderMenu.xib in Resources */, F7501C322212E57500FB1415 /* NCMedia.storyboard in Resources */, F74DE14425135B6800917068 /* NCTransfers.storyboard in Resources */, - F77910A525DD517B00CEDB9E /* Settings.bundle in Resources */, - F7CB68A0254169530050EC94 /* NCSettings.storyboard in Resources */, F76687082B7D067400779E3F /* NCAudioRecorderViewController.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3716,7 +3802,6 @@ F343A4C12A1E734600DDA874 /* Optional+Extension.swift in Sources */, F7245927289BB59300474787 /* ThreadSafeDictionary.swift in Sources */, 2C33C48223E2C475005F963B /* NotificationService.swift in Sources */, - F7183BD92AEBDCD9000CD020 /* NCKeychain.swift in Sources */, F73EF7A52B021FAE0087E6E9 /* NCLivePhoto.swift in Sources */, AF4BF617275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */, F7BF9D872934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */, @@ -3726,13 +3811,11 @@ F7C9B9232B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */, F73EF7CD2B0225610087E6E9 /* NCManageDatabase+PhotoLibrary.swift in Sources */, D575039F27146F93008DC9DC /* String+Extension.swift in Sources */, - F769CA1A2966EA3C00039397 /* ComponentView.swift in Sources */, F757CC8829E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */, F79B646326CA661600838ACA /* UIControl+Extension.swift in Sources */, F73EF7B52B0224350087E6E9 /* NCManageDatabase+DirectEditing.swift in Sources */, F78A10C429322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */, F7B769AE2B7A0B2000C1AAEB /* NCManageDatabase+Metadata+Session.swift in Sources */, - F75CA1482962F13700B01130 /* HUDView.swift in Sources */, F711A4E22AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */, AF4BF61C27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */, AF817EF4274BC781009ED85B /* NCUserBaseUrl.swift in Sources */, @@ -3740,6 +3823,7 @@ F7817CFF29802D1A00FFBC65 /* NCPushNotificationEncryption.m in Sources */, F798F0EC2588060A000DAFFD /* UIColor+Extension.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 */, @@ -3798,7 +3882,6 @@ F7490E7429882BCC009DCE94 /* NCManageDatabase.swift in Sources */, F7490E6E29882B56009DCE94 /* NCBrand.swift in Sources */, F73EF7CC2B0225610087E6E9 /* NCManageDatabase+PhotoLibrary.swift in Sources */, - F7183BD82AEBDCD8000CD020 /* NCKeychain.swift in Sources */, F7490E8129882C79009DCE94 /* NCManageDatabase+DashboardWidget.swift in Sources */, F73EF7D42B0225BA0087E6E9 /* NCManageDatabase+Tag.swift in Sources */, F71F6D0C2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */, @@ -3807,6 +3890,7 @@ F73EF7E42B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */, F343A4C02A1E734600DDA874 /* Optional+Extension.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 */, F7490E8C29882D02009DCE94 /* CCUtility.m in Sources */, @@ -3899,7 +3983,6 @@ F36E64FA2B96236C0085ABB5 /* UIView+Extension.swift in Sources */, F75A9EE723796C6F0044CFCE /* NCNetworking.swift in Sources */, AF730AFA27843E4C00B7520E /* NCShareExtension+NCDelegate.swift in Sources */, - F7183BD62AEBDCD7000CD020 /* NCKeychain.swift in Sources */, F7327E232B73A42F00A462C7 /* NCNetworking+Download.swift in Sources */, F749B64D297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */, F72FD3B8297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */, @@ -3909,6 +3992,7 @@ F73EF7AA2B0223900087E6E9 /* NCManageDatabase+Comments.swift in Sources */, F763D2A02A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */, F757CC8529E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */, + F768823A2C0DD230001CF441 /* NCKeychain.swift in Sources */, F737DA9E2B7B893C0063BAFC /* NCPasscode.swift in Sources */, F7817D0129802D5F00FFBC65 /* NCViewCertificateDetails.swift in Sources */, F7D57C8B26317BDE00DE301D /* NCAccountRequest.swift in Sources */, @@ -3940,7 +4024,6 @@ buildActionMask = 2147483647; files = ( F78302FD28B4C42B00B84583 /* NCUserBaseUrl.swift in Sources */, - F7183BD42AEBDCD6000CD020 /* NCKeychain.swift in Sources */, F793E5A128B76541005E4B02 /* NotificationCenter+MainThread.swift in Sources */, F76DEE9928F808AF0041B1C9 /* LockscreenWidgetView.swift in Sources */, F7817D0029802D3D00FFBC65 /* NCViewCertificateDetails.swift in Sources */, @@ -3958,6 +4041,7 @@ F711D63128F44801003F43C8 /* IntentHandler.swift in Sources */, F76DEE9728F808AF0041B1C9 /* LockscreenData.swift in Sources */, F72EA95A28B7BD0D00C88F0C /* FilesWidgetView.swift in Sources */, + F768823C2C0DD231001CF441 /* NCKeychain.swift in Sources */, F71F6D082B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */, F78302FE28B4C44700B84583 /* NCBrand.swift in Sources */, F749B64B297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */, @@ -4052,7 +4136,6 @@ F7C9B9212B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */, F359D86B2A7D03420023F405 /* NCUtility+Exif.swift in Sources */, F7864AD02A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */, - F7183BD72AEBDCD8000CD020 /* NCKeychain.swift in Sources */, F7327E402B73B92800A462C7 /* NCNetworking+Synchronization.swift in Sources */, AF4BF61B27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */, F70460542499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */, @@ -4082,6 +4165,7 @@ F71F6D0B2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */, F73EF7EB2B0226B90087E6E9 /* NCManageDatabase+UserStatus.swift in Sources */, F771E3F820E239B500AFB62D /* FileProviderExtension+Thumbnail.swift in Sources */, + F76882392C0DD230001CF441 /* NCKeychain.swift in Sources */, F343A4BF2A1E734600DDA874 /* Optional+Extension.swift in Sources */, AF4BF62027562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */, F785EEA62461A4FB00B3F945 /* CCUtility.m in Sources */, @@ -4098,7 +4182,6 @@ F78C6FDE296D677300C952C3 /* NCContextMenu.swift in Sources */, F7E402332BA89551007E5609 /* NCTrash+Networking.swift in Sources */, F7E7AEA72BA32D0000512E52 /* NCCollectionViewUnifiedSearch.swift in Sources */, - F769CA172965AB7C00039397 /* NCUploadAssets.swift in Sources */, F73EF7A72B0223900087E6E9 /* NCManageDatabase+Comments.swift in Sources */, F7AE00F8230E81CB007ACF8A /* NCBrowserWeb.swift in Sources */, F702F30825EE5D47008F8E80 /* NCPopupViewController.swift in Sources */, @@ -4106,8 +4189,10 @@ 370D26AF248A3D7A00121797 /* NCCellProtocol.swift in Sources */, F77B0DF51D118A16002130FE /* CCUtility.m in Sources */, F70D87D025EE6E58008CBBBD /* NCRenameFile.swift in Sources */, + F768822C2C0DD1E7001CF441 /* NCKeychain.swift in Sources */, F71CD6CA2930D7B1006C95C1 /* NCApplicationHandle.swift in Sources */, F73EF7D72B0226080087E6E9 /* NCManageDatabase+Tip.swift in Sources */, + F76882402C0DD30B001CF441 /* ViewOnAppear.swift in Sources */, F790110E21415BF600D7B136 /* NCViewerRichDocument.swift in Sources */, F78ACD4021903CC20088454D /* NCGridCell.swift in Sources */, F7D890752BD25C570050B8A6 /* NCCollectionViewCommon+DragDrop.swift in Sources */, @@ -4115,6 +4200,7 @@ F75B0ABD244C4DBB00E58DCA /* NCActionCenter.swift in Sources */, AF935067276B84E700BD078F /* NCMenu+FloatingPanel.swift in Sources */, F321DA8A2B71205A00DDA0E6 /* NCTrashSelectTabBar.swift in Sources */, + F76882282C0DD1E7001CF441 /* NCEndToEndInitialize.swift in Sources */, F702F2CD25EE5B4F008F8E80 /* AppDelegate.swift in Sources */, F769454022E9F077000A798A /* NCSharePaging.swift in Sources */, F7802B322BD5584F00D74270 /* NCMedia+DragDrop.swift in Sources */, @@ -4126,9 +4212,11 @@ F702F2CF25EE5B5C008F8E80 /* NCGlobal.swift in Sources */, F794E13F2BBC0F70003693D7 /* SceneDelegate.swift in Sources */, F72CD63A25C19EBF00F46F9A /* NCAutoUpload.swift in Sources */, + F768822F2C0DD1E7001CF441 /* NCAutoUploadModel.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 */, F757CC8229E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */, F7B769A82B7A0B2000C1AAEB /* NCManageDatabase+Metadata+Session.swift in Sources */, @@ -4141,9 +4229,9 @@ F70753F12542A9A200972D44 /* NCViewerMedia.swift in Sources */, F76B649C2ADFFAED00014640 /* NCImageCache.swift in Sources */, F78A18B823CDE2B300F681F3 /* NCViewerRichWorkspace.swift in Sources */, + F768822E2C0DD1E7001CF441 /* NCSettingsBundleHelper.swift in Sources */, F7A60F86292D215000FCE1F2 /* NCShareAccounts.swift in Sources */, F72408332B8A27C900F128E2 /* NCMedia+Command.swift in Sources */, - F77910AB25DD53C700CEDB9E /* NCSettingsBundleHelper.swift in Sources */, F755CB402B8CB13C00CE27E9 /* NCMediaLayout.swift in Sources */, F73EF7B72B0224AB0087E6E9 /* NCManageDatabase+ExternalSites.swift in Sources */, AF4BF61927562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */, @@ -4154,6 +4242,7 @@ AF36077127BFA4E8001A243D /* ParallelWorker.swift in Sources */, F75A9EE623796C6F0044CFCE /* NCNetworking.swift in Sources */, F758B460212C56A400515F55 /* NCScan.swift in Sources */, + F76882262C0DD1E7001CF441 /* NCSettingsView.swift in Sources */, F78ACD52219046DC0088454D /* NCSectionHeaderMenu.swift in Sources */, F72944F52A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */, F710D2022405826100A6033D /* NCViewer+Menu.swift in Sources */, @@ -4171,14 +4260,14 @@ F77BB746289984CA0090FC19 /* UIViewController+Extension.swift in Sources */, F700510522DF6A89003A3356 /* NCShare.swift in Sources */, F72D1007210B6882009C96B7 /* NCPushNotificationEncryption.m in Sources */, + F76882362C0DD1E7001CF441 /* NCAcknowledgementsView.swift in Sources */, F785EE9D246196DF00B3F945 /* NCNetworkingE2EE.swift in Sources */, F76673ED22C901F6007ED366 /* FileProviderDomain.swift in Sources */, - F7A321AD1E9E6AD50069AD1B /* CCAdvanced.m in Sources */, F794E13D2BBBFF2E003693D7 /* NCMainTabBarController.swift in Sources */, - F77B0E4F1D118A16002130FE /* CCManageAutoUpload.m in Sources */, F7CBC1252BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.swift in Sources */, F75C0C4823D1FAE300163CC8 /* NCRichWorkspaceCommon.swift in Sources */, F78ACD4A21903F850088454D /* NCTrashListCell.swift in Sources */, + F76882352C0DD1E7001CF441 /* NCWebBrowserView.swift in Sources */, F3A047972BD2668800658E7B /* NCAssistantEmptyView.swift in Sources */, F757CC8D29E82D0500F31428 /* NCGroupfolders.swift in Sources */, F760329F252F0F8E0015A421 /* NCTransferCell.swift in Sources */, @@ -4187,7 +4276,6 @@ F7682FE023C36B0500983A04 /* NCMainTabBar.swift in Sources */, F7A0D1352591FBC5008F8A13 /* String+Extension.swift in Sources */, F7CEE6012BA9A5C9003EFD89 /* NCTrashGridCell.swift in Sources */, - F77B0E5F1D118A16002130FE /* NCSettings.m in Sources */, F7F9D1BB25397CE000D9BFF5 /* NCViewer.swift in Sources */, F7E7AEA52BA32C6500512E52 /* NCCollectionViewDownloadThumbnail.swift in Sources */, AF730AF827834B1400B7520E /* NCShare+NCCellDelegate.swift in Sources */, @@ -4213,38 +4301,45 @@ F7EB9B132BBC12F300EDF036 /* UIApplication+Extension.swift in Sources */, F7E98C1627E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */, F7F4F11227ECDC52008676F9 /* UIFont+Extension.swift in Sources */, + F76882222C0DD1E7001CF441 /* NCCapabilitiesView.swift in Sources */, AF93471A27E2361E002537EE /* NCShareAdvancePermissionHeader.swift in Sources */, F7F878AE1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */, 3781B9B023DB2B7E006B4B1D /* AppDelegate+Menu.swift in Sources */, F710D1F52405770F00A6033D /* NCViewerPDF.swift in Sources */, F7B6B70427C4E7FA00A7F6EB /* NCScan+CollectionView.swift in Sources */, + F76882342C0DD1E7001CF441 /* NCDisplayView.swift in Sources */, F7C30DF6291BC0CA0017149B /* NCNetworkingE2EEUpload.swift in Sources */, F7501C332212E57500FB1415 /* NCMedia.swift in Sources */, F72944F22A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */, F70BFC7420E0FA7D00C67599 /* NCUtility.swift in Sources */, F79EDAA526B004980007D134 /* NCPlayer.swift in Sources */, F7C1EEA525053A9C00866ACC /* NCDataSource.swift in Sources */, + F76882432C0DD3B4001CF441 /* CCManageAccount.m in Sources */, F713FF002472764100214AF6 /* UIImage+animatedGIF.m in Sources */, AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */, F718C24E254D507B00C5C256 /* NCViewerMediaDetailView.swift in Sources */, F7145610296433C80038D028 /* NCDocumentCamera.swift in Sources */, + F76882312C0DD1E7001CF441 /* NCAutoUploadFileNamesView.swift in Sources */, F7381EE1218218C9000B1560 /* NCOffline.swift in Sources */, + F7FA80002C0F4F3B0072FC60 /* NCUploadAssetsModel.swift in Sources */, F719D9E2288D396100762E33 /* NCColorPicker.swift in Sources */, F73EF7DF2B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */, F79B646026CA661600838ACA /* UIControl+Extension.swift in Sources */, + F768823E2C0DD305001CF441 /* LazyView.swift in Sources */, F7CA212D25F1333300826ABB /* NCAccountRequest.swift in Sources */, F765F73125237E3F00391DBE /* NCRecent.swift in Sources */, F76B3CCE1EAE01BD00921AC9 /* NCBrand.swift in Sources */, + F7FA7FFC2C0F4EE40072FC60 /* NCViewerQuickLookView.swift in Sources */, F3A0479B2BD2668800658E7B /* NCAssistant.swift in Sources */, F359D8672A7D03420023F405 /* NCUtility+Exif.swift in Sources */, F738D4902756740100CD1D38 /* NCLoginNavigationController.swift in Sources */, - F77B0E981D118A16002130FE /* CCManageAccount.m in Sources */, F769CA192966EA3C00039397 /* ComponentView.swift in Sources */, F7C9B91D2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */, AF93474C27E34120002537EE /* NCUtility+Image.swift in Sources */, F702F30125EE5D2C008F8E80 /* NYMnemonic.m in Sources */, AF93474E27E3F212002537EE /* NCShareNewUserAddComment.swift in Sources */, F7C30DFD291BD0B80017149B /* NCNetworkingE2EEDelete.swift in Sources */, + F76882302C0DD1E7001CF441 /* NCAutoUploadFileNamesModel.swift in Sources */, F72FD3B5297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */, F73EF7CF2B0225BA0087E6E9 /* NCManageDatabase+Tag.swift in Sources */, F3A047982BD2668800658E7B /* NCAssistantCreateNewTask.swift in Sources */, @@ -4260,12 +4355,11 @@ F76D364628A4F8BF00214537 /* NCActivityIndicator.swift in Sources */, F3A047992BD2668800658E7B /* NCAssistantTask.swift in Sources */, F7134186259747BA00768D21 /* NCPushNotification.m in Sources */, + F76882322C0DD1E7001CF441 /* NCAutoUploadView.swift in Sources */, F36E64F72B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBarDelegate.swift in Sources */, F3BB464F2A39EBE500461F6E /* NCMoreUserCell.swift in Sources */, - F726EEEC1FED1C820030B9C8 /* NCEndToEndInitialize.swift in Sources */, F79A65C62191D95E00FF6DCC /* NCSelect.swift in Sources */, F75D19E325EFE09000D74598 /* NCTrash+Menu.swift in Sources */, - F7FC5EE12A1768D700D921F5 /* NCCapabilitiesView.swift in Sources */, F70CAE3A1F8CF31A008125FD /* NCEndToEndEncryption.m in Sources */, AF93471B27E2361E002537EE /* NCShareAdvancePermission.swift in Sources */, F77BC3ED293E528A005F2B08 /* NCConfigServer.swift in Sources */, @@ -4280,6 +4374,7 @@ F7AE00F5230D5F9E007ACF8A /* NCLoginWeb.swift in Sources */, F707C26521A2DC5200F6181E /* NCStoreReview.swift in Sources */, F7BAADCB1ED5A87C00B7EAD4 /* NCManageDatabase.swift in Sources */, + F768822A2C0DD1E7001CF441 /* NCSettingsModel.swift in Sources */, F737DA9D2B7B893C0063BAFC /* NCPasscode.swift in Sources */, F77C97392953131000FDDD09 /* NCCameraRoll.swift in Sources */, F343A4B32A1E01FF00DDA874 /* PHAsset+Extension.swift in Sources */, @@ -4292,7 +4387,6 @@ F745B253222D88AE00346520 /* NCLoginQRCode.swift in Sources */, F769454822E9F20D000A798A /* NCShareNetworking.swift in Sources */, F749B64A297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */, - F760DE172AE66F350027D78A /* NCKeychain.swift in Sources */, F7C9555521F0C5470024296E /* NCActivity.swift in Sources */, F7725A60251F33BB00D125E0 /* NCFiles.swift in Sources */, F3BB46522A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift in Sources */, @@ -4301,23 +4395,24 @@ F7327E352B73AEDE00A462C7 /* NCNetworking+LivePhoto.swift in Sources */, F76687072B7D067400779E3F /* NCAudioRecorderViewController.swift in Sources */, F343A4BB2A1E734600DDA874 /* Optional+Extension.swift in Sources */, + F76882232C0DD1E7001CF441 /* NCCapabilitiesModel.swift in Sources */, F7D68FCC28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */, + F76882292C0DD1E7001CF441 /* NCManageE2EEModel.swift in Sources */, F78E2D6529AF02DB0024D4F3 /* Database.swift in Sources */, F70CEF5623E9C7E50007035B /* UIColor+Extension.swift in Sources */, + F76882242C0DD1E7001CF441 /* NCSettingsAdvancedView.swift in Sources */, F75CA1472962F13700B01130 /* HUDView.swift in Sources */, - F7A48413297022E000BD1B49 /* ViewerQuickLook.swift in Sources */, F77BB748289985270090FC19 /* UITabBarController+Extension.swift in Sources */, F763D29D2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */, - F75AC2431F1F62450073EC19 /* NCManageAutoUploadFileName.swift in Sources */, - F7A7FA6329265CF4000603EF /* NCManageE2EE.swift in Sources */, + F76882252C0DD1E7001CF441 /* NCSettingsAdvancedModel.swift in Sources */, F7C7B489245EBA4100D93E60 /* NCViewerQuickLook.swift in Sources */, F758B45E212C569D00515F55 /* NCScanCell.swift in Sources */, F78B87E72B62527100C65ADC /* NCMediaDataSource.swift in Sources */, F7581D1A25EFDA61004DC699 /* NCLoginWeb+Menu.swift in Sources */, + F76882272C0DD1E7001CF441 /* NCManageE2EEView.swift in Sources */, F7864ACC2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */, F7F4F11027ECDC4A008676F9 /* UIDevice+Extension.swift in Sources */, F7327E302B73A86700A462C7 /* NCNetworking+WebDAV.swift in Sources */, - F77B0ED11D118A16002130FE /* Acknowledgements.m in Sources */, F79FFB262A97C24A0055EEA4 /* NCNetworkingE2EEMarkFolder.swift in Sources */, F70D8D8124A4A9BF000A5756 /* NCNetworkingProcess.swift in Sources */, F3A0479A2BD2668800658E7B /* NCAssistantTaskDetail.swift in Sources */, @@ -4325,6 +4420,7 @@ F38F71252B6BBDC300473CDC /* NCCollectionViewCommonSelectTabBar.swift in Sources */, F7E4D9C422ED929B003675FD /* NCShareCommentsCell.swift in Sources */, F7327E202B73A42F00A462C7 /* NCNetworking+Download.swift in Sources */, + F76882332C0DD1E7001CF441 /* NCDisplayModel.swift in Sources */, F717402E24F699A5000C87D5 /* NCFavorite.swift in Sources */, AF2D7C7E2742559100ADF566 /* NCShareUserCell.swift in Sources */, F74DE14325135B6800917068 /* NCTransfers.swift in Sources */, @@ -4363,6 +4459,7 @@ F73EF7A92B0223900087E6E9 /* NCManageDatabase+Comments.swift in Sources */, F7A8D73C28F181BC008BBE1C /* NCBrand.swift in Sources */, F711A4DE2AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */, + F768823B2C0DD231001CF441 /* NCKeychain.swift in Sources */, F7A8D74228F18261008BBE1C /* NCUtility.swift in Sources */, F7A8D73A28F17E28008BBE1C /* NCManageDatabase+Video.swift in Sources */, F7A8D73828F17E21008BBE1C /* NCManageDatabase+DashboardWidget.swift in Sources */, @@ -4370,7 +4467,6 @@ F73EF7E92B0226B90087E6E9 /* NCManageDatabase+UserStatus.swift in Sources */, F73EF7B12B0224350087E6E9 /* NCManageDatabase+DirectEditing.swift in Sources */, F343A4B52A1E084200DDA874 /* PHAsset+Extension.swift in Sources */, - F7183BD52AEBDCD7000CD020 /* NCKeychain.swift in Sources */, F72FD3B7297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */, F7A8D74128F18254008BBE1C /* UIColor+Extension.swift in Sources */, F73EF7D92B0226080087E6E9 /* NCManageDatabase+Tip.swift in Sources */, diff --git a/iOSClient/Diagnostics/NCCapabilitiesView.swift b/iOSClient/Diagnostics/NCCapabilitiesView.swift deleted file mode 100644 index 5265fa3cab..0000000000 --- a/iOSClient/Diagnostics/NCCapabilitiesView.swift +++ /dev/null @@ -1,203 +0,0 @@ -// -// NCCapabilitiesView.swift -// Nextcloud -// -// Created by Marino Faggiana on 19/05/23. -// Copyright © 2023 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 - -@objc class NCHostingCapabilitiesView: NSObject { - - @objc func makeShipDetailsUI() -> UIViewController { - - let capabilitiesStatus = NCCapabilitiesViewOO() - let view = NCCapabilitiesView(capabilitiesStatus: capabilitiesStatus) - let vc = UIHostingController(rootView: view) - vc.title = NSLocalizedString("_capabilities_", comment: "") - return vc - } -} - -class NCCapabilitiesViewOO: ObservableObject { - - struct Capability: Identifiable, Hashable { - let id = UUID() - let text: String - let image: UIImage - let resize: Bool - let available: Bool - } - - @Published var capabililies: [Capability] = [] - @Published var homeServer = "" - let utilityFileSystem = NCUtilityFileSystem() - let utility = NCUtility() - - init() { - loadCapabilities() - NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeUser), object: nil, queue: nil) { _ in - self.loadCapabilities() - } - } - - func loadCapabilities() { - guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return } - var textEditor = false - var onlyofficeEditors = false - - capabililies.removeAll() - - var image = utility.loadImage(named: "person.fill.badge.plus") - capabililies.append(Capability(text: "File sharing", image: image, resize: false, available: NCGlobal.shared.capabilityFileSharingApiEnabled)) - - image = utility.loadImage(named: "network") - capabililies.append(Capability(text: "External site", image: image, resize: false, available: NCGlobal.shared.capabilityExternalSites)) - - image = utility.loadImage(named: "lock") - capabililies.append(Capability(text: "End-to-End Encryption", image: image, resize: false, available: NCGlobal.shared.capabilityE2EEEnabled)) - - image = utility.loadImage(named: "bolt") - capabililies.append(Capability(text: "Activity", image: image, resize: false, available: !NCGlobal.shared.capabilityActivity.isEmpty)) - - image = utility.loadImage(named: "bell") - capabililies.append(Capability(text: "Notification", image: image, resize: false, available: !NCGlobal.shared.capabilityNotification.isEmpty)) - - image = utility.loadImage(named: "trash") - capabililies.append(Capability(text: "Deleted files", image: image, resize: false, available: NCGlobal.shared.capabilityFilesUndelete)) - - if let editors = NCManageDatabase.shared.getDirectEditingEditors(account: activeAccount.account) { - for editor in editors { - if editor.editor == NCGlobal.shared.editorText { - textEditor = true - } else if editor.editor == NCGlobal.shared.editorOnlyoffice { - onlyofficeEditors = true - } - } - } - - capabililies.append(Capability(text: "Text", image: utility.loadImage(named: "doc.text"), resize: false, available: textEditor)) - - capabililies.append(Capability(text: "ONLYOFFICE", image: utility.loadImage(named: "onlyoffice"), resize: true, available: onlyofficeEditors)) - - capabililies.append(Capability(text: "Collabora", image: utility.loadImage(named: "collabora"), resize: true, available: NCGlobal.shared.capabilityRichDocumentsEnabled)) - - capabililies.append(Capability(text: "User Status", image: utility.loadImage(named: "moon"), resize: false, available: NCGlobal.shared.capabilityUserStatusEnabled)) - - capabililies.append(Capability(text: "Comments", image: utility.loadImage(named: "ellipsis.bubble"), resize: false, available: NCGlobal.shared.capabilityFilesComments)) - - capabililies.append(Capability(text: "Lock file", image: utility.loadImage(named: "lock"), resize: false, available: !NCGlobal.shared.capabilityFilesLockVersion.isEmpty)) - - capabililies.append(Capability(text: "Group folders", image: utility.loadImage(named: "person.2"), resize: false, available: NCGlobal.shared.capabilityGroupfoldersEnabled)) - - if NCBrandOptions.shared.brand != "Nextcloud" { - capabililies.append(Capability(text: "Security Guard Diagnostics", image: utility.loadImage(named: "shield"), resize: false, available: NCGlobal.shared.capabilitySecurityGuardDiagnostics)) - } - - capabililies.append(Capability(text: "Assistant", image: utility.loadImage(named: "sparkles"), resize: false, available: NCGlobal.shared.capabilityAssistantEnabled)) - - homeServer = utilityFileSystem.getHomeServer(urlBase: activeAccount.urlBase, userId: activeAccount.userId) + "/" - } -} - -struct NCCapabilitiesView: View { - - @ObservedObject var capabilitiesViewOO: NCCapabilitiesViewOO - - init(capabilitiesStatus: NCCapabilitiesViewOO) { - self.capabilitiesViewOO = capabilitiesStatus - } - - var body: some View { - VStack { - List { - Section { - ForEach(capabilitiesViewOO.capabililies, id: \.id) { capability in - HStack { - CapabilityName(text: Binding.constant(capability.text), image: Image(uiImage: capability.image), resize: capability.resize) - CapabilityStatus(available: capability.available) - } - } - } - Section { - CapabilityName(text: $capabilitiesViewOO.homeServer, image: Image(uiImage: NCUtility().loadImage(named: "house")), resize: false) - } - } - } - .frame(maxWidth: .infinity, alignment: .top) - } - - struct CapabilityName: View { - - @Binding var text: String - @State var image: Image - @State var resize: Bool - - var body: some View { - Label { - Text(text) - .font(.system(size: 15)) - } icon: { - if resize { - image - .renderingMode(.template) - .resizable() - .scaledToFill() - .frame(width: 23.0, height: 23.0) - .foregroundColor(.primary) - } else { - image - .renderingMode(.template) - .foregroundColor(.primary) - } - } - .frame(maxWidth: .infinity, alignment: .leading) - } - } - - struct CapabilityStatus: View { - - @State var available: Bool - - var body: some View { - if available { - Image(systemName: "checkmark.circle.fill") - .foregroundColor(.green) - } else { - Image(systemName: "multiply.circle.fill") - .foregroundColor(Color(NCBrandColor.shared.textColor2)) - } - } - } -} - -#Preview { - func getCapabilitiesViewOOForPreview() -> NCCapabilitiesViewOO { - let capabilitiesViewOO = NCCapabilitiesViewOO() - capabilitiesViewOO.capabililies = [ - NCCapabilitiesViewOO.Capability(text: "Collabora", image: UIImage(named: "collabora")!, resize: true, available: true), - NCCapabilitiesViewOO.Capability(text: "XXX site", image: UIImage(systemName: "lock.shield")!, resize: false, available: false) - ] - capabilitiesViewOO.homeServer = "https://cloud.nextcloud.com/remote.php.dav/files/marino/" - return capabilitiesViewOO - } - - return NCCapabilitiesView(capabilitiesStatus: getCapabilitiesViewOOForPreview()) -} diff --git a/iOSClient/GUI/HUDView.swift b/iOSClient/GUI/HUDView.swift index 7f51cb7379..789c7711c1 100644 --- a/iOSClient/GUI/HUDView.swift +++ b/iOSClient/GUI/HUDView.swift @@ -85,7 +85,7 @@ struct ContentView: View { } HUDView(showHUD: $showHUD, textLabel: NSLocalizedString("_wait_", comment: ""), image: "doc.badge.arrow.up") .offset(y: showHUD ? (geo.size.height / 2) : -200) - .animation(.easeOut) + .animation(.easeOut, value: showHUD) } } } diff --git a/iOSClient/Settings/CCAdvanced.h b/iOSClient/GUI/LazyView.swift old mode 100755 new mode 100644 similarity index 63% rename from iOSClient/Settings/CCAdvanced.h rename to iOSClient/GUI/LazyView.swift index 7f9845888f..1c77c1afc5 --- a/iOSClient/Settings/CCAdvanced.h +++ b/iOSClient/GUI/LazyView.swift @@ -1,9 +1,9 @@ // -// CCAdvanced.h +// LazyView.swift // Nextcloud // -// Created by Marino Faggiana on 12/04/17. -// Copyright (c) 2017 Marino Faggiana. All rights reserved. +// Created by Marino Faggiana on 01/06/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. // // Author Marino Faggiana // @@ -21,9 +21,15 @@ // along with this program. If not, see . // -#import -#import +import SwiftUI -@interface CCAdvanced : XLFormViewController - -@end +/// LazyView is a view that delays the initialization of its contained view until it is actually needed. +struct LazyView: View { + let build: () -> Content + init(_ build: @escaping () -> Content) { + self.build = build + } + var body: Content { + build() + } +} diff --git a/iOSClient/GUI/ViewOnAppear.swift b/iOSClient/GUI/ViewOnAppear.swift new file mode 100644 index 0000000000..4a4937f27e --- /dev/null +++ b/iOSClient/GUI/ViewOnAppear.swift @@ -0,0 +1,49 @@ +// +// ViewOnAppear.swift +// Nextcloud +// +// Created by Aditya Tyagi on 17/03/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Aditya Tyagi +// +// 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 SwiftUI + +/// A protocol defining methods to handle view appearance events. +protocol ViewOnAppearHandling: ObservableObject { + /// Triggered when the view appears. + func onViewAppear() +} + +extension View { + @discardableResult func defaultViewModifier(_ model: some ViewOnAppearHandling) -> some View { + return modifier(DefaultViewModifier(viewModel: model)) + } +} + +/// A view modifier that automatically calls a view model's `onViewAppear` function when the view appears on screen. +struct DefaultViewModifier: ViewModifier { + @ObservedObject var viewModel: ViewModel + + func body(content: Content) -> some View { + content + .onAppear { + viewModel.onViewAppear() // Call onViewAppear on view appearance + } + } +} diff --git a/iOSClient/Main/Create cloud/NCUploadAssets.swift b/iOSClient/Main/Create cloud/NCUploadAssets.swift deleted file mode 100644 index 2acf997390..0000000000 --- a/iOSClient/Main/Create cloud/NCUploadAssets.swift +++ /dev/null @@ -1,577 +0,0 @@ -// -// NCUploadAssets.swift -// Nextcloud -// -// Created by Marino Faggiana on 04/01/23. -// Copyright © 2023 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 TLPhotoPicker -import Mantis -import Photos -import QuickLook - -class NCHostingUploadAssetsView: NSObject { - - func makeShipDetailsUI(assets: [TLPHAsset], serverUrl: String, userBaseUrl: NCUserBaseUrl) -> UIViewController { - - let uploadAssets = NCUploadAssets(assets: assets, serverUrl: serverUrl, userBaseUrl: userBaseUrl ) - let details = UploadAssetsView(uploadAssets: uploadAssets) - return UIHostingController(rootView: details) - } -} - -// MARK: - Class - -struct PreviewStore { - var id: String - var asset: TLPHAsset - var assetType: TLPHAsset.AssetType - var data: Data? - var fileName: String - var image: UIImage -} - -class NCUploadAssets: NSObject, ObservableObject, NCCreateFormUploadConflictDelegate { - @Published var serverUrl: String - @Published var assets: [TLPHAsset] - @Published var userBaseUrl: NCUserBaseUrl - @Published var dismiss = false - @Published var isHiddenSave = true - @Published var isUseAutoUploadFolder: Bool = false - @Published var isUseAutoUploadSubFolder: Bool = false - @Published var previewStore: [PreviewStore] = [] - @Published var showHUD: Bool = false - @Published var uploadInProgress: Bool = false - - var metadatasNOConflict: [tableMetadata] = [] - var metadatasUploadInConflict: [tableMetadata] = [] - var timer: Timer? - - init(assets: [TLPHAsset], serverUrl: String, userBaseUrl: NCUserBaseUrl) { - - self.assets = assets - self.serverUrl = serverUrl - self.userBaseUrl = userBaseUrl - } - - func loadImages() { - var previewStore: [PreviewStore] = [] - self.showHUD = true - DispatchQueue.global().async { - for asset in self.assets { - guard let image = asset.fullResolutionImage?.resizeImage(size: CGSize(width: 300, height: 300), isAspectRation: true), let localIdentifier = asset.phAsset?.localIdentifier else { continue } - previewStore.append(PreviewStore(id: localIdentifier, asset: asset, assetType: asset.type, fileName: "", image: image)) - } - DispatchQueue.main.async { - self.showHUD = false - self.previewStore = previewStore - self.isHiddenSave = false - } - } - } - - func startTimer(navigationItem: UINavigationItem) { - self.timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { _ in - guard let buttonDone = navigationItem.leftBarButtonItems?.first, let buttonCrop = navigationItem.leftBarButtonItems?.last else { return } - buttonCrop.isEnabled = true - buttonDone.isEnabled = true - if let markup = navigationItem.rightBarButtonItems?.first(where: { $0.accessibilityIdentifier == "QLOverlayMarkupButtonAccessibilityIdentifier" }) { - if let originalButton = markup.value(forKey: "originalButton") as AnyObject? { - if let symbolImageName = originalButton.value(forKey: "symbolImageName") as? String { - if symbolImageName == "pencil.tip.crop.circle.on" { - buttonCrop.isEnabled = false - buttonDone.isEnabled = false - } - } - } - } - }) - } - - func stopTimer() { - self.timer?.invalidate() - } - - func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) { - guard let metadatas = metadatas else { - self.showHUD = false - self.uploadInProgress.toggle() - return - } - - func createProcessUploads() { - if !self.dismiss { - NCNetworkingProcess.shared.createProcessUploads(metadatas: metadatas, completion: { _ in - self.dismiss = true - }) - } - } - - if isUseAutoUploadFolder { - DispatchQueue.global().async { - let assets = self.assets.compactMap { $0.phAsset } - let result = NCNetworking.shared.createFolder(assets: assets, useSubFolder: self.isUseAutoUploadSubFolder, account: self.userBaseUrl.account, urlBase: self.userBaseUrl.urlBase, userId: self.userBaseUrl.userId, withPush: false) - DispatchQueue.main.async { - self.showHUD = false - self.uploadInProgress.toggle() - if result { - createProcessUploads() - } else { - let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_error_createsubfolders_upload_") - NCContentPresenter().showError(error: error) - } - } - } - } else { - createProcessUploads() - } - } -} - -// MARK: - View - -struct UploadAssetsView: View { - @State private var fileName: String = NCKeychain().getFileNameMask(key: NCGlobal.shared.keyFileNameMask) - @State private var isMaintainOriginalFilename: Bool = NCKeychain().getOriginalFileName(key: NCGlobal.shared.keyFileNameOriginal) - @State private var isAddFilenametype: Bool = NCKeychain().getFileNameType(key: NCGlobal.shared.keyFileNameType) - @State private var isPresentedSelect = false - @State private var isPresentedUploadConflict = false - @State private var isPresentedQuickLook = false - @State private var isPresentedAlert = false - @State private var fileNamePath = NSTemporaryDirectory() + "Photo.jpg" - @State private var renameFileName: String = "" - @State private var renameIndex: Int = 0 - @State private var metadata: tableMetadata? - @State private var index: Int = 0 - - var gridItems: [GridItem] = [GridItem()] - - @ObservedObject var uploadAssets: NCUploadAssets - @Environment(\.presentationMode) var presentationMode - - init(uploadAssets: NCUploadAssets) { - self.uploadAssets = uploadAssets - uploadAssets.loadImages() - } - - func getTextServerUrl(_ serverUrl: String) -> String { - if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", uploadAssets.userBaseUrl.account, serverUrl)), let metadata = NCManageDatabase.shared.getMetadataFromOcId(directory.ocId) { - return (metadata.fileNameView) - } else { - return (serverUrl as NSString).lastPathComponent - } - } - - private func setFileNameMaskForPreview(fileName: String?) -> String { - guard let asset = uploadAssets.assets.first?.phAsset else { return "" } - var preview: String = "" - let creationDate = asset.creationDate ?? Date() - - NCKeychain().setOriginalFileName(key: NCGlobal.shared.keyFileNameOriginal, value: isMaintainOriginalFilename) - NCKeychain().setFileNameType(key: NCGlobal.shared.keyFileNameType, prefix: isAddFilenametype) - NCKeychain().setFileNameMask(key: NCGlobal.shared.keyFileNameMask, mask: fileName) - - preview = CCUtility.createFileName( - getOriginalFilenameForPreview() as String, - fileDate: creationDate, - fileType: asset.mediaType, - keyFileName: fileName.isEmptyOrNil ? nil : NCGlobal.shared.keyFileNameMask, - keyFileNameType: NCGlobal.shared.keyFileNameType, - keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, - forcedNewFileName: false - ) - - let trimmedPreview = preview.trimmingCharacters(in: .whitespacesAndNewlines) - - return String(format: NSLocalizedString("_preview_filename_", comment: ""), "MM, MMM, DD, YY, YYYY, HH, hh, mm, ss, ampm") + ":" + "\n\n" + (trimmedPreview as NSString).deletingPathExtension - } - - private func save(completion: @escaping (_ metadatasNOConflict: [tableMetadata], _ metadatasUploadInConflict: [tableMetadata]) -> Void) { - - let utilityFileSystem = NCUtilityFileSystem() - var metadatasNOConflict: [tableMetadata] = [] - var metadatasUploadInConflict: [tableMetadata] = [] - let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: uploadAssets.userBaseUrl.urlBase, userId: uploadAssets.userBaseUrl.userId, account: uploadAssets.userBaseUrl.account) - var serverUrl = uploadAssets.isUseAutoUploadFolder ? autoUploadPath : uploadAssets.serverUrl - - for tlAsset in uploadAssets.assets { - guard let asset = tlAsset.phAsset, let previewStore = uploadAssets.previewStore.first(where: { $0.id == asset.localIdentifier }) else { continue } - - let assetFileName = asset.originalFilename - var livePhoto: Bool = false - let creationDate = asset.creationDate ?? Date() - let ext = assetFileName.pathExtension.lowercased() - - let fileName = previewStore.fileName.isEmpty - ? CCUtility.createFileName(assetFileName as String, - fileDate: creationDate, - fileType: asset.mediaType, - keyFileName: NCGlobal.shared.keyFileNameMask, - keyFileNameType: NCGlobal.shared.keyFileNameType, - keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, - forcedNewFileName: false)! - : (previewStore.fileName + "." + ext) - - if previewStore.assetType == .livePhoto && NCKeychain().livePhoto && previewStore.data == nil { - livePhoto = true - } - - // Auto upload with subfolder - if uploadAssets.isUseAutoUploadSubFolder { - serverUrl = utilityFileSystem.createGranularityPath(serverUrl: serverUrl) - } - - // Check if is in upload - if let results = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@ AND session != ''", uploadAssets.userBaseUrl.account, serverUrl, fileName), sorted: "fileName", ascending: false), !results.isEmpty { - continue - } - - let metadata = NCManageDatabase.shared.createMetadata(account: uploadAssets.userBaseUrl.account, user: uploadAssets.userBaseUrl.user, userId: uploadAssets.userBaseUrl.userId, fileName: fileName, fileNameView: fileName, ocId: NSUUID().uuidString, serverUrl: serverUrl, urlBase: uploadAssets.userBaseUrl.urlBase, url: "", contentType: "") - - if livePhoto { - metadata.livePhotoFile = (metadata.fileName as NSString).deletingPathExtension + ".mov" - } - metadata.assetLocalIdentifier = asset.localIdentifier - metadata.session = NCNetworking.shared.sessionUploadBackground - metadata.sessionSelector = NCGlobal.shared.selectorUploadFile - metadata.status = NCGlobal.shared.metadataStatusWaitUpload - metadata.sessionDate = Date() - - // Modified - if let previewStore = uploadAssets.previewStore.first(where: { $0.id == asset.localIdentifier }), let data = previewStore.data { - if metadata.contentType == "image/heic" { - let fileNameNoExtension = (fileName as NSString).deletingPathExtension - metadata.contentType = "image/jpeg" - metadata.fileName = fileNameNoExtension + ".jpg" - metadata.fileNameView = fileNameNoExtension + ".jpg" - } - let fileNamePath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView) - do { - try data.write(to: URL(fileURLWithPath: fileNamePath)) - metadata.isExtractFile = true - metadata.size = utilityFileSystem.getFileSize(filePath: fileNamePath) - metadata.creationDate = asset.creationDate as? NSDate ?? (Date() as NSDate) - metadata.date = asset.modificationDate as? NSDate ?? (Date() as NSDate) - } catch { } - } - - if let result = NCManageDatabase.shared.getMetadataConflict(account: uploadAssets.userBaseUrl.account, serverUrl: serverUrl, fileNameView: fileName) { - metadata.fileName = result.fileName - metadatasUploadInConflict.append(metadata) - } else { - metadatasNOConflict.append(metadata) - } - } - - completion(metadatasNOConflict, metadatasUploadInConflict) - } - - private func presentedQuickLook(index: Int) { - var image: UIImage? - if let imageData = uploadAssets.previewStore[index].data { - image = UIImage(data: imageData) - } else if let imageFullResolution = uploadAssets.previewStore[index].asset.fullResolutionImage?.fixedOrientation() { - image = imageFullResolution - } - if let image = image { - if let data = image.jpegData(compressionQuality: 1) { - do { - try data.write(to: URL(fileURLWithPath: fileNamePath)) - self.index = index - isPresentedQuickLook = true - } catch { - } - } - } - } - - private func deleteAsset(index: Int) { - uploadAssets.assets.remove(at: index) - uploadAssets.previewStore.remove(at: index) - if uploadAssets.previewStore.isEmpty { - uploadAssets.dismiss = true - } - } - - private func getOriginalFilenameForPreview() -> NSString { - NCKeychain().setOriginalFileName(key: NCGlobal.shared.keyFileNameOriginal, value: isMaintainOriginalFilename) - if let asset = uploadAssets.assets.first?.phAsset { - return asset.originalFilename - } else { - return "" - } - } - - var body: some View { - let utilityFileSystem = NCUtilityFileSystem() - - NavigationView { - ZStack(alignment: .top) { - List { - Section(footer: Text(NSLocalizedString("_modify_image_desc_", comment: ""))) { - ScrollView(.horizontal) { - LazyHGrid(rows: gridItems, alignment: .center, spacing: 10) { - ForEach(0.. +// +// 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 TLPhotoPicker +import Mantis +import Photos +import QuickLook + +// MARK: - Class + +struct PreviewStore { + var id: String + var asset: TLPHAsset + var assetType: TLPHAsset.AssetType + var data: Data? + var fileName: String + var image: UIImage +} + +class NCUploadAssetsModel: NSObject, ObservableObject, NCCreateFormUploadConflictDelegate { + @Published var serverUrl: String + @Published var assets: [TLPHAsset] + @Published var userBaseUrl: NCUserBaseUrl + @Published var previewStore: [PreviewStore] = [] + @Published var dismissView = false + @Published var hiddenSave = true + @Published var useAutoUploadFolder = false + @Published var useAutoUploadSubFolder = false + @Published var showHUD = false + @Published var uploadInProgress = false + @Published var fileName: String = NCKeychain().getFileNameMask(key: NCGlobal.shared.keyFileNameMask) + @Published var addFilenametype: Bool = NCKeychain().getFileNameType(key: NCGlobal.shared.keyFileNameType) + @Published var maintainOriginalFilename: Bool = NCKeychain().getOriginalFileName(key: NCGlobal.shared.keyFileNameOriginal) + + /// Root View Controller + @Published var controller: NCMainTabBarController? + + var metadatasNOConflict: [tableMetadata] = [] + var metadatasUploadInConflict: [tableMetadata] = [] + var timer: Timer? + + init(assets: [TLPHAsset], serverUrl: String, userBaseUrl: NCUserBaseUrl, controller: NCMainTabBarController?) { + self.assets = assets + self.serverUrl = serverUrl + self.userBaseUrl = userBaseUrl + self.controller = controller + self.showHUD = true + super.init() + + DispatchQueue.global().async { + for asset in self.assets { + guard let image = asset.fullResolutionImage?.resizeImage(size: CGSize(width: 300, height: 300), isAspectRation: true), + let localIdentifier = asset.phAsset?.localIdentifier else { continue } + self.previewStore.append(PreviewStore(id: localIdentifier, asset: asset, assetType: asset.type, fileName: "", image: image)) + } + DispatchQueue.main.async { + self.showHUD = false + self.hiddenSave = false + } + } + } + + func getTextServerUrl() -> String { + if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", userBaseUrl.account, serverUrl)), let metadata = NCManageDatabase.shared.getMetadataFromOcId(directory.ocId) { + return (metadata.fileNameView) + } else { + return (serverUrl as NSString).lastPathComponent + } + } + + func getOriginalFilenameForPreview() -> NSString { + NCKeychain().setOriginalFileName(key: NCGlobal.shared.keyFileNameOriginal, value: maintainOriginalFilename) + if let asset = assets.first?.phAsset { + return asset.originalFilename + } else { + return "" + } + } + + func deleteAsset(index: Int) { + assets.remove(at: index) + previewStore.remove(at: index) + if previewStore.isEmpty { + dismissView = true + } + } + + func setFileNameMaskForPreview(fileName: String?) -> String { + guard let asset = assets.first?.phAsset else { return "" } + var preview: String = "" + let creationDate = asset.creationDate ?? Date() + + NCKeychain().setOriginalFileName(key: NCGlobal.shared.keyFileNameOriginal, value: maintainOriginalFilename) + NCKeychain().setFileNameType(key: NCGlobal.shared.keyFileNameType, prefix: addFilenametype) + NCKeychain().setFileNameMask(key: NCGlobal.shared.keyFileNameMask, mask: fileName) + + preview = CCUtility.createFileName( + getOriginalFilenameForPreview() as String, + fileDate: creationDate, + fileType: asset.mediaType, + keyFileName: fileName.isEmptyOrNil ? nil : NCGlobal.shared.keyFileNameMask, + keyFileNameType: NCGlobal.shared.keyFileNameType, + keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, + forcedNewFileName: false + ) + + let trimmedPreview = preview.trimmingCharacters(in: .whitespacesAndNewlines) + + return String(format: NSLocalizedString("_preview_filename_", comment: ""), "MM, MMM, DD, YY, YYYY, HH, hh, mm, ss, ampm") + ":" + "\n\n" + (trimmedPreview as NSString).deletingPathExtension + } + + func presentedQuickLook(index: Int, fileNamePath: String) -> Bool { + var image: UIImage? + + if let imageData = previewStore[index].data { + image = UIImage(data: imageData) + } else if let imageFullResolution = previewStore[index].asset.fullResolutionImage?.fixedOrientation() { + image = imageFullResolution + } + if let image = image { + if let data = image.jpegData(compressionQuality: 1) { + do { + try data.write(to: URL(fileURLWithPath: fileNamePath)) + return true + } catch { + } + } + } + return false + } + + func startTimer(navigationItem: UINavigationItem) { + self.timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { _ in + guard let buttonDone = navigationItem.leftBarButtonItems?.first, let buttonCrop = navigationItem.leftBarButtonItems?.last else { return } + buttonCrop.isEnabled = true + buttonDone.isEnabled = true + if let markup = navigationItem.rightBarButtonItems?.first(where: { $0.accessibilityIdentifier == "QLOverlayMarkupButtonAccessibilityIdentifier" }) { + if let originalButton = markup.value(forKey: "originalButton") as AnyObject? { + if let symbolImageName = originalButton.value(forKey: "symbolImageName") as? String { + if symbolImageName == "pencil.tip.crop.circle.on" { + buttonCrop.isEnabled = false + buttonDone.isEnabled = false + } + } + } + } + }) + } + + func stopTimer() { + self.timer?.invalidate() + } + + func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) { + guard let metadatas = metadatas else { + self.showHUD = false + self.uploadInProgress.toggle() + return + } + + func createProcessUploads() { + if !self.dismissView { + NCNetworkingProcess.shared.createProcessUploads(metadatas: metadatas, completion: { _ in + self.dismissView = true + }) + } + } + + if useAutoUploadFolder { + DispatchQueue.global().async { + let assets = self.assets.compactMap { $0.phAsset } + let result = NCNetworking.shared.createFolder(assets: assets, useSubFolder: self.useAutoUploadSubFolder, account: self.userBaseUrl.account, urlBase: self.userBaseUrl.urlBase, userId: self.userBaseUrl.userId, withPush: false) + DispatchQueue.main.async { + self.showHUD = false + self.uploadInProgress.toggle() + if result { + createProcessUploads() + } else { + let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_error_createsubfolders_upload_") + NCContentPresenter().showError(error: error) + } + } + } + } else { + createProcessUploads() + } + } + + func save(completion: @escaping (_ metadatasNOConflict: [tableMetadata], _ metadatasUploadInConflict: [tableMetadata]) -> Void) { + let utilityFileSystem = NCUtilityFileSystem() + var metadatasNOConflict: [tableMetadata] = [] + var metadatasUploadInConflict: [tableMetadata] = [] + let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: userBaseUrl.urlBase, userId: userBaseUrl.userId, account: userBaseUrl.account) + var serverUrl = useAutoUploadFolder ? autoUploadPath : serverUrl + + for tlAsset in assets { + guard let asset = tlAsset.phAsset, let previewStore = previewStore.first(where: { $0.id == asset.localIdentifier }) else { continue } + + let assetFileName = asset.originalFilename + var livePhoto: Bool = false + let creationDate = asset.creationDate ?? Date() + let ext = assetFileName.pathExtension.lowercased() + + let fileName = previewStore.fileName.isEmpty + ? CCUtility.createFileName(assetFileName as String, + fileDate: creationDate, + fileType: asset.mediaType, + keyFileName: NCGlobal.shared.keyFileNameMask, + keyFileNameType: NCGlobal.shared.keyFileNameType, + keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, + forcedNewFileName: false)! + : (previewStore.fileName + "." + ext) + + if previewStore.assetType == .livePhoto && NCKeychain().livePhoto && previewStore.data == nil { + livePhoto = true + } + + // Auto upload with subfolder + if useAutoUploadSubFolder { + serverUrl = utilityFileSystem.createGranularityPath(serverUrl: serverUrl) + } + + // Check if is in upload + if let results = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@ AND session != ''", userBaseUrl.account, serverUrl, fileName), sorted: "fileName", ascending: false), !results.isEmpty { + continue + } + + let metadata = NCManageDatabase.shared.createMetadata(account: userBaseUrl.account, user: userBaseUrl.user, userId: userBaseUrl.userId, fileName: fileName, fileNameView: fileName, ocId: NSUUID().uuidString, serverUrl: serverUrl, urlBase: userBaseUrl.urlBase, url: "", contentType: "") + + if livePhoto { + metadata.livePhotoFile = (metadata.fileName as NSString).deletingPathExtension + ".mov" + } + metadata.assetLocalIdentifier = asset.localIdentifier + metadata.session = NCNetworking.shared.sessionUploadBackground + metadata.sessionSelector = NCGlobal.shared.selectorUploadFile + metadata.status = NCGlobal.shared.metadataStatusWaitUpload + metadata.sessionDate = Date() + + // Modified + if let previewStore = self.previewStore.first(where: { $0.id == asset.localIdentifier }), let data = previewStore.data { + if metadata.contentType == "image/heic" { + let fileNameNoExtension = (fileName as NSString).deletingPathExtension + metadata.contentType = "image/jpeg" + metadata.fileName = fileNameNoExtension + ".jpg" + metadata.fileNameView = fileNameNoExtension + ".jpg" + } + let fileNamePath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView) + do { + try data.write(to: URL(fileURLWithPath: fileNamePath)) + metadata.isExtractFile = true + metadata.size = utilityFileSystem.getFileSize(filePath: fileNamePath) + metadata.creationDate = asset.creationDate as? NSDate ?? (Date() as NSDate) + metadata.date = asset.modificationDate as? NSDate ?? (Date() as NSDate) + } catch { } + } + + if let result = NCManageDatabase.shared.getMetadataConflict(account: userBaseUrl.account, serverUrl: serverUrl, fileNameView: fileName) { + metadata.fileName = result.fileName + metadatasUploadInConflict.append(metadata) + } else { + metadatasNOConflict.append(metadata) + } + } + + completion(metadatasNOConflict, metadatasUploadInConflict) + } +} diff --git a/iOSClient/Main/Create cloud/Upload Assets/NCUploadAssetsView.swift b/iOSClient/Main/Create cloud/Upload Assets/NCUploadAssetsView.swift new file mode 100644 index 0000000000..ddd896e861 --- /dev/null +++ b/iOSClient/Main/Create cloud/Upload Assets/NCUploadAssetsView.swift @@ -0,0 +1,277 @@ +// +// NCUploadAssetsView.swift +// Nextcloud +// +// Created by Marino Faggiana on 03/06/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// + +import SwiftUI + +struct NCUploadAssetsView: View { + @ObservedObject var model: NCUploadAssetsModel + @State private var showSelect = false + @State private var showUploadConflict = false + @State private var showQuickLook = false + @State private var shorRenameAlert = false + @State private var renameFileName: String = "" + @State private var renameIndex: Int = 0 + @State private var index: Int = 0 + + var metadata: tableMetadata? + let gridItems: [GridItem] = [GridItem()] + let fileNamePath = NSTemporaryDirectory() + "Photo.jpg" + + @Environment(\.presentationMode) var presentationMode + + var body: some View { + let utilityFileSystem = NCUtilityFileSystem() + + NavigationView { + ZStack(alignment: .top) { + List { + Section(footer: Text(NSLocalizedString("_modify_image_desc_", comment: ""))) { + ScrollView(.horizontal) { + LazyHGrid(rows: gridItems, alignment: .center, spacing: 10) { + ForEach(0.. - @@ -151,7 +150,7 @@ - + @@ -161,7 +160,7 @@ - + @@ -171,7 +170,7 @@ - + @@ -181,7 +180,7 @@ - + @@ -191,7 +190,7 @@ - + @@ -201,7 +200,7 @@ - + @@ -211,17 +210,7 @@ - - - - - - - - - - - + @@ -231,7 +220,7 @@ - + diff --git a/iOSClient/Main/NCPickerViewController.swift b/iOSClient/Main/NCPickerViewController.swift index 17f24b72e5..30666c3c3e 100644 --- a/iOSClient/Main/NCPickerViewController.swift +++ b/iOSClient/Main/NCPickerViewController.swift @@ -26,6 +26,7 @@ import TLPhotoPicker import MobileCoreServices import Photos import NextcloudKit +import SwiftUI // MARK: - Photo Picker @@ -46,9 +47,10 @@ class NCPhotosPickerViewController: NSObject { self.openPhotosPickerViewController { assets in if !assets.isEmpty { let serverUrl = mainTabBarController.currentServerUrl() - let vc = NCHostingUploadAssetsView().makeShipDetailsUI(assets: assets, serverUrl: serverUrl, userBaseUrl: self.appDelegate) + let view = NCUploadAssetsView(model: NCUploadAssetsModel(assets: assets, serverUrl: serverUrl, userBaseUrl: self.appDelegate, controller: mainTabBarController)) + let controller = UIHostingController(rootView: view) DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) { - mainTabBarController.present(vc, animated: true, completion: nil) + mainTabBarController.present(controller, animated: true, completion: nil) } } } diff --git a/iOSClient/Settings/CCManageAccount.h b/iOSClient/More/CCManageAccount.h similarity index 100% rename from iOSClient/Settings/CCManageAccount.h rename to iOSClient/More/CCManageAccount.h diff --git a/iOSClient/Settings/CCManageAccount.m b/iOSClient/More/CCManageAccount.m similarity index 100% rename from iOSClient/Settings/CCManageAccount.m rename to iOSClient/More/CCManageAccount.m diff --git a/iOSClient/More/NCMore.swift b/iOSClient/More/NCMore.swift index f65e6d8f06..bf2c179f57 100644 --- a/iOSClient/More/NCMore.swift +++ b/iOSClient/More/NCMore.swift @@ -193,7 +193,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { item = NKExternalSite() item.name = "_settings_" item.icon = "gear" - item.url = "segueSettings" + item.url = "openSettings" settingsMenu.append(item) if !quotaMenu.isEmpty { @@ -415,7 +415,6 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { tapImageLogoManageAccount() return } - // Action if item.url.contains("segue") && !item.url.contains("//") { self.navigationController?.performSegue(withIdentifier: item.url, sender: self) @@ -455,6 +454,10 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { let assistant = NCAssistant().environmentObject(NCAssistantTask()) let hostingController = UIHostingController(rootView: assistant) present(hostingController, animated: true, completion: nil) + } else if item.url == "openSettings" { + let settingsView = NCSettingsView(model: NCSettingsModel(controller: tabBarController as? NCMainTabBarController)) + let settingsController = UIHostingController(rootView: settingsView) + navigationController?.pushViewController(settingsController, animated: true) } else { applicationHandle.didSelectItem(item, viewController: self) } diff --git a/iOSClient/Scan document/NCUploadScanDocument.swift b/iOSClient/Scan document/NCUploadScanDocument.swift index b392f6e303..f29e60e5f3 100644 --- a/iOSClient/Scan document/NCUploadScanDocument.swift +++ b/iOSClient/Scan document/NCUploadScanDocument.swift @@ -491,7 +491,7 @@ struct UploadScanDocumentView: View { } HUDView(showHUD: $uploadScanDocument.showHUD, textLabel: NSLocalizedString("_wait_", comment: ""), image: "doc.badge.arrow.up") .offset(y: uploadScanDocument.showHUD ? 5 : -200) - .animation(.easeOut, value: UUID()) + .animation(.easeOut, value: uploadScanDocument.showHUD) } } .background(Color(UIColor.systemGroupedBackground)) diff --git a/iOSClient/SceneDelegate.swift b/iOSClient/SceneDelegate.swift index 3c54cc63da..913333da76 100644 --- a/iOSClient/SceneDelegate.swift +++ b/iOSClient/SceneDelegate.swift @@ -421,6 +421,12 @@ class SceneManager { return (scene as? UIWindowScene)?.keyWindow } + func getWindow(controller: NCMainTabBarController?) -> UIWindow? { + guard let controller, + let scene = sceneMainTabBarController[controller] else { return nil } + return getWindow(scene: scene) + } + func getSceneIdentifier() -> [String] { var results: [String] = [] for mainTabBarController in sceneMainTabBarController.keys { diff --git a/iOSClient/Settings/Acknowledgements.h b/iOSClient/Settings/Acknowledgements.h deleted file mode 100644 index 29be1b5a48..0000000000 --- a/iOSClient/Settings/Acknowledgements.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// Acknowledgements.h -// Nextcloud -// -// Created by Marino Faggiana on 14/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 - -@interface Acknowledgements : UIViewController - -@property (nonatomic, weak) IBOutlet UITextView *txtTermini; - -@end diff --git a/iOSClient/Settings/Acknowledgements.m b/iOSClient/Settings/Acknowledgements.m deleted file mode 100644 index a808f36de4..0000000000 --- a/iOSClient/Settings/Acknowledgements.m +++ /dev/null @@ -1,61 +0,0 @@ -// -// Acknowledgements.m -// Nextcloud -// -// Created by Marino Faggiana on 14/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 "Acknowledgements.h" -#import "NCBridgeSwift.h" - -@implementation Acknowledgements - -// MARK: - View Life Cycle - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - NSURL *rtfPath = [[NSBundle mainBundle] URLForResource:@"Acknowledgements" withExtension:@"rtf"]; - - NSAttributedString *attributedStringWithRtf = [[NSAttributedString alloc] initWithURL:rtfPath options:@{NSDocumentTypeDocumentAttribute:NSRTFTextDocumentType} documentAttributes:nil error:nil]; - self.txtTermini.attributedText = attributedStringWithRtf; - - self.navigationController.navigationBar.backgroundColor = [UIColor whiteColor]; - self.view.backgroundColor = [UIColor whiteColor]; - self.title = NSLocalizedString(@"_acknowledgements_", nil); - self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(cancelPressed)]; - self.txtTermini.hidden = true; -} - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - - [self.txtTermini setContentOffset:CGPointZero animated:NO]; - self.txtTermini.hidden = false; -} - -- (void)cancelPressed -{ - [self dismissViewControllerAnimated:true completion:nil]; -} - -@end - diff --git a/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesModel.swift b/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesModel.swift new file mode 100644 index 0000000000..8e74707374 --- /dev/null +++ b/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesModel.swift @@ -0,0 +1,86 @@ +// +// NCCapabilitiesModel.swift +// Nextcloud +// +// Created by Marino Faggiana on 02/06/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// + +import Foundation + +class NCCapabilitiesModel: ObservableObject, ViewOnAppearHandling { + struct Capability: Identifiable, Hashable { + let id = UUID() + let text: String + let image: UIImage + let resize: Bool + let available: Bool + } + @Published var capabililies: [Capability] = [] + @Published var homeServer = "" + let utilityFileSystem = NCUtilityFileSystem() + let utility = NCUtility() + + init() { + onViewAppear() + } + + /// Triggered when the view appears. + func onViewAppear() { + guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return } + var textEditor = false + var onlyofficeEditors = false + + capabililies.removeAll() + + var image = utility.loadImage(named: "person.fill.badge.plus") + capabililies.append(Capability(text: "File sharing", image: image, resize: false, available: NCGlobal.shared.capabilityFileSharingApiEnabled)) + + image = utility.loadImage(named: "network") + capabililies.append(Capability(text: "External site", image: image, resize: false, available: NCGlobal.shared.capabilityExternalSites)) + + image = utility.loadImage(named: "lock") + capabililies.append(Capability(text: "End-to-End Encryption", image: image, resize: false, available: NCGlobal.shared.capabilityE2EEEnabled)) + + image = utility.loadImage(named: "bolt") + capabililies.append(Capability(text: "Activity", image: image, resize: false, available: !NCGlobal.shared.capabilityActivity.isEmpty)) + + image = utility.loadImage(named: "bell") + capabililies.append(Capability(text: "Notification", image: image, resize: false, available: !NCGlobal.shared.capabilityNotification.isEmpty)) + + image = utility.loadImage(named: "trash") + capabililies.append(Capability(text: "Deleted files", image: image, resize: false, available: NCGlobal.shared.capabilityFilesUndelete)) + + if let editors = NCManageDatabase.shared.getDirectEditingEditors(account: activeAccount.account) { + for editor in editors { + if editor.editor == NCGlobal.shared.editorText { + textEditor = true + } else if editor.editor == NCGlobal.shared.editorOnlyoffice { + onlyofficeEditors = true + } + } + } + + capabililies.append(Capability(text: "Text", image: utility.loadImage(named: "doc.text"), resize: false, available: textEditor)) + + capabililies.append(Capability(text: "ONLYOFFICE", image: utility.loadImage(named: "onlyoffice"), resize: true, available: onlyofficeEditors)) + + capabililies.append(Capability(text: "Collabora", image: utility.loadImage(named: "collabora"), resize: true, available: NCGlobal.shared.capabilityRichDocumentsEnabled)) + + capabililies.append(Capability(text: "User Status", image: utility.loadImage(named: "moon"), resize: false, available: NCGlobal.shared.capabilityUserStatusEnabled)) + + capabililies.append(Capability(text: "Comments", image: utility.loadImage(named: "ellipsis.bubble"), resize: false, available: NCGlobal.shared.capabilityFilesComments)) + + capabililies.append(Capability(text: "Lock file", image: utility.loadImage(named: "lock"), resize: false, available: !NCGlobal.shared.capabilityFilesLockVersion.isEmpty)) + + capabililies.append(Capability(text: "Group folders", image: utility.loadImage(named: "person.2"), resize: false, available: NCGlobal.shared.capabilityGroupfoldersEnabled)) + + if NCBrandOptions.shared.brand != "Nextcloud" { + capabililies.append(Capability(text: "Security Guard Diagnostics", image: utility.loadImage(named: "shield"), resize: false, available: NCGlobal.shared.capabilitySecurityGuardDiagnostics)) + } + + capabililies.append(Capability(text: "Assistant", image: utility.loadImage(named: "sparkles"), resize: false, available: NCGlobal.shared.capabilityAssistantEnabled)) + + homeServer = utilityFileSystem.getHomeServer(urlBase: activeAccount.urlBase, userId: activeAccount.userId) + "/" + } +} diff --git a/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesView.swift b/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesView.swift new file mode 100644 index 0000000000..700137be48 --- /dev/null +++ b/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesView.swift @@ -0,0 +1,95 @@ +// +// NCCapabilitiesView.swift +// Nextcloud +// +// Created by Marino Faggiana on 19/05/23. +// Copyright © 2023 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 + +struct NCCapabilitiesView: View { + @ObservedObject var model: NCCapabilitiesModel + + var body: some View { + VStack { + List { + Section { + ForEach(model.capabililies, id: \.id) { capability in + HStack { + CapabilityName(text: Binding.constant(capability.text), image: Image(uiImage: capability.image), resize: capability.resize) + CapabilityStatus(available: capability.available) + } + } + } + Section { + CapabilityName(text: $model.homeServer, image: Image(uiImage: NCUtility().loadImage(named: "house")), resize: false) + } + } + } + .navigationBarTitle(NSLocalizedString("_capabilities_", comment: "")) + .frame(maxWidth: .infinity, alignment: .top) + .defaultViewModifier(model) + } + + struct CapabilityName: View { + @Binding var text: String + @State var image: Image + @State var resize: Bool + + var body: some View { + Label { + Text(text) + .font(.system(size: 15)) + } icon: { + if resize { + image + .renderingMode(.template) + .resizable() + .scaledToFill() + .frame(width: 23.0, height: 23.0) + .foregroundColor(.primary) + } else { + image + .renderingMode(.template) + .foregroundColor(.primary) + } + } + .frame(maxWidth: .infinity, alignment: .leading) + } + } + + struct CapabilityStatus: View { + @State var available: Bool + + var body: some View { + if available { + Image(systemName: "checkmark.circle.fill") + .foregroundColor(.green) + } else { + Image(systemName: "multiply.circle.fill") + .foregroundColor(Color(NCBrandColor.shared.textColor2)) + } + } + } +} + +#Preview { + return NCCapabilitiesView(model: NCCapabilitiesModel()) +} diff --git a/iOSClient/Settings/Advanced/NCSettingsAdvancedModel.swift b/iOSClient/Settings/Advanced/NCSettingsAdvancedModel.swift new file mode 100644 index 0000000000..6665545dbb --- /dev/null +++ b/iOSClient/Settings/Advanced/NCSettingsAdvancedModel.swift @@ -0,0 +1,259 @@ +// +// NCSettingsAdvancedViewModel.swift +// Nextcloud +// +// Created by Aditya Tyagi on 08/03/24. +// Created by Marino Faggiana on 30/05/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Aditya Tyagi +// +// 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 +import NextcloudKit +import Combine +import SwiftUI + +class NCSettingsAdvancedModel: ObservableObject, ViewOnAppearHandling { + /// AppDelegate + let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + /// Keychain access + var keychain = NCKeychain() + /// State variable for indicating whether hidden files are shown. + @Published var showHiddenFiles: Bool = false + /// State variable for indicating the most compatible format. + @Published var mostCompatible: Bool = false + /// State variable for enabling live photo uploads. + @Published var livePhoto: Bool = false + /// State variable for indicating whether to remove photos from the camera roll after upload. + @Published var removeFromCameraRoll: Bool = false + /// State variable for app integration. + @Published var appIntegration: Bool = false + /// State variable for enabling the crash reporter. + @Published var crashReporter: Bool = false + /// State variable for indicating whether the log file has been cleared. + @Published var logFileCleared: Bool = false + // Properties for log level and cache deletion + /// State variable for storing the selected log level. + @Published var selectedLogLevel: LogLevel = .standard + /// State variable for storing the selected cache deletion interval. + @Published var selectedInterval: CacheDeletionInterval = .never + /// State variable for storing the footer title, usually used for cache deletion. + @Published var footerTitle: String = "" + /// Root View Controller + @Published var controller: NCMainTabBarController? + + /// Initializes the view model with default values. + init(controller: NCMainTabBarController?) { + self.controller = controller + onViewAppear() + } + + /// Triggered when the view appears. + func onViewAppear() { + showHiddenFiles = keychain.showHiddenFiles + mostCompatible = keychain.formatCompatibility + livePhoto = keychain.livePhoto + removeFromCameraRoll = keychain.removePhotoCameraRoll + appIntegration = keychain.disableFilesApp + crashReporter = keychain.disableCrashservice + selectedLogLevel = LogLevel(rawValue: keychain.logLevel) ?? .standard + selectedInterval = CacheDeletionInterval(rawValue: keychain.cleanUpDay) ?? .never + DispatchQueue.global().async { + self.calculateSize() + } + } + + // MARK: - All functions + + /// Updates the value of `showHiddenFiles` in the keychain. + func updateShowHiddenFiles() { + keychain.showHiddenFiles = showHiddenFiles + } + + /// Updates the value of `mostCompatible` in the keychain. + func updateMostCompatible() { + keychain.formatCompatibility = mostCompatible + } + + /// Updates the value of `livePhoto` in the keychain. + func updateLivePhoto() { + keychain.livePhoto = livePhoto + } + + /// Updates the value of `removeFromCameraRoll` in the keychain. + func updateRemoveFromCameraRoll() { + keychain.removePhotoCameraRoll = removeFromCameraRoll + } + + /// Updates the value of `appIntegration` in the keychain. + func updateAppIntegration() { + keychain.disableFilesApp = appIntegration + } + + /// Updates the value of `crashReporter` in the keychain. + func updateCrashReporter() { + keychain.disableCrashservice = crashReporter + } + + /// Updates the value of `selectedLogLevel` in the keychain and sets it for NextcloudKit. + func updateSelectedLogLevel() { + keychain.logLevel = selectedLogLevel.rawValue + NextcloudKit.shared.nkCommonInstance.levelLog = selectedLogLevel.rawValue + } + + /// Updates the value of `selectedInterval` in the keychain. + func updateSelectedInterval() { + keychain.cleanUpDay = selectedInterval.rawValue + } + + /// Clears cache associated with the specified account. + func clearCache() { + NCActivityIndicator.shared.startActivity(style: .large, blurEffect: true) + // Cancel all networking tasks + NCNetworking.shared.cancelAllTask() + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + URLCache.shared.memoryCapacity = 0 + URLCache.shared.diskCapacity = 0 + + NCManageDatabase.shared.clearDatabase(account: self.appDelegate.account, removeAccount: false) + + let ufs = NCUtilityFileSystem() + ufs.removeGroupDirectoryProviderStorage() + ufs.removeGroupLibraryDirectory() + ufs.removeDocumentsDirectory() + ufs.removeTemporaryDirectory() + ufs.createDirectoryStandard() + + NCAutoUpload.shared.alignPhotoLibrary(viewController: self.controller) + NCImageCache.shared.createMediaCache(account: self.appDelegate.account, withCacheSize: true) + + NCActivityIndicator.shared.stop() + self.calculateSize() + } + } + + /// Asynchronously calculates the size of cache directory and updates the footer title. + func calculateSize() { + let ufs = NCUtilityFileSystem() + let directory = ufs.directoryProviderStorage + let totalSize = ufs.getDirectorySize(directory: directory) + DispatchQueue.main.async { + self.footerTitle = "\(NSLocalizedString("_clear_cache_footer_", comment: "")). (\(NSLocalizedString("_used_space_", comment: "")) \(ufs.transformedSize(totalSize)))" + } + } + + /// Removes all accounts & exits the Nextcloud application if specified. + /// + /// - Parameter + /// exit: Boolean indicating whether to reset the application. + func resetNextCloud(exit: Bool) { + if exit { + self.appDelegate.resetApplication() + } else { } + } + + /// Exits the Nextcloud application if specified. + /// + /// - Parameter + /// exit: Boolean indicating whether to exit the application. + func exitNextCloud(ext: Bool) { + if ext { + exit(0) + } else { } + } + + /// Presents the log file viewer. + func viewLogFile() { + // Instantiate NCViewerQuickLook with the log file URL, editing disabled, and no metadata + let viewerQuickLook = NCViewerQuickLook(with: NSURL(fileURLWithPath: NextcloudKit.shared.nkCommonInstance.filenamePathLog) as URL, isEditingEnabled: false, metadata: nil) + // Present the NCViewerQuickLook view controller + controller?.present(viewerQuickLook, animated: true, completion: nil) + } + + /// Clears the log file. + func clearLogFile() { + // Clear the log file using NextcloudKit + NextcloudKit.shared.nkCommonInstance.clearFileLog() + // Fetch the log level from the keychain + let logLevel = keychain.logLevel + // Check if the app is running in a simulator or TestFlight environment + let isSimulatorOrTestFlight = NCUtility().isSimulatorOrTestFlight() + // Get the app's version and copyright information + let versionNextcloudiOS = String(format: NCBrandOptions.shared.textCopyrightNextcloudiOS, NCUtility().getVersionApp(withBuild: true)) + // Construct the log message + let logMessage = "[INFO] Clear log with level \(logLevel) \(versionNextcloudiOS)" + (isSimulatorOrTestFlight ? " (Simulator / TestFlight)" : "") + // Write the log entry about the log clearance + NextcloudKit.shared.nkCommonInstance.writeLog(logMessage) + // Set the alert state to show that log file has been cleared + self.logFileCleared = true + } +} + +/// An enum that represents the level of the log +enum LogLevel: Int, CaseIterable, Identifiable, Equatable { + /// Represents that logging is disabled + case disabled = 0 + /// Represents standard logging level + case standard = 1 + /// Represents maximum logging level + case maximum = 2 + var id: Int { self.rawValue } +} + +extension LogLevel { + var displayText: String { + switch self { + case .disabled: + return NSLocalizedString("_disabled_", comment: "") + case .standard: + return NSLocalizedString("_standard_", comment: "") + case .maximum: + return NSLocalizedString("_maximum_", comment: "") + } + } +} + +/// An enum that represents the intervals for cache deletion +enum CacheDeletionInterval: Int, CaseIterable, Identifiable { + case never = 0 + case oneYear = 365 + case sixMonths = 180 + case threeMonths = 90 + case oneMonth = 30 + case oneWeek = 7 + var id: Int { self.rawValue } +} + +extension CacheDeletionInterval { + var displayText: String { + switch self { + case .never: + return NSLocalizedString("_never_", comment: "") + case .oneYear: + return NSLocalizedString("_1_year_", comment: "") + case .sixMonths: + return NSLocalizedString("_6_months_", comment: "") + case .threeMonths: + return NSLocalizedString("_3_months_", comment: "") + case .oneMonth: + return NSLocalizedString("_1_month_", comment: "") + case .oneWeek: + return NSLocalizedString("_1_week_", comment: "") + } + } +} diff --git a/iOSClient/Settings/Advanced/NCSettingsAdvancedView.swift b/iOSClient/Settings/Advanced/NCSettingsAdvancedView.swift new file mode 100644 index 0000000000..f30f2417a9 --- /dev/null +++ b/iOSClient/Settings/Advanced/NCSettingsAdvancedView.swift @@ -0,0 +1,276 @@ +// +// NCSettingsAdvancedView.swift +// Nextcloud +// +// Created by Aditya Tyagi on 08/03/24. +// Created by Marino Faggiana on 30/05/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Aditya Tyagi +// +// 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 + +struct NCSettingsAdvancedView: View { + @ObservedObject var model: NCSettingsAdvancedModel + /// State variable for indicating whether the exit alert is shown. + @State var showExitAlert: Bool = false + /// State variable for indicating whether the cache alert is shown. + @State var showCacheAlert: Bool = false + /// State variable for indicating whether to disable crash reporter. + @State var showCrashReporter: Bool = false + + var body: some View { + Form { + /// Show Hidden Files + Section(content: { + Toggle(NSLocalizedString("_show_hidden_files_", comment: ""), isOn: $model.showHiddenFiles) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.showHiddenFiles) { _ in + model.updateShowHiddenFiles() + } + .font(.system(size: 16)) + }, footer: { }) + /// Most Compatible & Enable Live Photo + Section(content: { + Toggle(NSLocalizedString("_format_compatibility_", comment: ""), isOn: $model.mostCompatible) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.mostCompatible) { _ in + model.updateMostCompatible() + } + .font(.system(size: 16)) + Toggle(NSLocalizedString("_upload_mov_livephoto_", comment: ""), isOn: $model.livePhoto) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.livePhoto) { _ in + model.updateLivePhoto() + } + .font(.system(size: 16)) + }, footer: { + ( + Text(NSLocalizedString("_format_compatibility_footer_", comment: "")) + + + Text(NSLocalizedString("_upload_mov_livephoto_footer_", comment: "")) + ).font(.system(size: 12)) + .multilineTextAlignment(.leading) + }) + /// Remove from Camera Roll + Section(content: { + Toggle(NSLocalizedString("_remove_photo_CameraRoll_", comment: ""), isOn: $model.removeFromCameraRoll) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.removeFromCameraRoll) { _ in + model.updateRemoveFromCameraRoll() + } + .font(.system(size: 16)) + }, footer: { + Text(NSLocalizedString("_remove_photo_CameraRoll_desc_", comment: "")) + .font(.system(size: 12)) + .multilineTextAlignment(.leading) + }) + /// Section : Files App + if !NCBrandOptions.shared.disable_openin_file { + Section(content: { + Toggle(NSLocalizedString("_disable_files_app_", comment: ""), isOn: $model.appIntegration) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.appIntegration) { _ in + model.updateAppIntegration() + } + .font(.system(size: 16)) + }, footer: { + Text(NSLocalizedString("_disable_files_app_footer_", comment: "")) + .font(.system(size: 12)) + .multilineTextAlignment(.leading) + }) + } + /// Section: Privacy + if !NCBrandOptions.shared.disable_crash_service { + Section(content: { + Toggle(NSLocalizedString("_crashservice_title_", comment: ""), isOn: $model.crashReporter) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.crashReporter) { _ in + model.updateCrashReporter() + showCrashReporter.toggle() + } + .font(.system(size: 16)) + .alert(NSLocalizedString("_crashservice_title_", comment: ""), isPresented: $showCrashReporter, actions: { + Button(NSLocalizedString("OK", comment: ""), role: .cancel) { + model.exitNextCloud(ext: showCrashReporter) + } + }, message: { + Text(NSLocalizedString("_crashservice_alert_", comment: "")) + }) + }, header: { + Text(NSLocalizedString("_privacy_", comment: "")) + }, footer: { + Text(NSLocalizedString("_privacy_footer_", comment: "")) + .font(.system(size: 12)) + .multilineTextAlignment(.leading) + }) + } + /// Section: Diagnostic LOG + if !NCBrandOptions.shared.disable_log { + Section(content: { + /// View Log File + Button(action: { + model.viewLogFile() + }, label: { + HStack { + Image(systemName: "doc.badge.gearshape") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_view_log_", comment: "")) + } + .font(.system(size: 16)) + }) + .tint(Color(UIColor.label)) + /// Clear Log File + Button(action: { + model.clearLogFile() + }, label: { + HStack { + Image(systemName: "xmark") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 15) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_clear_log_", comment: "")) + } + .font(.system(size: 16)) + }) + .tint(Color(UIColor.label)) + .alert(NSLocalizedString("_log_file_clear_alert_", comment: ""), isPresented: $model.logFileCleared) { + Button(NSLocalizedString("OK", comment: ""), role: .cancel) { } + } + /// Set Log Level() + Picker(NSLocalizedString("_set_log_level_", comment: ""), selection: $model.selectedLogLevel) { + ForEach(LogLevel.allCases) { level in + Text(level.displayText).tag(level) + } + } + .font(.system(size: 16)) + .onChange(of: model.selectedLogLevel) { _ in + model.updateSelectedLogLevel() + } + }, header: { + Text(NSLocalizedString("_diagnostics_", comment: "")) + }, footer: { }) + /// Set Log Level() & Capabilities + Section(content: { + NavigationLink(destination: LazyView { + NCCapabilitiesView(model: NCCapabilitiesModel()) + }) { + HStack { + Image(systemName: "list.bullet") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_capabilities_", comment: "")) + } + .font(.system(size: 16)) + } + }, header: { + Text(NSLocalizedString("_capabilities_", comment: "")) + }, footer: { + Text(NSLocalizedString("_capabilities_footer_", comment: "")) + }) + } + /// Delete in Cache & Clear Cache + Section(content: { + Picker(NSLocalizedString("_auto_delete_cache_files_", comment: ""), selection: $model.selectedInterval) { + ForEach(CacheDeletionInterval.allCases) { interval in + Text(interval.displayText).tag(interval) + } + } + .font(.system(size: 16)) + .pickerStyle(.automatic) + .onChange(of: model.selectedInterval) { _ in + model.updateSelectedInterval() + } + Button(action: { + showCacheAlert.toggle() + }, label: { + HStack { + Image(systemName: "xmark") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 15, height: 15) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_clear_cache_", comment: "")) + } + .font(.system(size: 16)) + }) + .tint(Color(UIColor.label)) + .alert(NSLocalizedString("_want_delete_cache_", comment: ""), isPresented: $showCacheAlert) { + Button(NSLocalizedString("_yes_", comment: ""), role: .destructive) { + model.clearCache() + } + Button(NSLocalizedString("_cancel_", comment: ""), role: .cancel) { } + } + }, header: { + Text(NSLocalizedString("_delete_files_desc_", comment: "")) + }, footer: { + Text(model.footerTitle) + .font(.system(size: 12)) + .multilineTextAlignment(.leading) + }) + /// Reset Application + Section(content: { + Button(action: { + showExitAlert.toggle() + }, label: { + HStack { + Image(systemName: "xmark") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 15, height: 15) + .foregroundColor(Color(UIColor.systemRed)) + Text(NSLocalizedString("_exit_", comment: "")) + .foregroundColor(Color(UIColor.systemRed)) + } + .font(.system(size: 16)) + }) + .tint(Color(UIColor.label)) + .alert(NSLocalizedString("_want_exit_", comment: ""), isPresented: $showExitAlert) { + Button(NSLocalizedString("_ok_", comment: ""), role: .destructive) { + model.resetNextCloud(exit: showExitAlert) + } + Button(NSLocalizedString("_cancel_", comment: ""), role: .cancel) { } + } + }, footer: { + ( + Text(NSLocalizedString("_exit_footer_", comment: "")) + + + Text("\n\n") + ) + .font(.system(size: 12)) + .multilineTextAlignment(.leading) + }) + } + .navigationBarTitle(NSLocalizedString("_advanced_", comment: "")) + .defaultViewModifier(model) + } +} + +#Preview { + NCSettingsAdvancedView(model: NCSettingsAdvancedModel(controller: nil), showExitAlert: false, showCacheAlert: false) +} diff --git a/iOSClient/Settings/AutoUpload/AutoUploadFileNames/NCAutoUploadFileNamesModel.swift b/iOSClient/Settings/AutoUpload/AutoUploadFileNames/NCAutoUploadFileNamesModel.swift new file mode 100644 index 0000000000..3bb8e4d9cf --- /dev/null +++ b/iOSClient/Settings/AutoUpload/AutoUploadFileNames/NCAutoUploadFileNamesModel.swift @@ -0,0 +1,122 @@ +// +// NCAutoUploadFileNamesModel.swift +// Nextcloud +// +// Created by Aditya Tyagi on 12/03/24. +// Created by Marino Faggiana on 30/05/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Aditya Tyagi +// +// 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 NextcloudKit +import SwiftUI +import Combine + +/// A view model responsible for managing auto-upload file names. +class NCAutoUploadFileNamesModel: ObservableObject, ViewOnAppearHandling { + /// A keychain instance for handling authentication. + private var keychain = NCKeychain() + /// A shared global instance for managing application-wide settings. + private let globalKey = NCGlobal.shared + /// A boolean indicating whether to maintain the original file name. + @Published var maintainFilename: Bool = false + /// A boolean indicating whether to specify a custom file name. + @Published var specifyFilename: Bool = false + /// The changed file name. + @Published var changedName: String = "" + /// The original file name. + @Published var oldName: String = "" + /// The complete new file name. + @Published var fileName: String = "" + let dateExample = Date() + + /// Initializes the view model with default values. + init() { + onViewAppear() + } + + /// Triggered when the view appears. + func onViewAppear() { + maintainFilename = keychain.getOriginalFileName(key: globalKey.keyFileNameOriginalAutoUpload) + specifyFilename = keychain.getOriginalFileName(key: globalKey.keyFileNameAutoUploadType) + changedName = keychain.getFileNameMask(key: globalKey.keyFileNameAutoUploadMask) + oldName = keychain.getFileNameMask(key: globalKey.keyFileNameAutoUploadMask) + getFileName() + } + + // MARK: - All functions + + func getFileName() { + fileName = previewFileName() + } + + /// Toggles maintaining the original filename. + func toggleMaintainOriginalFilename(newValue: Bool) { + keychain.setOriginalFileName(key: NCGlobal.shared.keyFileNameOriginalAutoUpload, value: newValue) + } + + /// Toggles adding filename type. + func toggleAddFilenameType(newValue: Bool) { + keychain.setFileNameType(key: NCGlobal.shared.keyFileNameAutoUploadType, prefix: newValue) + } + + /// Submits the changed file name. + func submitChangedName() { + changedName = checkUploadFileName() + presentForbiddenCharError() + oldName = changedName + } + + /// Presents an error message if the changed file name contains forbidden characters. + func presentForbiddenCharError() { + if changedName != oldName { + 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) + } + } + + /// Checks and removes forbidden characters from the changed file name. + /// - Returns: The sanitized file name. + func checkUploadFileName() -> String { + return NCUtility().removeForbiddenCharacters(changedName) + } + + /// Generates a preview file name based on current settings and file name mask. + /// - Returns: The preview file name. + func previewFileName() -> String { + var returnString: String = "" + // Check if maintaining original file name is enabled + if keychain.getOriginalFileName(key: NCGlobal.shared.keyFileNameOriginalAutoUpload) { + // If maintaining original file name, return a default filename + return (NSLocalizedString("_filename_", comment: "") + ": IMG_0001.JPG") + } else { + let valueRenameTrimming = changedName.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + // If the changed name is empty, set the filename mask to empty and generate a new filename + if valueRenameTrimming.isEmpty { + keychain.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 { + // If there is a changed name, set the filename mask and generate a new filename + keychain.setFileNameMask(key: NCGlobal.shared.keyFileNameAutoUploadMask, mask: changedName) + 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) + } + } + return returnString + } +} diff --git a/iOSClient/Settings/AutoUpload/AutoUploadFileNames/NCAutoUploadFileNamesView.swift b/iOSClient/Settings/AutoUpload/AutoUploadFileNames/NCAutoUploadFileNamesView.swift new file mode 100644 index 0000000000..7c88bfe71b --- /dev/null +++ b/iOSClient/Settings/AutoUpload/AutoUploadFileNames/NCAutoUploadFileNamesView.swift @@ -0,0 +1,112 @@ +// +// NCAutoUploadFileNamesView.swift +// Nextcloud +// +// Created by Aditya Tyagi on 10/03/24. +// Created by Marino Faggiana on 30/05/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Aditya Tyagi +// +// 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 + +struct NCAutoUploadFileNamesView: View { + @ObservedObject var model = NCAutoUploadFileNamesModel() + + var body: some View { + Form { + /// Specify Filename + Section(header: Text(NSLocalizedString("_mode_filename_", comment: ""))) { + Toggle(NSLocalizedString("_maintain_original_filename_", comment: ""), isOn: $model.maintainFilename) + .font(.system(size: 16)) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.maintainFilename, perform: { newValue in + model.toggleMaintainOriginalFilename(newValue: newValue) + model.getFileName() + }) + /// Filename + if !model.maintainFilename { + Toggle(NSLocalizedString("_add_filenametype_", comment: ""), isOn: $model.specifyFilename) + .font(.system(size: 16)) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.specifyFilename, perform: { newValue in + model.toggleAddFilenameType(newValue: newValue) + model.getFileName() + }) + } + } + .transition(.slide) + .animation(.easeInOut, value: model.maintainFilename) + + /// Filename Preview + fileNamePreview + .animation(.easeInOut, value: model.specifyFilename) + } + .navigationBarTitle(NSLocalizedString("_mode_filename_", comment: "")) + .defaultViewModifier(model) + .padding(.top, 0) + .transition(.slide) + } + + @ViewBuilder + var fileNamePreview: some View { + if !model.maintainFilename { + Section(content: { + HStack { + Text(NSLocalizedString("_filename_", comment: "")) + .font(.system(size: 17)) + .foregroundColor(Color(UIColor.label)) + .fontWeight(.medium) + .background(Color(UIColor.secondarySystemGroupedBackground)) + Spacer() + TextField(NSLocalizedString("_filename_header_", comment: ""), text: $model.changedName) + .onSubmit { + model.submitChangedName() + } + .onChange(of: model.changedName, perform: { _ in + model.getFileName() + }) + + .font(.system(size: 15)) + .foregroundColor(Color(UIColor.label)) + .background(Color(UIColor.secondarySystemGroupedBackground)) + .multilineTextAlignment(.trailing) + } + .font(.system(size: 16)) + Text("\(model.fileName)") + .font(.system(size: 16)) + }, header: { + Text(NSLocalizedString("_filename_", comment: "")) + }, footer: { + Text(NSLocalizedString("_preview_filename_footer_", comment: "")) + }) + } else { + Section(content: { + Text(NSLocalizedString("_default_filename_image_", comment: "")) + }, header: { + Text(NSLocalizedString("_filename_", comment: "")) + }, footer: { + Text(NSLocalizedString("_default_preview_filename_footer_", comment: "")) + }) + } + + } +} + +#Preview { + NCAutoUploadFileNamesView(model: NCAutoUploadFileNamesModel()) +} diff --git a/iOSClient/Settings/AutoUpload/NCAutoUploadModel.swift b/iOSClient/Settings/AutoUpload/NCAutoUploadModel.swift new file mode 100644 index 0000000000..172e2ef272 --- /dev/null +++ b/iOSClient/Settings/AutoUpload/NCAutoUploadModel.swift @@ -0,0 +1,201 @@ +// +// NCAutoUploadModel.swift +// Nextcloud +// +// Created by Aditya Tyagi on 08/03/24. +// Created by Marino Faggiana on 30/05/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Aditya Tyagi +// +// 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 NextcloudKit + +/// A model that allows the user to configure the `auto upload settings for Nextcloud` +class NCAutoUploadModel: ObservableObject, ViewOnAppearHandling { + /// AppDelegate + let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + /// A state variable that indicates whether auto upload is enabled or not + @Published var autoUpload: Bool = false + /// A state variable that indicates whether to open NCSelect View or not + @Published var autoUploadFolder: Bool = false + /// A state variable that indicates whether auto upload for photos is enabled or not + @Published var autoUploadImage: Bool = false + /// A state variable that indicates whether auto upload for photos is restricted to Wi-Fi only or not + @Published var autoUploadWWAnPhoto: Bool = false + /// A state variable that indicates whether auto upload for videos is enabled or not + @Published var autoUploadVideo: Bool = false + /// A state variable that indicates whether auto upload for videos is enabled or not + @Published var autoUploadWWAnVideo: Bool = false + /// A state variable that indicates whether auto upload for full resolution photos is enabled or not + @Published var autoUploadFull: Bool = false + /// A state variable that indicates whether auto upload creates subfolders based on date or not + @Published var autoUploadCreateSubfolder: Bool = false + /// A state variable that indicates the granularity of the subfolders, either daily, monthly, or yearly + @Published var autoUploadSubfolderGranularity: Granularity = .monthly + /// A state variable that shows error in view in case of an error + @Published var showErrorAlert: Bool = false + @Published var sectionName = "" + @Published var isAuthorized: Bool = false + /// A string variable that contains error text + @Published var error: String = "" + private let manageDatabase = NCManageDatabase.shared + @Published var autoUploadPath = "\(NCManageDatabase.shared.getAccountAutoUploadFileName())" + /// Root View Controller + var controller: NCMainTabBarController? + /// A variable user for change the auto upload directory + var serverUrl: String = "" + + /// Initialization code to set up the ViewModel with the active account + init(controller: NCMainTabBarController?) { + self.controller = controller + onViewAppear() + } + + /// Triggered when the view appears. + func onViewAppear() { + let activeAccount: tableAccount? = manageDatabase.getActiveAccount() + if let account = activeAccount { + autoUpload = account.autoUpload + autoUploadImage = account.autoUploadImage + autoUploadWWAnPhoto = account.autoUploadWWAnPhoto + autoUploadVideo = account.autoUploadVideo + autoUploadWWAnVideo = account.autoUploadWWAnVideo + autoUploadFull = account.autoUploadFull + autoUploadCreateSubfolder = account.autoUploadCreateSubfolder + autoUploadSubfolderGranularity = Granularity(rawValue: account.autoUploadSubfolderGranularity) ?? .monthly + serverUrl = NCUtilityFileSystem().getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) + } + if autoUpload { + requestAuthorization() + } + } + + // MARK: - All functions + + func requestAuthorization() { + PHPhotoLibrary.requestAuthorization { status in + DispatchQueue.main.async { + let value = (status == .authorized) + self.autoUpload = value + self.updateAccountProperty(\.autoUpload, value: value) + if !value { + let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_access_photo_not_enabled_msg_", comment: ""), responseData: nil) + NCContentPresenter().messageNotification("_error_", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .error) + } else if UIApplication.shared.backgroundRefreshStatus != .available { + let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: NSLocalizedString("_access_background_app_refresh_denied_", comment: ""), responseData: nil) + NCContentPresenter().messageNotification("_info_", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .info) + } + } + } + } + + /// Updates the auto-upload setting. + func handleAutoUploadChange(newValue: Bool) { + if newValue { + requestAuthorization() + } else { + updateAccountProperty(\.autoUpload, value: newValue) + } + } + + /// Updates the auto-upload image setting. + func handleAutoUploadImageChange(newValue: Bool) { + updateAccountProperty(\.autoUploadImage, value: newValue) + } + + /// Updates the auto-upload image over WWAN setting. + func handleAutoUploadWWAnPhotoChange(newValue: Bool) { + updateAccountProperty(\.autoUploadWWAnPhoto, value: newValue) + } + + /// Updates the auto-upload video setting. + func handleAutoUploadVideoChange(newValue: Bool) { + updateAccountProperty(\.autoUploadVideo, value: newValue) + } + + /// Updates the auto-upload video over WWAN setting. + func handleAutoUploadWWAnVideoChange(newValue: Bool) { + updateAccountProperty(\.autoUploadWWAnVideo, value: newValue) + } + + /// Updates the auto-upload full content setting. + func handleAutoUploadFullChange(newValue: Bool) { + updateAccountProperty(\.autoUploadFull, value: newValue) + if newValue { + NCAutoUpload.shared.autoUploadFullPhotos(viewController: self.controller, log: "Auto upload full") + NCManageDatabase.shared.setAccountAutoUploadProperty("autoUploadFull", state: true) + } else { + NCManageDatabase.shared.clearMetadatasUpload(account: appDelegate.account) + NCManageDatabase.shared.setAccountAutoUploadProperty("autoUploadFull", state: false) + } + } + + /// Updates the auto-upload create subfolder setting. + func handleAutoUploadCreateSubfolderChange(newValue: Bool) { + updateAccountProperty(\.autoUploadCreateSubfolder, value: newValue) + } + + /// Updates the auto-upload subfolder granularity setting. + func handleAutoUploadSubfolderGranularityChange(newValue: Granularity) { + updateAccountProperty(\.autoUploadSubfolderGranularity, value: newValue.rawValue) + } + + /// Updates a property of the active account in the database. + private func updateAccountProperty(_ keyPath: ReferenceWritableKeyPath, value: T) { + guard let activeAccount = manageDatabase.getActiveAccount() else { return } + activeAccount[keyPath: keyPath] = value + manageDatabase.updateAccount(activeAccount) + } + + /// Returns the path for auto-upload based on the active account's settings. + /// + /// - Returns: The path for auto-upload. + func returnPath() -> String { + let autoUploadPath = manageDatabase.getAccountAutoUploadDirectory(urlBase: appDelegate.urlBase, userId: appDelegate.userId, account: appDelegate.account) + "/" + manageDatabase.getAccountAutoUploadFileName() + let homeServer = NCUtilityFileSystem().getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) + let path = autoUploadPath.replacingOccurrences(of: homeServer, with: "") + return path + } + + /// Sets the auto-upload directory based on the provided server URL. + /// + /// - Parameter + /// serverUrl: The server URL to set as the auto-upload directory. + func setAutoUploadDirectory(serverUrl: String?) { + guard let serverUrl = serverUrl else { return } + let home = NCUtilityFileSystem().getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) + if home != serverUrl { + let fileName = (serverUrl as NSString).lastPathComponent + NCManageDatabase.shared.setAccountAutoUploadFileName(fileName) + if let path = NCUtilityFileSystem().deleteLastPath(serverUrlPath: serverUrl, home: home) { + NCManageDatabase.shared.setAccountAutoUploadDirectory(path, urlBase: appDelegate.urlBase, userId: appDelegate.userId, account: appDelegate.account) + } + } + onViewAppear() + } +} + +/// An enum that represents the granularity of the subfolders for auto upload +enum Granularity: Int { + /// Daily granularity, meaning the subfolders are named by day + case daily = 2 + /// Monthly granularity, meaning the subfolders are named by month + case monthly = 1 + /// Yearly granularity, meaning the subfolders are named by year + case yearly = 0 +} diff --git a/iOSClient/Settings/AutoUpload/NCAutoUploadView.swift b/iOSClient/Settings/AutoUpload/NCAutoUploadView.swift new file mode 100644 index 0000000000..c34b4a6eca --- /dev/null +++ b/iOSClient/Settings/AutoUpload/NCAutoUploadView.swift @@ -0,0 +1,167 @@ +// +// NCAutoUploadView.swift +// Nextcloud +// +// Created by Aditya Tyagi on 06/03/24. +// Created by Marino Faggiana on 30/05/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Aditya Tyagi +// +// 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 UIKit + +/// A view that allows the user to configure the `auto upload settings for Nextcloud` +struct NCAutoUploadView: View { + @ObservedObject var model: NCAutoUploadModel + + var body: some View { + Form { + /// Auto Upload + Section(content: { + Toggle(NSLocalizedString("_autoupload_", comment: ""), isOn: $model.autoUpload) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.autoUpload) { newValue in + model.handleAutoUploadChange(newValue: newValue) + } + .font(.system(size: 16)) + }, footer: { + Text(NSLocalizedString("_autoupload_notice_", comment: "")) + }) + /// If `autoUpload` state will be true, we will animate out the whole `autoUploadOnView` section + if model.autoUpload { + autoUploadOnView + .transition(.slide) + .animation(.easeInOut, value: model.autoUpload) + } + } + .navigationBarTitle(NSLocalizedString("_auto_upload_folder_", comment: "")) + .defaultViewModifier(model) + .alert(model.error, isPresented: $model.showErrorAlert) { + Button(NSLocalizedString("_ok_", comment: ""), role: .cancel) { } + } + } + + @ViewBuilder + var autoUploadOnView: some View { + Section(content: { + Button(action: { + model.autoUploadFolder.toggle() + }, label: { + HStack { + Image(systemName: "folder") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_autoupload_select_folder_", comment: "")) + } + .font(.system(size: 16)) + }) + .tint(Color(UIColor.label)) + }, footer: { + Text("\(NSLocalizedString("_autoupload_current_folder_", comment: "")): \(model.returnPath())") + }) + .sheet(isPresented: $model.autoUploadFolder) { + SelectView(serverUrl: $model.serverUrl) + .onDisappear { + model.setAutoUploadDirectory(serverUrl: model.serverUrl) + } + } + /// Auto Upload Photo + Section(content: { + Toggle(NSLocalizedString("_autoupload_photos_", comment: ""), isOn: $model.autoUploadImage) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.autoUploadImage) { newValue in + model.handleAutoUploadImageChange(newValue: newValue) + } + .font(.system(size: 16)) + Toggle(NSLocalizedString("_wifi_only_", comment: ""), isOn: $model.autoUploadWWAnPhoto) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.autoUploadWWAnPhoto) { newValue in + model.handleAutoUploadWWAnPhotoChange(newValue: newValue) + } + .font(.system(size: 16)) + }) + /// Auto Upload Video + Section(content: { + Toggle(NSLocalizedString("_autoupload_videos_", comment: ""), isOn: $model.autoUploadVideo) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.autoUploadVideo) { newValue in + model.handleAutoUploadVideoChange(newValue: newValue) + } + .font(.system(size: 16)) + Toggle(NSLocalizedString("_wifi_only_", comment: ""), isOn: $model.autoUploadWWAnVideo) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.autoUploadWWAnVideo) { newValue in + model.handleAutoUploadWWAnVideoChange(newValue: newValue) + } + .font(.system(size: 16)) + }) + /// Auto Upload Full + Section(content: { + Toggle(NSLocalizedString("_autoupload_fullphotos_", comment: ""), isOn: $model.autoUploadFull) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.autoUploadFull) { newValue in + model.handleAutoUploadFullChange(newValue: newValue) + } + .font(.system(size: 16)) + }, footer: { + Text(NSLocalizedString("_autoupload_fullphotos_footer_", comment: "")) + }) + /// Auto Upload create subfolder + Section(content: { + Toggle(NSLocalizedString("_autoupload_create_subfolder_", comment: ""), isOn: $model.autoUploadCreateSubfolder) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.autoUploadCreateSubfolder) { newValue in + model.handleAutoUploadCreateSubfolderChange(newValue: newValue) + } + .font(.system(size: 16)) + Picker(NSLocalizedString("_autoupload_subfolder_granularity_", comment: ""), selection: $model.autoUploadSubfolderGranularity) { + Text(NSLocalizedString("_daily_", comment: "")).tag(Granularity.daily) + Text(NSLocalizedString("_monthly_", comment: "")).tag(Granularity.monthly) + Text(NSLocalizedString("_yearly_", comment: "")).tag(Granularity.yearly) + } + .font(.system(size: 16)) + .onChange(of: model.autoUploadSubfolderGranularity) { newValue in + model.handleAutoUploadSubfolderGranularityChange(newValue: newValue) + } + }, footer: { + Text(NSLocalizedString("_autoupload_create_subfolder_footer_", comment: "")) + }) + /// Auto Upload file name + Section(content: { + NavigationLink(destination: LazyView { + NCAutoUploadFileNamesView(model: NCAutoUploadFileNamesModel()) + }) { + Text(NSLocalizedString("_autoupload_filenamemask_", comment: "")) + .font(.system(size: 16)) + } + }, footer: { + Text( + NSLocalizedString("_autoupload_filenamemask_footer_", comment: "") + + + "\n \n" + ) + }) + } +} + +#Preview { + NCAutoUploadView(model: NCAutoUploadModel(controller: nil)) +} diff --git a/iOSClient/Settings/CCAdvanced.m b/iOSClient/Settings/CCAdvanced.m deleted file mode 100755 index 49da3bef8a..0000000000 --- a/iOSClient/Settings/CCAdvanced.m +++ /dev/null @@ -1,450 +0,0 @@ -// -// 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" - -@interface CCAdvanced () -{ - AppDelegate *appDelegate; - XLFormSectionDescriptor *sectionSize; -} -@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"]; - [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"]; - [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"]; - [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"]; - [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:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - if ([[[NCKeychain alloc] init] disableCrashservice]) row.value = @"1"; - else row.value = @"0"; - [section addFormRow:row]; - } - - // Section DIAGNOSTICS ------------------------------------------------- - - section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_diagnostics_", nil)]; - [form addFormSection:section]; - - if ([[NSFileManager defaultManager] fileExistsAtPath:NextcloudKit.shared.nkCommonInstance.filenamePathLog] && NCBrandOptions.shared.disable_log == false) { - - 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:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.action.formBlock = ^(XLFormRowDescriptor * sender) { - - [self deselectFormRow:sender]; - NCViewerQuickLook *viewerQuickLook = [[NCViewerQuickLook alloc] initWith:[NSURL fileURLWithPath:NextcloudKit.shared.nkCommonInstance.filenamePathLog] isEditingEnabled:false metadata:nil]; - [self presentViewController:viewerQuickLook animated:YES completion: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:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.action.formBlock = ^(XLFormRowDescriptor * sender) { - - [self deselectFormRow:sender]; - - [[[NextcloudKit shared] nkCommonInstance] clearFileLog]; - - 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]]; - } - }; - [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]; - } - - 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:[NCBrandColor shared].iconImageColor 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]; - - // 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.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:@"trash"] imageWithColor:[NCBrandColor shared].iconImageColor 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; - - self.tableView.backgroundColor = UIColor.systemGroupedBackgroundColor; - - [self initializeForm]; - [self calculateSize]; -} - -#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]; - } - - if ([rowDescriptor.tag isEqualToString:@"deleteoldfiles"]) { - - NSInteger days = [[rowDescriptor.value valueData] intValue]; - [[NCKeychain alloc] init].cleanUpDay = days; - } -} - -#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]; - - [ufs removeGroupDirectoryProviderStorage]; - [ufs removeGroupLibraryDirectory]; - - [ufs removeDocumentsDirectory]; - [ufs removeTemporaryDirectory]; - - [ufs createDirectoryStandard]; - - [[NCAutoUpload shared] alignPhotoLibraryWithViewController:self]; - - [[NCImageCache shared] createMediaCacheWithAccount:appDelegate.account withCacheSize:true]; - - [[NCActivityIndicator shared] stop]; - [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)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) { - [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/CCManageAutoUpload.h b/iOSClient/Settings/CCManageAutoUpload.h deleted file mode 100644 index 1e6b701cfc..0000000000 --- a/iOSClient/Settings/CCManageAutoUpload.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// 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 deleted file mode 100644 index 567c5b49e9..0000000000 --- a/iOSClient/Settings/CCManageAutoUpload.m +++ /dev/null @@ -1,461 +0,0 @@ -// -// 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" - -@interface CCManageAutoUpload () -{ - AppDelegate *appDelegate; -} -@end - -@implementation CCManageAutoUpload - -- (void)initializeForm -{ - XLFormDescriptor *form = [XLFormDescriptor formDescriptor]; - XLFormSectionDescriptor *section; - XLFormRowDescriptor *row; - - 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"]; - [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:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; - 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"]; - [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"]; - [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"]; - [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"]; - [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; - 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]; - - // 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"]; - [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.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; - - 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]; - - [[[NCAskAuthorization alloc] init] askAuthorizationPhotoLibraryWithViewController: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] getActiveAccount]; - - if ([rowDescriptor.tag isEqualToString:@"autoUpload"]) { - - if ([[rowDescriptor.value valueData] boolValue] == YES) { - - [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUpload" state:YES]; - - // Default - [[NCManageDatabase shared] setAccountAutoUploadFileName:@""]; - [[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] alignPhotoLibraryWithViewController:self]; - - } else { - - [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUpload" state:NO]; - [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadFull" state:NO]; - - // remove - [[NCManageDatabase shared] clearMetadatasUploadWithAccount:appDelegate.account]; - } - - [self reloadForm]; - } - - if ([rowDescriptor.tag isEqualToString:@"autoUploadFull"]) { - - if ([[rowDescriptor.value valueData] boolValue] == YES) { - - [[NCAutoUpload shared] autoUploadFullPhotosWithViewController:self log:@"Auto upload full"]; - [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadFull" state:YES]; - - } else { - - [[NCManageDatabase shared] clearMetadatasUploadWithAccount:appDelegate.account]; - [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadFull" state:NO]; - } - } - - if ([rowDescriptor.tag isEqualToString:@"autoUploadImage"]) { - - [[NCManageDatabase shared] setAccountAutoUploadProperty:@"autoUploadImage" state:[[rowDescriptor.value valueData] boolValue]]; - - if ([[rowDescriptor.value valueData] boolValue] == YES) { - [[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] 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 *rowAutoUploadFull = [self.form formRowWithTag:@"autoUploadFull"]; - - XLFormRowDescriptor *rowAutoUploadCreateSubfolder = [self.form formRowWithTag:@"autoUploadCreateSubfolder"]; - - XLFormRowDescriptor *rowAutoUploadSubfolderGranularity = [self.form formRowWithTag:@"autoUploadSubfolderGranularity"]; - - XLFormRowDescriptor *rowAutoUploadFileName = [self.form formRowWithTag:@"autoUploadFileName"]; - - // - STATUS --------------------- - 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 (activeAccount.autoUploadVideo) - [rowAutoUploadVideo setValue:@1]; else [rowAutoUploadVideo setValue:@0]; - - if (activeAccount.autoUploadWWAnVideo) - [rowAutoUploadWWAnVideo setValue:@1]; else [rowAutoUploadWWAnVideo setValue:@0]; - - if (activeAccount.autoUploadFull) - [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"]; - - 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] 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(@"_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 -{ - 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]; - 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/Display/NCDisplayModel.swift b/iOSClient/Settings/Display/NCDisplayModel.swift new file mode 100644 index 0000000000..17d6b9d826 --- /dev/null +++ b/iOSClient/Settings/Display/NCDisplayModel.swift @@ -0,0 +1,53 @@ +// +// NCDisplayModel.swift +// Nextcloud +// +// Created by Marino Faggiana on 30/05/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// + +import Foundation +import SwiftUI + +class NCDisplayModel: ObservableObject, ViewOnAppearHandling { + /// AppDelegate + let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + /// Keychain access + var keychain = NCKeychain() + /// Root View Controller + @Published var controller: NCMainTabBarController? + /// State variable for enabling the automatic appreance + @Published var appearanceAutomatic: Bool = false + + /// Initializes the view model with default values. + init(controller: NCMainTabBarController?) { + self.controller = controller + onViewAppear() + } + + /// Triggered when the view appears. + func onViewAppear() { + appearanceAutomatic = keychain.appearanceAutomatic + } + + // MARK: - All functions + + /// Update window(s) style + func userInterfaceStyle(_ style: UIUserInterfaceStyle) { + let windowScenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene } + keychain.appearanceInterfaceStyle = style + for windowScene in windowScenes { + for window in windowScene.windows { + window.overrideUserInterfaceStyle = style + } + } + } + + /// Updates the value of `appearanceAutomatic` in the keychain. + func updateAppearanceAutomatic() { + keychain.appearanceAutomatic = appearanceAutomatic + if appearanceAutomatic { + userInterfaceStyle(.unspecified) + } + } +} diff --git a/iOSClient/Settings/Display/NCDisplayView.swift b/iOSClient/Settings/Display/NCDisplayView.swift new file mode 100644 index 0000000000..a4152ab0ae --- /dev/null +++ b/iOSClient/Settings/Display/NCDisplayView.swift @@ -0,0 +1,78 @@ +// +// NCDisplayView.swift +// Nextcloud +// +// Created by Marino Faggiana on 30/05/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// + +import SwiftUI + +struct NCDisplayView: View { + @ObservedObject var model: NCDisplayModel + @Environment(\.colorScheme) var colorScheme + + var body: some View { + Form { + Section(header: Text(NSLocalizedString("_appearance_", comment: ""))) { + VStack { + HStack { + Spacer() + VStack { + Image(systemName: "sun.max") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 50, height: 100) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_light_", comment: "")) + Image(systemName: colorScheme == .light ? "checkmark.circle.fill" : "circle") + .foregroundColor(Color(NCBrandColor.shared.brandElement)) + .imageScale(.large) + .font(Font.system(.body).weight(.light)) + .frame(width: 50, height: 50) + } + .onTapGesture { + model.userInterfaceStyle(.light) + } + Spacer() + VStack { + Image(systemName: "moon.fill") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 50, height: 100) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_dark_", comment: "")) + Image(systemName: colorScheme == .dark ? "checkmark.circle.fill" : "circle") + .foregroundColor(Color(NCBrandColor.shared.brandElement)) + .imageScale(.large) + .font(Font.system(.body).weight(.light)) + .frame(width: 50, height: 50) + } + .onTapGesture { + model.userInterfaceStyle(.dark) + } + Spacer() + } + Divider() + .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: -50)) + + Toggle(NSLocalizedString("_use_system_style_", comment: ""), isOn: $model.appearanceAutomatic) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.appearanceAutomatic) { _ in + model.updateAppearanceAutomatic() + } + } + } + .font(.system(size: 16)) + } + .navigationBarTitle(NSLocalizedString("_display_", comment: "")) + .defaultViewModifier(model) + .padding(.top, 0) + } +} + +#Preview { + NCDisplayView(model: NCDisplayModel(controller: nil)) +} diff --git a/iOSClient/Settings/Helpers/NCAcknowledgementsView.swift b/iOSClient/Settings/Helpers/NCAcknowledgementsView.swift new file mode 100644 index 0000000000..b181838ae4 --- /dev/null +++ b/iOSClient/Settings/Helpers/NCAcknowledgementsView.swift @@ -0,0 +1,86 @@ +// +// NCAcknowledgementsView.swift +// Nextcloud +// +// Created by Aditya Tyagi on 04/03/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Aditya Tyagi +// +// 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 + +/// Returns a WebView preferably for Sheets in SwiftUI, using a UIViewRepresentable struct with WebKit library +/// +/// - Parameters: +/// - showText: A Bool value which initiates the RTF file view in the sheet +/// - text: A String value which contains the text of RTF file +/// - browserTitle: A String value to show as the title of the webView +struct NCAcknowledgementsView: View { + @State private var text = "" + @State var showText: Bool = false + var browserTitle: String + @Environment(\.presentationMode) var presentationMode: Binding + + var body: some View { + VStack(spacing: 0) { + HStack { + HStack(alignment: .center) { + Text(browserTitle) + .font(.title3) + .foregroundColor(Color(NCBrandColor.shared.textColor)) + .padding(.leading, 8) + } + .padding() + Spacer() + Button(action: { + presentationMode.wrappedValue.dismiss() + }) { + ZStack { + Image(systemName: "xmark") + .renderingMode(.template) + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 14, height: 14) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + } + } + .padding() + } + Divider() + if showText { + ScrollView { + Text(text) + .padding() + } + } + } + .navigationBarTitle(Text(NSLocalizedString("_autoupload_description_", comment: "")), displayMode: .inline) + .onAppear { + loadRTF() + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + self.showText = true + } + } + } + func loadRTF() { + if let rtfPath = Bundle.main.url(forResource: "Acknowledgements", withExtension: "rtf"), + let attributedStringWithRtf = try? NSAttributedString(url: rtfPath, options: [.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil) { + self.text = attributedStringWithRtf.string + } + } +} diff --git a/iOSClient/Settings/Helpers/NCWebBrowserView.swift b/iOSClient/Settings/Helpers/NCWebBrowserView.swift new file mode 100644 index 0000000000..835241b76c --- /dev/null +++ b/iOSClient/Settings/Helpers/NCWebBrowserView.swift @@ -0,0 +1,101 @@ +// +// NCWebBrowserView.swift +// Nextcloud +// +// Created by Aditya Tyagi on 04/03/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Aditya Tyagi +// +// 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 WebKit + +/// Returns a WebView preferably for Sheets in SwiftUI, using a UIViewRepresentable struct with WebKit library +/// +/// - Parameters: +/// - isPresented: A Bool value which initiates the webView in the parentView +/// - urlBase: A URL value to which our view will open initially +/// - browserTitle: A String value to show as the title of the webView +struct NCBrowserWebView: View { + var urlBase: URL + var browserTitle: String + @Environment(\.presentationMode) var presentationMode: Binding + + var body: some View { + VStack(spacing: 0) { + HStack { + HStack(alignment: .center) { + Text(browserTitle) + .font(.title3) + .foregroundColor(Color(NCBrandColor.shared.textColor)) + .padding(.leading, 8) + } + .padding() + Spacer() + Button(action: { + presentationMode.wrappedValue.dismiss() + }) { + ZStack { + Image(systemName: "xmark") + .renderingMode(.template) + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 14, height: 14) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + } + } + .padding() + } + Divider() + WebView(url: urlBase) + } + .navigationBarTitle(Text(""), displayMode: .inline) // Empty title to hide default navigation bar title + } +} + +struct WebView: UIViewRepresentable { + let url: URL + func makeUIView(context: Context) -> WKWebView { + let webView = WKWebView() + webView.navigationDelegate = context.coordinator + return webView + } + func updateUIView(_ webView: WKWebView, context: Context) { + let request = URLRequest(url: url) + webView.load(request) + } + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + class Coordinator: NSObject, WKNavigationDelegate { + var parent: WebView + init(_ parent: WebView) { + self.parent = parent + } + public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + if let serverTrust = challenge.protectionSpace.serverTrust { + completionHandler(.useCredential, URLCredential(trust: serverTrust)) + } else { + completionHandler(.useCredential, nil) + } + } + public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + decisionHandler(.allow) + } + } +} diff --git a/iOSClient/Settings/NCKeychain.swift b/iOSClient/Settings/NCKeychain.swift index 189cb68db2..4527d49267 100644 --- a/iOSClient/Settings/NCKeychain.swift +++ b/iOSClient/Settings/NCKeychain.swift @@ -56,7 +56,7 @@ import KeychainAccess @objc var passcode: String? { get { migrate(key: "passcodeBlock") - if let value = try? keychain.get("passcodeBlock") { + if let value = try? keychain.get("passcodeBlock"), !value.isEmpty { return value } return nil @@ -346,6 +346,38 @@ import KeychainAccess } } + var appearanceAutomatic: Bool { + get { + if let value = try? keychain.get("appearanceAutomatic"), let result = Bool(value) { + return result + } + return true + } + set { + keychain["appearanceAutomatic"] = String(newValue) + } + } + + var appearanceInterfaceStyle: UIUserInterfaceStyle { + get { + if let value = try? keychain.get("appearanceInterfaceStyle") { + if value == "light" { + return .light + } else { + return .dark + } + } + return .light + } + set { + if newValue == .light { + keychain["appearanceInterfaceStyle"] = "light" + } else { + keychain["appearanceInterfaceStyle"] = "dark" + } + } + } + // MARK: - @objc func getPassword(account: String) -> String { diff --git a/iOSClient/Settings/NCManageAutoUploadFileName.swift b/iOSClient/Settings/NCManageAutoUploadFileName.swift deleted file mode 100644 index 4279a1eb39..0000000000 --- a/iOSClient/Settings/NCManageAutoUploadFileName.swift +++ /dev/null @@ -1,214 +0,0 @@ -// -// 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 - -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["backgroundColor"] = UIColor.secondarySystemGroupedBackground - - row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) - row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.textColor - - 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["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) - row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.textColor - - 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.value = fileNameMask - } - row.hidden = "$\("maintainOriginalFileName") == 1" - row.cellConfig["backgroundColor"] = UIColor.secondarySystemGroupedBackground - - row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0) - row.cellConfig["textLabel.textColor"] = NCBrandColor.shared.textColor - - row.cellConfig["textField.textAlignment"] = NSTextAlignment.right.rawValue - row.cellConfig["textField.font"] = UIFont.systemFont(ofSize: 15.0) - row.cellConfig["textField.textColor"] = NCBrandColor.shared.textColor - - 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"] = NCBrandColor.shared.textColor - - 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() - } - - // 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) - - 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) - } - - 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 deleted file mode 100644 index cab5d57de6..0000000000 --- a/iOSClient/Settings/NCManageE2EE.swift +++ /dev/null @@ -1,390 +0,0 @@ -// -// 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, rootViewController: UIViewController?) -> UIViewController { - - let details = NCViewE2EE(account: account, rootViewController: rootViewController) - 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 rootViewController: UIViewController? - @Published var isEndToEndEnabled: Bool = false - @Published var statusOfService: String = NSLocalizedString("_status_in_progress_", comment: "") - - init(rootViewController: UIViewController?) { - super.init() - self.rootViewController = rootViewController - 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(metadata: tableMetadata?) { - 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 - rootViewController?.present(passcodeViewController, animated: true) - } - - @objc func correctPasscode() { - - switch self.passcodeType { - case "startE2E": - endToEndInitialize.initEndToEndEncryption(viewController: rootViewController, metadata: nil) - 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 - })) - 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 })) - 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 - @State var rootViewController: UIViewController? - - init(account: String, rootViewController: UIViewController?) { - self.manageE2EE = NCManageE2EE(rootViewController: rootViewController) - self.account = account - self.rootViewController = rootViewController - } - - var body: some View { - - VStack { - - if manageE2EE.isEndToEndEnabled { - - List { - - Section(header: Text(""), footer: Text(manageE2EE.statusOfService + "\n\n" + "End-to-End Encryption " + NCGlobal.shared.capabilityE2EEApiVersion)) { - Label { - Text(NSLocalizedString("_e2e_settings_activated_", comment: "")) - } icon: { - Image(systemName: "checkmark.circle.fill") - .resizable() - .scaledToFit() - .font(Font.system(.body).weight(.light)) - .foregroundColor(.green) - } - } - - HStack { - Label { - Text(NSLocalizedString("_e2e_settings_read_passphrase_", comment: "")) - } icon: { - Image(systemName: "eye") - .resizable() - .scaledToFit() - .font(Font.system(.body).weight(.light)) - .foregroundColor(.black) - } - Spacer() - } - .contentShape(Rectangle()) - .onTapGesture { - if NCKeychain().passcode != nil { - manageE2EE.requestPasscodeType("readPassphrase") - } else { - NCContentPresenter().showInfo(error: NKError(errorCode: 0, errorDescription: "_e2e_settings_lock_not_active_")) - } - } - - HStack { - Label { - Text(NSLocalizedString("_e2e_settings_remove_", comment: "")) - } icon: { - Image(systemName: "trash") - .resizable() - .scaledToFit() - .font(Font.system(.body).weight(.light)) - .foregroundColor(.red) - } - Spacer() - } - .contentShape(Rectangle()) - .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 { - - Section(header: Text(""), footer: Text(manageE2EE.statusOfService + "\n\n" + "End-to-End Encryption " + NCGlobal.shared.capabilityE2EEApiVersion)) { - HStack { - Label { - Text(NSLocalizedString("_e2e_settings_start_", comment: "")) - } icon: { - Image(systemName: "play.circle") - .resizable() - .scaledToFit() - .font(Font.system(.body).weight(.light)) - .foregroundColor(.green) - } - 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 - } - } - } - .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() - .font(Font.system(.body).weight(.light)) - .foregroundColor(Color(NCBrandColor.shared.textColor2)) - } - 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() - .font(Font.system(.body).weight(.light)) - .foregroundColor(Color(NCBrandColor.shared.textColor2)) - } - 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) - .font(Font.system(.body).weight(.light)) - .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) - .font(Font.system(.body).weight(.light)) - .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, rootViewController: nil) - // swiftlint:enable force_cast - } -} diff --git a/iOSClient/Settings/NCSettings.h b/iOSClient/Settings/NCSettings.h deleted file mode 100644 index e06a29f1ac..0000000000 --- a/iOSClient/Settings/NCSettings.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// 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 deleted file mode 100644 index 2b0056c40f..0000000000 --- a/iOSClient/Settings/NCSettings.m +++ /dev/null @@ -1,488 +0,0 @@ -// -// 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 - -#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 : PRIVACY -------------------------------------------------------------- - - section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_privacy_", 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.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"]; - [section addFormRow:row]; - // Lock no screen - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"notPasscodeAtStart" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_lock_protection_no_screen_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - if ([[NCBrandOptions shared] doNotAskPasscodeAtStartup]) { - row.disabled = @YES; - } - [section addFormRow:row]; - // Privacy screen - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"privacyScreen" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_privacy_screen_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - [section addFormRow:row]; - // Reset app wrong attemps - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"resetAppAttemps" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_reset_wrong_passcode_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - [section addFormRow:row]; - - // Section : CALDAV CARDAV -------------------------------------------------------------- - - if (!NCBrandOptions.shared.disable_mobileconfig) { - - section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_calendar_contacts_", nil)]; - [form addFormSection:section]; - - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"caldavcardav" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_mobile_config_", 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:@"caldavcardav"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.action.formSelector = @selector(CalDAVCardDAV:); - [section addFormRow:row]; - } - - // Section : E2EEncryption -------------------------------------------------------------- - - BOOL isE2EEEnabled = [[NCGlobal shared] capabilityE2EEEnabled]; - NSString *versionE2EE = [[NCGlobal shared] capabilityE2EEApiVersion]; - - if (isE2EEEnabled == YES && [NCGlobal.shared.e2eeVersions containsObject:versionE2EE]) { - - section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_e2e_settings_title_", nil)]; - [form addFormSection:section]; - - // 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: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 : INFORMATION ------------------------------------------------ - - section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_information_", nil)]; - [form addFormSection:section]; - - // Acknowledgements - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"buttonLeftAligned" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_acknowledgements_", 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:@"acknowledgements"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.action.formBlock = ^(XLFormRowDescriptor * sender){ - [self performSegueWithIdentifier:@"AcknowledgementsSegue" sender:sender]; - [self deselectFormRow:sender]; - }; - [section addFormRow:row]; - - if (!NCBrandOptions.shared.disable_crash_service) { - - // Privacy and Legal Policy - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"privacy" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_privacy_legal_", 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:@"shield.checkerboard"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.action.formSelector = @selector(privacy:); - [section addFormRow:row]; - - // Source code - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"sourcecode" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_source_code_", 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:@"gitHub"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.action.formSelector = @selector(sourceCode:); - [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:UIApplicationDidEnterBackgroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeUser) name:NCGlobal.shared.notificationCenterChangeUser object:nil]; - - [self initializeForm]; - [self reloadForm]; -} - -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - - 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"]; - XLFormRowDescriptor *rowResetAppAttemps = [self.form formRowWithTag:@"resetAppAttemps"]; - XLFormRowDescriptor *rowPrivacyScreen = [self.form formRowWithTag:@"privacyScreen"]; - - // ------------------------------------------------------------------ - - 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"]; - } else { - rowBloccoPasscode.title = NSLocalizedString(@"_lock_not_active_", nil); - [rowBloccoPasscode.cellConfig setObject:[[UIImage imageNamed:@"lock_open"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - } - - if ([[NCKeychain alloc] init].resetAppCounterFail) [rowResetAppAttemps setValue:@1]; else [rowResetAppAttemps setValue:@0]; - if ([[NCKeychain alloc] init].touchFaceID) [rowEnableTouchDaceID setValue:@1]; else [rowEnableTouchDaceID setValue:@0]; - if ([[NCKeychain alloc] init].requestPasscodeAtStart) [rowNotPasscodeAtStart setValue:@0]; else [rowNotPasscodeAtStart setValue:@1]; - if ([[NCKeychain alloc] init].privacyScreenEnabled) [rowPrivacyScreen setValue:@1]; else [rowPrivacyScreen setValue:@0]; - - - // ----------------------------------------------------------------- - - [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; - } - } - - if ([rowDescriptor.tag isEqualToString:@"privacyScreen"]) { - - if ([[rowDescriptor.value valueData] boolValue] == YES) { - [[NCKeychain alloc] init].privacyScreenEnabled = true; - } else { - [[NCKeychain alloc] init].privacyScreenEnabled = false; - } - } - - if ([rowDescriptor.tag isEqualToString:@"resetAppAttemps"]) { - - NSInteger value = [[rowDescriptor.value valueData] intValue]; - [[NCKeychain alloc] init].resetAppCounterFail = value; - } -} - -#pragma mark - - -- (void)manageE2EE:(XLFormRowDescriptor *)sender -{ - [self deselectFormRow:sender]; - - UIViewController *vc = [[NCManageE2EEInterface alloc] makeShipDetailsUIWithAccount:appDelegate.account rootViewController: self.tabBarController]; - [self.navigationController pushViewController:vc animated:YES]; -} - -- (void)privacy:(XLFormRowDescriptor *)sender -{ - [self deselectFormRow:sender]; - - NCBrowserWeb* browserWebVC = [[UIStoryboard storyboardWithName:@"NCBrowserWeb" bundle:nil] instantiateInitialViewController]; - - browserWebVC.urlBase = NCBrandOptions.shared.privacy; - browserWebVC.isHiddenButtonExit = false; - browserWebVC.titleBrowser = NSLocalizedString(@"_privacy_", nil); - - [self presentViewController:browserWebVC animated:YES completion:nil]; -} - -- (void)sourceCode:(XLFormRowDescriptor *)sender -{ - [self deselectFormRow:sender]; - - NCBrowserWeb* browserWebVC = [[UIStoryboard storyboardWithName:@"NCBrowserWeb" bundle:nil] instantiateInitialViewController]; - - browserWebVC.urlBase = NCBrandOptions.shared.sourceCode; - browserWebVC.isHiddenButtonExit = false; - browserWebVC.titleBrowser = NSLocalizedString(@"_source_code_", nil); - - [self presentViewController:browserWebVC animated:YES completion:nil]; -} - -- (void)CalDAVCardDAV:(XLFormRowDescriptor *)sender -{ - [self deselectFormRow:sender]; - - NSString *url = [appDelegate.urlBase stringByAppendingString:NCBrandOptions.shared.mobileconfig]; - NCConfigServer *configServer = [NCConfigServer new]; - [configServer startServiceWithUrl:[NSURL URLWithString: url]]; -} - - -#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; - - if (section == 1) { - NSString *lock = NSLocalizedString(@"_lock_protection_no_screen_footer_", nil); - NSString *reset = [NSString stringWithFormat:NSLocalizedString(@"_reset_wrong_passcode_desc_", nil), NCBrandOptions.shared.resetAppPasscodeAttempts]; - sectionName = [NSString stringWithFormat:@"%@\n%@", lock, reset]; - } else if (section == 2 && !NCBrandOptions.shared.disable_mobileconfig) { - sectionName = NSLocalizedString(@"_calendar_contacts_footer_", nil); - } else if (section == numSections) { - NSString *versionNextcloud = [NSString stringWithFormat:[NCBrandOptions shared].textCopyrightNextcloudServer, versionServer]; - NSString *versionNextcloudiOS = [NSString stringWithFormat:[NCBrandOptions shared].textCopyrightNextcloudiOS, [[[NCUtility alloc] init] getVersionAppWithBuild:true]]; - NSString *nameSlogan = [NSString stringWithFormat:@"%@ - %@", themingName, themingSlogan]; - sectionName = [NSString stringWithFormat:@"\n%@\n\n%@\n%@", versionNextcloudiOS, versionNextcloud, nameSlogan]; - } - return sectionName; -} - -@end diff --git a/iOSClient/Settings/NCSettings.storyboard b/iOSClient/Settings/NCSettings.storyboard deleted file mode 100644 index 5484294f6e..0000000000 --- a/iOSClient/Settings/NCSettings.storyboard +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOSClient/Settings/NCEndToEndInitialize.swift b/iOSClient/Settings/Settings/E2EE/NCEndToEndInitialize.swift similarity index 100% rename from iOSClient/Settings/NCEndToEndInitialize.swift rename to iOSClient/Settings/Settings/E2EE/NCEndToEndInitialize.swift diff --git a/iOSClient/Settings/Settings/E2EE/NCManageE2EEModel.swift b/iOSClient/Settings/Settings/E2EE/NCManageE2EEModel.swift new file mode 100644 index 0000000000..1ed8bbaccd --- /dev/null +++ b/iOSClient/Settings/Settings/E2EE/NCManageE2EEModel.swift @@ -0,0 +1,152 @@ +// +// NCManageE2EEModel.swift +// Nextcloud +// +// Created by Marino Faggiana on 30/05/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 UIKit +import SwiftUI +import NextcloudKit +import TOPasscodeViewController +import LocalAuthentication + +class NCManageE2EE: NSObject, ObservableObject, ViewOnAppearHandling, NCEndToEndInitializeDelegate, TOPasscodeViewControllerDelegate { + let endToEndInitialize = NCEndToEndInitialize() + let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + var passcodeType = "" + + @Published var controller: UITabBarController? + @Published var isEndToEndEnabled: Bool = false + @Published var statusOfService: String = NSLocalizedString("_status_in_progress_", comment: "") + @Published var navigateBack: Bool = false + + init(controller: UITabBarController?) { + super.init() + self.controller = controller + endToEndInitialize.delegate = self + onViewAppear() + } + + /// Triggered when the view appears. + func onViewAppear() { + if NCGlobal.shared.capabilityE2EEEnabled && NCGlobal.shared.e2eeVersions.contains(NCGlobal.shared.capabilityE2EEApiVersion) { + 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: "") + } + } + } + } else { + navigateBack = true + } + } + + // MARK: - Delegate + + func endToEndInitializeSuccess(metadata: tableMetadata?) { + 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 + controller?.present(passcodeViewController, animated: true) + } + + @objc func correctPasscode() { + switch self.passcodeType { + case "startE2E": + endToEndInitialize.initEndToEndEncryption(viewController: controller, metadata: nil) + 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 + })) + controller?.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 })) + controller?.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) + } +} diff --git a/iOSClient/Settings/Settings/E2EE/NCManageE2EEView.swift b/iOSClient/Settings/Settings/E2EE/NCManageE2EEView.swift new file mode 100644 index 0000000000..3ee5bfa6e4 --- /dev/null +++ b/iOSClient/Settings/Settings/E2EE/NCManageE2EEView.swift @@ -0,0 +1,189 @@ +// +// NCManageE2EEView.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 + +struct NCManageE2EEView: View { + @ObservedObject var model: NCManageE2EE + @Environment(\.presentationMode) var presentationMode + + var body: some View { + VStack { + if model.isEndToEndEnabled { + List { + Section(header: Text(""), footer: Text(model.statusOfService + "\n\n" + "End-to-End Encryption " + NCGlobal.shared.capabilityE2EEApiVersion)) { + Label { + Text(NSLocalizedString("_e2e_settings_activated_", comment: "")) + } icon: { + Image(systemName: "checkmark.circle.fill") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundColor(.green) + } + } + HStack { + Label { + Text(NSLocalizedString("_e2e_settings_read_passphrase_", comment: "")) + } icon: { + Image(systemName: "eye") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + } + Spacer() + } + .contentShape(Rectangle()) + .onTapGesture { + if NCKeychain().passcode != nil { + model.requestPasscodeType("readPassphrase") + } else { + NCContentPresenter().showInfo(error: NKError(errorCode: 0, errorDescription: "_e2e_settings_lock_not_active_")) + } + } + HStack { + Label { + Text(NSLocalizedString("_e2e_settings_remove_", comment: "")) + } icon: { + Image(systemName: "xmark") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 15) + .foregroundColor(.red) + } + Spacer() + } + .contentShape(Rectangle()) + .onTapGesture { + if NCKeychain().passcode != nil { + model.requestPasscodeType("removeLocallyEncryption") + } else { + NCContentPresenter().showInfo(error: NKError(errorCode: 0, errorDescription: "_e2e_settings_lock_not_active_")) + } + } +#if DEBUG + deleteCerificateSection +#endif + } + } else { + List { + Section(header: Text(""), footer: Text(model.statusOfService + "\n\n" + "End-to-End Encryption " + NCGlobal.shared.capabilityE2EEApiVersion)) { + HStack { + Label { + Text(NSLocalizedString("_e2e_settings_start_", comment: "")) + } icon: { + Image(systemName: "play.circle") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundColor(.green) + } + Spacer() + } + .contentShape(Rectangle()) + .onTapGesture { + if NCKeychain().passcode != nil { + model.requestPasscodeType("startE2E") + } else { + NCContentPresenter().showInfo(error: NKError(errorCode: 0, errorDescription: "_e2e_settings_lock_not_active_")) + } + } + } +#if DEBUG + deleteCerificateSection +#endif + } + } + } + .navigationBarTitle(NSLocalizedString("_e2e_settings_", comment: "")) + .background(Color(UIColor.systemGroupedBackground)) + .defaultViewModifier(model) + .onChange(of: model.navigateBack) { newValue in + if newValue { + presentationMode.wrappedValue.dismiss() + } + } + } + + @ViewBuilder + var deleteCerificateSection: 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() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundColor(Color(NCBrandColor.shared.textColor2)) + } + 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() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundColor(Color(NCBrandColor.shared.textColor2)) + } + 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) + } + } + } + } + } +} + +#Preview { + NCManageE2EEView(model: NCManageE2EE(controller: nil)) +} diff --git a/iOSClient/Settings/Settings/NCSettingsModel.swift b/iOSClient/Settings/Settings/NCSettingsModel.swift new file mode 100644 index 0000000000..451fbb7da6 --- /dev/null +++ b/iOSClient/Settings/Settings/NCSettingsModel.swift @@ -0,0 +1,191 @@ +// +// NCSettingsViewModel.swift +// Nextcloud +// +// Created by Aditya Tyagi on 05/03/24. +// Created by Marino Faggiana on 30/05/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Aditya Tyagi +// +// 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 +import SwiftUI +import TOPasscodeViewController +import LocalAuthentication + +class NCSettingsModel: ObservableObject, ViewOnAppearHandling { + /// AppDelegate + let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + /// Keychain access + var keychain = NCKeychain() + /// State to control the lock on/off section + @Published var isLockActive: Bool = false + /// State to control the enable TouchID toggle + @Published var enableTouchID: Bool = false + /// State to control + @Published var lockScreen: Bool = false + /// State to control + @Published var privacyScreen: Bool = false + /// State to control + @Published var resetWrongAttempts: Bool = false + /// Root View Controller + @Published var controller: NCMainTabBarController? + /// Footer + var footerApp = "" + var footerServer = "" + var footerSlogan = "" + + /// Initializes the view model with default values. + init(controller: NCMainTabBarController?) { + self.controller = controller + onViewAppear() + } + + /// Triggered when the view appears. + func onViewAppear() { + isLockActive = (keychain.passcode != nil) + enableTouchID = keychain.touchFaceID + lockScreen = !keychain.requestPasscodeAtStart + privacyScreen = keychain.privacyScreenEnabled + resetWrongAttempts = keychain.resetAppCounterFail + footerApp = String(format: NCBrandOptions.shared.textCopyrightNextcloudiOS, NCUtility().getVersionApp(withBuild: true)) + "\n\n" + footerServer = String(format: NCBrandOptions.shared.textCopyrightNextcloudServer, NCGlobal.shared.capabilityServerVersion) + "\n" + footerSlogan = NCGlobal.shared.capabilityThemingName + " - " + NCGlobal.shared.capabilityThemingSlogan + "\n\n" + } + + // MARK: - All functions + + /// Function to update Touch ID / Face ID setting + func updateTouchIDSetting() { + keychain.touchFaceID = enableTouchID + } + + /// Function to update Lock Screen setting + func updateLockScreenSetting() { + keychain.requestPasscodeAtStart = !lockScreen + } + + /// Function to update Privacy Screen setting + func updatePrivacyScreenSetting() { + keychain.privacyScreenEnabled = privacyScreen + } + + /// Function to update Reset Wrong Attempts setting + func updateResetWrongAttemptsSetting() { + keychain.resetAppCounterFail = resetWrongAttempts + } + + /// This function initiates a service call to download the configuration files + /// using the URL provided in the `configLink` property. + func getConfigFiles() { + let configLink = appDelegate.urlBase + NCBrandOptions.shared.mobileconfig + let configServer = NCConfigServer() + if let url = URL(string: configLink) { + configServer.startService(url: url) + } + } +} + +struct PasscodeView: UIViewControllerRepresentable { + @Binding var isLockActive: Bool + + func makeUIViewController(context: Context) -> UIViewController { + let laContext = LAContext() + var error: NSError? + if NCKeychain().passcode != nil { + let passcodeViewController = TOPasscodeViewController(passcodeType: .sixDigits, allowCancel: true) + passcodeViewController.keypadButtonShowLettering = false + if NCKeychain().touchFaceID && laContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { + if error == nil { + if laContext.biometryType == .faceID { + passcodeViewController.biometryType = .faceID + passcodeViewController.allowBiometricValidation = true + passcodeViewController.automaticallyPromptForBiometricValidation = true + } else if laContext.biometryType == .touchID { + passcodeViewController.biometryType = .touchID + passcodeViewController.allowBiometricValidation = true + passcodeViewController.automaticallyPromptForBiometricValidation = true + } else { + print("No Biometric support") + } + } + } + passcodeViewController.delegate = context.coordinator + return passcodeViewController + } else { + let passcodeSettingsViewController = TOPasscodeSettingsViewController() + passcodeSettingsViewController.hideOptionsButton = true + passcodeSettingsViewController.requireCurrentPasscode = false + passcodeSettingsViewController.passcodeType = .sixDigits + passcodeSettingsViewController.delegate = context.coordinator + return passcodeSettingsViewController + } + } + + func updateUIViewController(_ uiViewController: UIViewController, context: Context) { + // Update the view controller if needed + } + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + class Coordinator: NSObject, TOPasscodeSettingsViewControllerDelegate, TOPasscodeViewControllerDelegate { + var parent: PasscodeView + init(_ parent: PasscodeView) { + self.parent = parent + } + + func didPerformBiometricValidationRequest(in passcodeViewController: TOPasscodeViewController) { + let context = LAContext() + var error: NSError? + + if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { + context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: NCBrandOptions.shared.brand) { success, _ in + DispatchQueue.main.async { + if success { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + NCKeychain().passcode = nil + passcodeViewController.dismiss(animated: true) + } + } + } + } + } + } + + func passcodeSettingsViewController(_ passcodeSettingsViewController: TOPasscodeSettingsViewController, didChangeToNewPasscode passcode: String, of type: TOPasscodeType) { + NCKeychain().passcode = passcode + self.parent.isLockActive = true + passcodeSettingsViewController.dismiss(animated: true) + } + + func didTapCancel(in passcodeViewController: TOPasscodeViewController) { + passcodeViewController.dismiss(animated: true) + } + + func passcodeViewController(_ passcodeViewController: TOPasscodeViewController, isCorrectCode code: String) -> Bool { + if code == NCKeychain().passcode { + self.parent.isLockActive = false + NCKeychain().passcode = nil + return true + } + return false + } + } +} diff --git a/iOSClient/Settings/Settings/NCSettingsView.swift b/iOSClient/Settings/Settings/NCSettingsView.swift new file mode 100644 index 0000000000..93cafd8b7a --- /dev/null +++ b/iOSClient/Settings/Settings/NCSettingsView.swift @@ -0,0 +1,276 @@ +// +// NCSettingsView.swift +// Nextcloud +// +// Created by Aditya Tyagi on 03/03/24. +// Created by Marino Faggiana on 30/05/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Aditya Tyagi +// +// 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 + +/// Settings view for Nextcloud +struct NCSettingsView: View { + /// State to control the visibility of the acknowledgements view + @State private var showAcknowledgements = false + /// State to control the visibility of the passcode view + @State private var showPasscode = false + /// State to control the visibility of the Policy view + @State private var showBrowser = false + /// State to control the visibility of the Source Code view + @State private var showSourceCode = false + /// Object of ViewModel of this view + @ObservedObject var model: NCSettingsModel + + var body: some View { + Form { + /// `Auto Upload` Section + Section(content: { + NavigationLink(destination: LazyView { + NCAutoUploadView(model: NCAutoUploadModel(controller: model.controller)) + }) { + HStack { + Image(systemName: "photo.circle") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_settings_autoupload_", comment: "")) + } + .font(.system(size: 16)) + } + }, header: { + }, footer: { + Text(NSLocalizedString("_autoupload_description_", comment: "")) + }) + /// `Privacy` Section + Section(content: { + Button(action: { + showPasscode.toggle() + }, label: { + HStack { + Image(systemName: model.isLockActive ? "lock" : "lock.open") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + .frame(width: 20, height: 20) + Text(model.isLockActive ? NSLocalizedString("_lock_active_", comment: "") : NSLocalizedString("_lock_not_active_", comment: "")) + } + .font(.system(size: 16)) + }) + .tint(Color(NCBrandColor.shared.textColor)) + .sheet(isPresented: $showPasscode) { + PasscodeView(isLockActive: $model.isLockActive) + } + /// Enable Touch ID + Toggle(NSLocalizedString("_enable_touch_face_id_", comment: ""), isOn: $model.enableTouchID) + .tint(Color(NCBrandColor.shared.brandElement)) + .font(.system(size: 16)) + .onChange(of: model.enableTouchID) { _ in + model.updateTouchIDSetting() + } + /// Lock no screen + Toggle(NSLocalizedString("_lock_protection_no_screen_", comment: ""), isOn: $model.lockScreen) + .tint(Color(NCBrandColor.shared.brandElement)) + .font(.system(size: 16)) + .onChange(of: model.lockScreen) { _ in + model.updateLockScreenSetting() + } + /// Privacy screen + Toggle(NSLocalizedString("_privacy_screen_", comment: ""), isOn: $model.privacyScreen) + .tint(Color(NCBrandColor.shared.brandElement)) + .font(.system(size: 16)) + .onChange(of: model.privacyScreen) { _ in + model.updatePrivacyScreenSetting() + } + /// Reset app wrong attempts + Toggle(NSLocalizedString("_reset_wrong_passcode_", comment: ""), isOn: $model.resetWrongAttempts) + .tint(Color(NCBrandColor.shared.brandElement)) + .font(.system(size: 16)) + .onChange(of: model.resetWrongAttempts) { _ in + model.updateResetWrongAttemptsSetting() + } + }, header: { + Text(NSLocalizedString("_privacy_", comment: "")) + }, footer: { + Text(NSLocalizedString("_lock_protection_no_screen_footer_", comment: "") + "\n" + String(format: NSLocalizedString("_reset_wrong_passcode_desc_", comment: ""), NCBrandOptions.shared.resetAppPasscodeAttempts)) + .font(.system(size: 12)) + .lineSpacing(1) + }) + /// Display + Section(header: Text(NSLocalizedString("_display_", comment: "")), content: { + NavigationLink(destination: LazyView { + NCDisplayView(model: NCDisplayModel(controller: model.controller)) + }) { + HStack { + Image(systemName: "sun.max.circle") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 20, height: 20) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_display_", comment: "")) + } + .font(.system(size: 16)) + } + }) + /// Calender & Contacts + if !NCBrandOptions.shared.disable_mobileconfig { + Section(content: { + Button(action: { + model.getConfigFiles() + }, label: { + HStack { + Image(systemName: "calendar.badge.plus") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_mobile_config_", comment: "")) + } + .font(.system(size: 16)) + }) + .tint(Color(NCBrandColor.shared.textColor)) + }, header: { + Text(NSLocalizedString("_calendar_contacts_", comment: "")) + }, footer: { + Text(NSLocalizedString("_calendar_contacts_footer_", comment: "")) + .font(.system(size: 12)) + .lineSpacing(1) + }) + } + /// `E2EEncryption` Section + if NCGlobal.shared.capabilityE2EEEnabled && NCGlobal.shared.e2eeVersions.contains(NCGlobal.shared.capabilityE2EEApiVersion) { + E2EESection(model: model) + } + /// `Advanced` Section + Section { + NavigationLink(destination: LazyView { + NCSettingsAdvancedView(model: NCSettingsAdvancedModel(controller: model.controller), showExitAlert: false, showCacheAlert: false) + }) { + HStack { + Image(systemName: "gear") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_advanced_", comment: "")) + } + .font(.system(size: 16)) + } + } + /// `Information` Section + Section(header: Text(NSLocalizedString("_information_", comment: "")), content: { + // Acknowledgements + Button(action: { + showAcknowledgements.toggle() + }, label: { + HStack { + Image("acknowledgements") + .resizable() + .renderingMode(.template) + .frame(width: 25, height: 25) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_acknowledgements_", comment: "")) + } + .font(.system(size: 16)) + }) + .tint(Color(NCBrandColor.shared.textColor)) + .sheet(isPresented: $showAcknowledgements) { + NCAcknowledgementsView(browserTitle: NSLocalizedString("_acknowledgements_", comment: "")) + } + /// Terms & Privacy Conditions + Button(action: { + showBrowser.toggle() + }, label: { + HStack { + Image(systemName: "shield.checkerboard") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_privacy_legal_", comment: "")) + } + .font(.system(size: 16)) + }) + .tint(Color(NCBrandColor.shared.textColor)) + .sheet(isPresented: $showBrowser) { + NCBrowserWebView(urlBase: URL(string: NCBrandOptions.shared.privacy)!, browserTitle: NSLocalizedString("_privacy_legal_", comment: "")) + } + /// Source Code + Button(action: { + showSourceCode.toggle() + }, label: { + HStack { + Image("gitHub") + .resizable() + .renderingMode(.template) + .frame(width: 25, height: 25) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_source_code_", comment: "")) + } + .font(.system(size: 16)) + }) + .tint(Color(NCBrandColor.shared.textColor)) + .sheet(isPresented: $showSourceCode) { + NCBrowserWebView(urlBase: URL(string: NCBrandOptions.shared.sourceCode)!, browserTitle: NSLocalizedString("_source_code_", comment: "")) + } + }) + /// `Watermark` Section + Section(content: { + }, footer: { + Text(model.footerApp + model.footerServer + model.footerSlogan) + }) + } + .navigationBarTitle(NSLocalizedString("_settings_", comment: "")) + .defaultViewModifier(model) + } +} + +struct E2EESection: View { + @ObservedObject var model: NCSettingsModel + + var body: some View { + Section(header: Text(NSLocalizedString("_e2e_settings_title_", comment: "")), content: { + NavigationLink(destination: LazyView { + NCManageE2EEView(model: NCManageE2EE(controller: model.controller)) + }) { + HStack { + Image(systemName: "lock") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 20, height: 20) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_e2e_settings_", comment: "")) + } + .font(.system(size: 16)) + } + }) + } +} + +#Preview { + NCSettingsView(model: NCSettingsModel(controller: nil)) +} diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 41e507a5a9..d576314d3b 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -156,6 +156,8 @@ "_current_" = "Current"; "_buy_" = "Buy"; "_disabled_" = "Disabled"; +"_standard_" = "Standard"; +"_maximum_" = "Maximum"; "_error_occurred_" = "An error occurred, please try again"; /* MARK: Files lock */ @@ -386,6 +388,7 @@ "_autoupload_photos_" = "Auto upload photos"; "_autoupload_videos_" = "Auto upload videos"; "_autoupload_description_" = "New photos/videos will be automatically uploaded to your server"; +"_auto_delete_cache_files_" = "Auto Delete Cache files after"; "_autoupload_description_background_" = "This option requires the use of GPS to trigger the detection of new photos/videos in the camera roll once the location changes significantly"; "_autoupload_background_title_" = "Limitations"; "_autoupload_background_msg_" = "Due to iOS restrictions, it is not yet possible to perform background processes, unless GPS services are activated. Once the cell in the cellular network is changed, the system wakes up for a short time and checks for new photos to upload to the cloud."; @@ -415,6 +418,7 @@ "_privacy_" = "Privacy"; "_privacy_policy_" = "Privacy Policy"; "_privacy_footer_" = "This app uses a service for the analysis of a crash. Your personal information is not sent with the report. If you want disable it, please change the setting \"Disable crash reporter\" to ON"; +"_show_hidden_files_footer" = "All Hidden files will be visible in every device"; "_crashservice_title_" = "Disable crash reporter"; "_crashservice_alert_" = "This option requires a restart of the app to take effect"; "_upload_mov_livephoto_" = "Live Photo"; @@ -422,10 +426,14 @@ "_view_capabilities_" = "View the capabilities"; "_capabilities_" = "Capabilities"; "_no_capabilities_found_" = "Capabilities not found"; +"_capabilities_footer_" = "Display the packages used by the app if they are installed and available on the server"; "_diagnostics_" = "Diagnostics"; "_view_log_" = "View log file"; "_clear_log_" = "Clear log file"; "_level_log_" = "Set Log level (disabled, standard, maximum)"; +"_set_log_level_" = "Set Log Level"; +"_log_file_clear_alert_" = "Log file cleared \n successfully!"; +"_diagnostics_footer_" = "Log files contains history of all your actions on Nextcloud."; "_connect_server_anyway_" = "Do you want to connect to the server anyway?"; "_server_is_trusted_" = "Do you consider this server trusted?"; "_connection_error_" = "Connection error"; @@ -462,6 +470,7 @@ "_location_not_enabled_msg_" = "Please go to \"Settings\" and turn on \"Location Services\""; "_access_photo_not_enabled_" = "Access to Photos not enabled"; "_access_photo_not_enabled_msg_" = "Please go to \"Settings\" and turn on \"Photo Access\""; +"_access_background_app_refresh_denied_" = "\"Background App Refresh\" is denied. Please enable it in \"Settings\" otherwise, new photos or videos will not be detected when the application is in the background"; "_access_photo_location_not_enabled_" = "Access to Photos and Location not enabled"; "_access_photo_location_not_enabled_msg_" = "Please go to \"Settings\" and turn on \"Photo Access\" and \"Location Services\""; "_tutorial_photo_view_" = "No photos or videos uploaded yet"; @@ -698,6 +707,10 @@ "_rename_filename_" = "Rename"; "_filename_" = "Filename"; "_enter_filename_" = "Enter filename …"; +"_default_filename_image_" = "Filename: IMG_0001.JPG"; +"_default_preview_filename_footer_" = "Example preview of filename: IMG_0001.JPG"; +"_preview_filename_footer_" = "Example preview of filename. You can use the mask YYYY.MM.DD hh.mm.ss am/pm for date/time."; +"_filename_header_" = "Enter filename"; "_preview_filename_" = "Example preview of filename. You can use the mask %@ for date/time"; "_add_filenametype_" = "Specify type in filename"; "_filenametype_photo_video_" = "Photo/Video"; @@ -974,6 +987,12 @@ "_delete_selected_photos_" = "Delete selected photos"; "_media_square_" = "Square photo grid"; "_media_ratio_" = "Aspect ratio grid"; +"_autoupload_notice_" = "To ensure the proper functioning of the application, it is necessary to enable Background App Refresh. Otherwise, new photos or videos will not be detected when the application is in the background.\n\nAdditionally, please note that the application will not be able to detect new photos and videos if it is manually terminated. When the app is in the background, data transfer may be slower, and new photos and/or videos will generally be detected every 10 minutes, depending on the phone’s battery level.\n\nTo verify that the app is functioning correctly, you can use the log file available in Advanced."; +"_display_" = "Display"; +"_appearance_" = "Appearance"; +"_light_" = "Light"; +"_dark_" = "Dark"; +"_use_system_style_" = "Use system style"; // Video "_select_trace_" = "Select the trace"; diff --git a/iOSClient/Viewer/NCViewerQuickLook/ViewerQuickLook.swift b/iOSClient/Viewer/NCViewerQuickLook/NCViewerQuickLookView.swift similarity index 90% rename from iOSClient/Viewer/NCViewerQuickLook/ViewerQuickLook.swift rename to iOSClient/Viewer/NCViewerQuickLook/NCViewerQuickLookView.swift index 9c0d4e6140..9a70572f4c 100644 --- a/iOSClient/Viewer/NCViewerQuickLook/ViewerQuickLook.swift +++ b/iOSClient/Viewer/NCViewerQuickLook/NCViewerQuickLookView.swift @@ -1,5 +1,5 @@ // -// ViewerQuickLook.swift +// NCViewerQuickLookView.swift // Nextcloud // // Created by Marino Faggiana on 12/01/23. @@ -26,13 +26,11 @@ import QuickLook import Mantis import NextcloudKit -struct ViewerQuickLook: UIViewControllerRepresentable { - +struct NCViewerQuickLookView: UIViewControllerRepresentable { let url: URL - @Binding var index: Int @Binding var isPresentedQuickLook: Bool - @ObservedObject var uploadAssets: NCUploadAssets + @ObservedObject var model: NCUploadAssetsModel func makeUIViewController(context: Context) -> UINavigationController { let controller = QLPreviewController() @@ -45,10 +43,10 @@ struct ViewerQuickLook: UIViewControllerRepresentable { let buttonCrop = UIBarButtonItem(image: NCUtility().loadImage(named: "crop"), style: .plain, target: context.coordinator, action: #selector(context.coordinator.crop)) controller.navigationItem.leftBarButtonItems = [buttonDone, buttonCrop] - uploadAssets.startTimer(navigationItem: controller.navigationItem) + model.startTimer(navigationItem: controller.navigationItem) DispatchQueue.main.asyncAfter(deadline: .now() + 1) { - if uploadAssets.previewStore[index].assetType == .livePhoto && uploadAssets.previewStore[index].asset.type == .livePhoto && uploadAssets.previewStore[index].data == nil { + if model.previewStore[index].assetType == .livePhoto && model.previewStore[index].asset.type == .livePhoto && model.previewStore[index].data == nil { let error = NKError(errorCode: NCGlobal.shared.errorCharactersForbidden, errorDescription: "_message_disable_livephoto_") NCContentPresenter().showInfo(error: error) } @@ -65,23 +63,21 @@ struct ViewerQuickLook: UIViewControllerRepresentable { } class Coordinator: NSObject, QLPreviewControllerDataSource, QLPreviewControllerDelegate, CropViewControllerDelegate { - weak var viewController: QLPreviewController? - let parent: ViewerQuickLook - + let parent: NCViewerQuickLookView var image: UIImage? var hasChange = false - init(parent: ViewerQuickLook) { + init(parent: NCViewerQuickLookView) { self.parent = parent } @objc func dismiss() { - parent.uploadAssets.stopTimer() + parent.model.stopTimer() parent.isPresentedQuickLook = false if let imageData = image, let image = image?.resizeImage(size: CGSize(width: 300, height: 300), isAspectRation: true) { - parent.uploadAssets.previewStore[parent.index].image = image - parent.uploadAssets.previewStore[parent.index].data = imageData.jpegData(compressionQuality: 0.9) + parent.model.previewStore[parent.index].image = image + parent.model.previewStore[parent.index].data = imageData.jpegData(compressionQuality: 0.9) } }