AppDelegate.m 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292
  1. //
  2. // AppDelegate.m
  3. // Nextcloud
  4. //
  5. // Created by Marino Faggiana on 04/09/14.
  6. // Copyright (c) 2014 Marino Faggiana. All rights reserved.
  7. //
  8. // Author Marino Faggiana <marino.faggiana@nextcloud.com>
  9. //
  10. // This program is free software: you can redistribute it and/or modify
  11. // it under the terms of the GNU General Public License as published by
  12. // the Free Software Foundation, either version 3 of the License, or
  13. // (at your option) any later version.
  14. //
  15. // This program is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. // GNU General Public License for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License
  21. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. //
  23. #import "AppDelegate.h"
  24. #import "CCGraphics.h"
  25. #import "NCBridgeSwift.h"
  26. #import "NCAutoUpload.h"
  27. #import "NCPushNotificationEncryption.h"
  28. #import <QuartzCore/QuartzCore.h>
  29. @import Sentry;
  30. @class NCViewerRichdocument;
  31. @interface AppDelegate() <TOPasscodeViewControllerDelegate>
  32. @end
  33. @implementation AppDelegate
  34. + (void)initialize
  35. {
  36. [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent": [CCUtility getUserAgent]}];
  37. }
  38. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  39. {
  40. BOOL isSimulatorOrTestFlight = [[NCUtility shared] isSimulatorOrTestFlight];
  41. if (isSimulatorOrTestFlight) {
  42. NCBrandOptions.sharedInstance.disable_crash_service = false;
  43. }
  44. if (![CCUtility getDisableCrashservice] && NCBrandOptions.sharedInstance.disable_crash_service == false) {
  45. [SentrySDK startWithOptions: @{
  46. @"dsn": @"https://42eaf570ec2646b1a564a4c4bfc8c279@o394108.ingest.sentry.io/5243836",
  47. @"debug": @(YES),
  48. @"enableAutoSessionTracking": @(YES)
  49. /* PRIVACY : https://github.com/getsentry/sentry-cocoa
  50. By default, we don’t apply the user identification provided to the SDK via the API. Instead, we use
  51. the installation ID generated with the first use of the application. The ID doesn’t contain any
  52. private or public data of your users or any public or shared data of their device.
  53. */
  54. }];
  55. }
  56. [CCUtility createDirectoryStandard];
  57. [CCUtility emptyTemporaryDirectory];
  58. // Networking
  59. [[NCCommunicationCommon shared] setupWithDelegate:[NCNetworking shared]];
  60. [[NCCommunicationCommon shared] setupWithUserAgent:[CCUtility getUserAgent]];
  61. NSInteger logLevel = [CCUtility getLogLevel];
  62. [[NCCommunicationCommon shared] setFileLogWithLevel:logLevel];
  63. NSString *versionApp = [NSString stringWithFormat:@"%@.%@", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"], [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]];
  64. NSString *versionNextcloudiOS = [NSString stringWithFormat:[NCBrandOptions sharedInstance].textCopyrightNextcloudiOS, versionApp];
  65. if (isSimulatorOrTestFlight) {
  66. [[NCCommunicationCommon shared] writeLog:[NSString stringWithFormat:@"Start session with level %lu %@ (Simulator / TestFlight)", (unsigned long)logLevel, versionNextcloudiOS]];
  67. } else {
  68. [[NCCommunicationCommon shared] writeLog:[NSString stringWithFormat:@"Start session with level %lu %@", (unsigned long)logLevel, versionNextcloudiOS]];
  69. }
  70. //
  71. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(initializeMain:) name:k_notificationCenter_initializeMain object:nil];
  72. // Set account, if no exists clear all
  73. tableAccount *tableAccount = [[NCManageDatabase sharedInstance] getAccountActive];
  74. if (tableAccount == nil) {
  75. // remove all the keys Chain
  76. [CCUtility deleteAllChainStore];
  77. // remove all the App group key
  78. [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
  79. } else {
  80. // FIX 3.0.5 lost urlbase
  81. if (tableAccount.urlBase.length == 0) {
  82. NSString *user = [tableAccount.user stringByAppendingString:@" "];
  83. NSString *urlBase = [tableAccount.account stringByReplacingOccurrencesOfString:user withString:@""];
  84. tableAccount.urlBase = urlBase;
  85. [[NCManageDatabase sharedInstance] updateAccount:tableAccount];
  86. tableAccount = [[NCManageDatabase sharedInstance] getAccountActive];
  87. }
  88. [self settingAccount:tableAccount.account urlBase:tableAccount.urlBase user:tableAccount.user userID:tableAccount.userID password:[CCUtility getPassword:tableAccount.account]];
  89. }
  90. // UserDefaults
  91. self.ncUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:[NCBrandOptions sharedInstance].capabilitiesGroups];
  92. // Background Fetch
  93. [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
  94. self.listProgressMetadata = [NSMutableDictionary new];
  95. self.listFilesVC = [NSMutableDictionary new];
  96. self.listMainVC = [NSMutableDictionary new];
  97. self.listFavoriteVC = [NSMutableDictionary new];
  98. self.listOfflineVC = [NSMutableDictionary new];
  99. // Push Notification
  100. [application registerForRemoteNotifications];
  101. // Display notification
  102. [UNUserNotificationCenter currentNotificationCenter].delegate = self;
  103. UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
  104. [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) { }];
  105. //AV Session
  106. [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:nil];
  107. [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
  108. // ProgressView Detail
  109. self.progressViewDetail = [[UIProgressView alloc] initWithProgressViewStyle: UIProgressViewStyleBar];
  110. // Quick Actions
  111. if([[UIApplicationShortcutItem class] respondsToSelector:@selector(new)]) {
  112. [self configDynamicShortcutItems];
  113. UIApplicationShortcutItem *shortcutItem = [launchOptions objectForKeyedSubscript:UIApplicationLaunchOptionsShortcutItemKey];
  114. if (shortcutItem)
  115. [self handleShortCutItem:shortcutItem];
  116. }
  117. // Start Timer
  118. self.timerUpdateApplicationIconBadgeNumber = [NSTimer scheduledTimerWithTimeInterval:k_timerUpdateApplicationIconBadgeNumber target:self selector:@selector(updateApplicationIconBadgeNumber) userInfo:nil repeats:YES];
  119. [self startTimerErrorNetworking];
  120. // Store review
  121. if ([[NCUtility shared] isSimulatorOrTestFlight] == false) {
  122. NCStoreReview *review = [NCStoreReview new];
  123. [review incrementAppRuns];
  124. [review showStoreReview];
  125. }
  126. // Detect Dark mode
  127. if (@available(iOS 13.0, *)) {
  128. if ([CCUtility getDarkModeDetect]) {
  129. if ([[UITraitCollection currentTraitCollection] userInterfaceStyle] == UIUserInterfaceStyleDark) {
  130. [CCUtility setDarkMode:YES];
  131. } else {
  132. [CCUtility setDarkMode:NO];
  133. }
  134. }
  135. }
  136. //
  137. UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
  138. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  139. [self createTabBarController:tabBarController];
  140. }
  141. if ([NCBrandOptions sharedInstance].disable_intro) {
  142. [CCUtility setIntro:YES];
  143. if (self.account.length == 0) {
  144. [self openLoginView:nil selector:k_intro_login openLoginWeb:false];
  145. }
  146. } else {
  147. if ([CCUtility getIntro] == NO) {
  148. UIViewController *introViewController = [[UIStoryboard storyboardWithName:@"NCIntro" bundle:[NSBundle mainBundle]] instantiateInitialViewController];
  149. UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: introViewController];
  150. self.window.rootViewController = navController;
  151. [self.window makeKeyAndVisible];
  152. }
  153. }
  154. // init home
  155. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_initializeMain object:nil userInfo:nil];
  156. // Passcode
  157. dispatch_async(dispatch_get_main_queue(), ^{
  158. [self passcodeWithAutomaticallyPromptForBiometricValidation:true];
  159. });
  160. // Auto upload
  161. self.networkingAutoUpload = [NCNetworkingAutoUpload new];
  162. [[NCCommunicationCommon shared] writeLog:@"Application did finish launching"];
  163. return YES;
  164. }
  165. //
  166. // L' applicazione si dimetterà dallo stato di attivo
  167. //
  168. - (void)applicationWillResignActive:(UIApplication *)application
  169. {
  170. // Test Maintenance
  171. if (self.account.length == 0 || self.maintenanceMode)
  172. return;
  173. // Dismiss FileViewInFolder
  174. if (self.activeFileViewInFolder != nil ) {
  175. [self.activeFileViewInFolder dismissViewControllerAnimated:false completion:^{
  176. self.activeFileViewInFolder = nil;
  177. }];
  178. }
  179. [self updateApplicationIconBadgeNumber];
  180. }
  181. //
  182. // L' applicazione entrerà in primo piano (attivo solo dopo il background)
  183. //
  184. - (void)applicationWillEnterForeground:(UIApplication *)application
  185. {
  186. if (self.account.length == 0 || self.maintenanceMode) { return; }
  187. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_applicationWillEnterForeground object:nil];
  188. // Request Passcode
  189. [self passcodeWithAutomaticallyPromptForBiometricValidation:true];
  190. // Initialize Auto upload
  191. [[NCAutoUpload sharedInstance] initStateAutoUpload];
  192. // Read active directory
  193. [self.activeFiles reloadDataSourceNetworkWithForced:true];
  194. // Required unsubscribing / subscribing
  195. [self pushNotification];
  196. // RichDocument
  197. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_richdocumentGrabFocus object:nil];
  198. // Request Service Server Nextcloud
  199. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  200. [[NCService shared] startRequestServicesServer];
  201. });
  202. [[NCCommunicationCommon shared] writeLog:@"The application Will enter in foreground"];
  203. }
  204. //
  205. // L' applicazione entrerà in primo piano (attivo sempre)
  206. //
  207. - (void)applicationDidBecomeActive:(UIApplication *)application
  208. {
  209. if (self.account.length == 0 || self.maintenanceMode) { return; }
  210. // Brand
  211. #if defined(HC)
  212. tableAccount *account = [[NCManageDatabase sharedInstance] getAccountActive];
  213. if (account.hcIsTrial == true || account.hcTrialExpired == true || account.hcNextGroupExpirationGroupExpired == true) {
  214. HCTrial *vc = [[UIStoryboard storyboardWithName:@"HCTrial" bundle:nil] instantiateInitialViewController];
  215. vc.account = account;
  216. [self.window.rootViewController presentViewController:vc animated:YES completion:nil];
  217. }
  218. #endif
  219. [[NCNetworking shared] verifyUploadZombie];
  220. [[NCCommunicationCommon shared] writeLog:@"The application did become active"];
  221. }
  222. //
  223. // L' applicazione è entrata nello sfondo
  224. //
  225. - (void)applicationDidEnterBackground:(UIApplication *)application
  226. {
  227. if (self.account.length == 0 || self.maintenanceMode) { return; }
  228. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_applicationDidEnterBackground object:nil];
  229. [self passcodeWithAutomaticallyPromptForBiometricValidation:false];
  230. }
  231. //
  232. // L'applicazione terminerà
  233. //
  234. - (void)applicationWillTerminate:(UIApplication *)application
  235. {
  236. [[NCCommunicationCommon shared] writeLog:@"bye bye"];
  237. }
  238. // NotificationCenter
  239. - (void)initializeMain:(NSNotification *)notification
  240. {
  241. if (self.account.length == 0) return;
  242. // Clear error certificate
  243. [CCUtility setCertificateError:self.account error:NO];
  244. // Setting Theming
  245. [self settingThemingColorBrand];
  246. // If AVPlayer in play -> Stop
  247. if (self.player != nil && self.player.rate != 0) {
  248. [self.player pause];
  249. }
  250. // close detail
  251. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_menuDetailClose object:nil];
  252. // Not Photos Video in library ? then align and Init Auto Upload
  253. NSArray *recordsPhotoLibrary = [[NCManageDatabase sharedInstance] getPhotoLibraryWithPredicate:[NSPredicate predicateWithFormat:@"account == %@", self.account]];
  254. if ([recordsPhotoLibrary count] == 0) {
  255. [[NCAutoUpload sharedInstance] alignPhotoLibrary];
  256. }
  257. // Start Auto Upload
  258. [[NCAutoUpload sharedInstance] initStateAutoUpload];
  259. // Start services
  260. [[NCCommunicationCommon shared] writeLog:@"Request Service Server Nextcloud"];
  261. [[NCService shared] startRequestServicesServer];
  262. // Registeration push notification
  263. [self pushNotification];
  264. // Registeration domain File Provider
  265. FileProviderDomain *fileProviderDomain = [FileProviderDomain new];
  266. [fileProviderDomain removeAllDomains];
  267. //[fileProviderDomain registerDomains];
  268. [[NCCommunicationCommon shared] writeLog:@"initialize Main"];
  269. }
  270. #pragma --------------------------------------------------------------------------------------------
  271. #pragma mark ===== Login / checkErrorNetworking =====
  272. #pragma --------------------------------------------------------------------------------------------
  273. - (void)checkErrorNetworking
  274. {
  275. // test
  276. if (self.account.length == 0 || self.maintenanceMode)
  277. return;
  278. // check unauthorized server (401)
  279. if ([CCUtility getPassword:self.account].length == 0) {
  280. [self openLoginView:self.window.rootViewController selector:k_intro_login openLoginWeb:true];
  281. }
  282. // check certificate untrusted (-1202)
  283. if ([CCUtility getCertificateError:self.account]) {
  284. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_ssl_certificate_untrusted_", nil) message:NSLocalizedString(@"_connect_server_anyway_", nil) preferredStyle:UIAlertControllerStyleAlert];
  285. [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_yes_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
  286. [[NCNetworking shared] wrtiteCertificateWithDirectoryCertificate:[CCUtility getDirectoryCerificates]];
  287. [self startTimerErrorNetworking];
  288. }]];
  289. [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_no_", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
  290. [self startTimerErrorNetworking];
  291. }]];
  292. [self.window.rootViewController presentViewController:alertController animated:YES completion:^{
  293. // Stop timer error network
  294. [self.timerErrorNetworking invalidate];
  295. }];
  296. }
  297. }
  298. - (void)openLoginView:(UIViewController *)viewController selector:(NSInteger)selector openLoginWeb:(BOOL)openLoginWeb
  299. {
  300. // use appConfig [MDM]
  301. if ([NCBrandOptions sharedInstance].use_configuration) {
  302. if (!(_appConfigView.isViewLoaded && _appConfigView.view.window)) {
  303. self.appConfigView = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCAppConfigView"];
  304. [self showLoginViewController:self.appConfigView forContext:viewController];
  305. }
  306. return;
  307. }
  308. // only for personalized LoginWeb [customer]
  309. if ([NCBrandOptions sharedInstance].use_login_web_personalized) {
  310. if (!(_activeLoginWeb.isViewLoaded && _activeLoginWeb.view.window)) {
  311. self.activeLoginWeb = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCLoginWeb"];
  312. self.activeLoginWeb.urlBase = [[NCBrandOptions sharedInstance] loginBaseUrl];
  313. [self showLoginViewController:self.activeLoginWeb forContext:viewController];
  314. }
  315. return;
  316. }
  317. // normal login
  318. if (selector == k_intro_signup) {
  319. if (!(_activeLoginWeb.isViewLoaded && _activeLoginWeb.view.window)) {
  320. self.activeLoginWeb = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCLoginWeb"];
  321. if (selector == k_intro_signup) {
  322. self.activeLoginWeb.urlBase = [[NCBrandOptions sharedInstance] linkloginPreferredProviders];
  323. } else {
  324. self.activeLoginWeb.urlBase = self.urlBase;
  325. }
  326. [self showLoginViewController:self.activeLoginWeb forContext:viewController];
  327. }
  328. } else if ([NCBrandOptions sharedInstance].disable_intro && [NCBrandOptions sharedInstance].disable_request_login_url) {
  329. self.activeLoginWeb = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCLoginWeb"];
  330. self.activeLoginWeb.urlBase = [[NCBrandOptions sharedInstance] loginBaseUrl];
  331. [self showLoginViewController:self.activeLoginWeb forContext:viewController];
  332. } else if (openLoginWeb) {
  333. if (!(_activeLoginWeb.isViewLoaded && _activeLoginWeb.view.window)) {
  334. self.activeLoginWeb = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCLoginWeb"];
  335. self.activeLoginWeb.urlBase = self.urlBase;
  336. [self showLoginViewController:self.activeLoginWeb forContext:viewController];
  337. }
  338. } else {
  339. if (!(_activeLogin.isViewLoaded && _activeLogin.view.window)) {
  340. _activeLogin = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"CCLoginNextcloud"];
  341. [self showLoginViewController:_activeLogin forContext:viewController];
  342. }
  343. }
  344. }
  345. -(void)showLoginViewController:(UIViewController *)viewController forContext:(UIViewController *)contextViewController
  346. {
  347. if (contextViewController == NULL) {
  348. UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
  349. navController.navigationBar.barStyle = UIBarStyleBlack;
  350. navController.navigationBar.tintColor = NCBrandColor.sharedInstance.customerText;
  351. navController.navigationBar.barTintColor = NCBrandColor.sharedInstance.customer;
  352. [navController.navigationBar setTranslucent:false];
  353. self.window.rootViewController = navController;
  354. [self.window makeKeyAndVisible];
  355. } else if ([contextViewController isKindOfClass:[UINavigationController class]]) {
  356. UINavigationController *navController = ((UINavigationController *)contextViewController);
  357. [navController pushViewController:viewController animated:true];
  358. } else {
  359. UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
  360. navController.modalPresentationStyle = UIModalPresentationFullScreen;
  361. navController.navigationBar.barStyle = UIBarStyleBlack;
  362. navController.navigationBar.tintColor = NCBrandColor.sharedInstance.customerText;
  363. navController.navigationBar.barTintColor = NCBrandColor.sharedInstance.customer;
  364. [navController.navigationBar setTranslucent:false];
  365. [contextViewController presentViewController:navController animated:true completion:nil];
  366. }
  367. }
  368. - (void)startTimerErrorNetworking
  369. {
  370. self.timerErrorNetworking = [NSTimer scheduledTimerWithTimeInterval:k_timerErrorNetworking target:self selector:@selector(checkErrorNetworking) userInfo:nil repeats:YES];
  371. }
  372. #pragma --------------------------------------------------------------------------------------------
  373. #pragma mark ===== Account & Communication =====
  374. #pragma --------------------------------------------------------------------------------------------
  375. - (void)settingAccount:(NSString *)account urlBase:(NSString *)urlBase user:(NSString *)user userID:(NSString *)userID password:(NSString *)password
  376. {
  377. self.account = account;
  378. self.urlBase = urlBase;
  379. self.user = user;
  380. self.userID = userID;
  381. self.password = password;
  382. (void)[NCNetworkingNotificationCenter shared];
  383. [[NCCommunicationCommon shared] setupWithAccount:account user:user userId:userID password:password urlBase:urlBase];
  384. [self settingSetupCommunication:account];
  385. }
  386. - (void)deleteAccount:(NSString *)account wipe:(BOOL)wipe
  387. {
  388. // Push Notification
  389. tableAccount *accountPN = [[NCManageDatabase sharedInstance] getAccountWithPredicate:[NSPredicate predicateWithFormat:@"account == %@", account]];
  390. [self unsubscribingNextcloudServerPushNotification:accountPN.account urlBase:accountPN.urlBase user:accountPN.user withSubscribing:false];
  391. [self settingAccount:nil urlBase:nil user:nil userID:nil password:nil];
  392. /* DELETE ALL FILES LOCAL FS */
  393. NSArray *results = [[NCManageDatabase sharedInstance] getTableLocalFilesWithPredicate:[NSPredicate predicateWithFormat:@"account == %@", account] sorted:@"ocId" ascending:NO];
  394. for (tableLocalFile *result in results) {
  395. [CCUtility removeFileAtPath:[CCUtility getDirectoryProviderStorageOcId:result.ocId]];
  396. }
  397. // Clear database
  398. [[NCManageDatabase sharedInstance] clearDatabaseWithAccount:account removeAccount:true];
  399. [CCUtility clearAllKeysEndToEnd:account];
  400. [CCUtility clearAllKeysPushNotification:account];
  401. [CCUtility setCertificateError:account error:false];
  402. [CCUtility setPassword:account password:nil];
  403. if (wipe) {
  404. NSArray *listAccount = [[NCManageDatabase sharedInstance] getAccounts];
  405. if ([listAccount count] > 0) {
  406. NSString *newAccount = listAccount[0];
  407. tableAccount *tableAccount = [[NCManageDatabase sharedInstance] setAccountActive:newAccount];
  408. [self settingAccount:newAccount urlBase:tableAccount.urlBase user:tableAccount.user userID:tableAccount.userID password:[CCUtility getPassword:tableAccount.account]];
  409. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_initializeMain object:nil userInfo:nil];
  410. } else {
  411. [self openLoginView:self.window.rootViewController selector:k_intro_login openLoginWeb:false];
  412. }
  413. }
  414. }
  415. - (void)settingSetupCommunication:(NSString *)account
  416. {
  417. NSInteger serverVersionMajor = [[NCManageDatabase sharedInstance] getCapabilitiesServerIntWithAccount:account elements:NCElementsJSON.shared.capabilitiesVersionMajor];
  418. if (serverVersionMajor > 0) {
  419. [[NCCommunicationCommon shared] setupWithNextcloudVersion:serverVersionMajor];
  420. }
  421. [[NCCommunicationCommon shared] setupWithWebDav:[[NCUtility shared] getWebDAVWithAccount:account]];
  422. [[NCCommunicationCommon shared] setupWithDav:[[NCUtility shared] getDAV]];
  423. }
  424. #pragma --------------------------------------------------------------------------------------------
  425. #pragma mark ===== Push Notifications =====
  426. #pragma --------------------------------------------------------------------------------------------
  427. - (void)pushNotification
  428. {
  429. // test
  430. if (self.account.length == 0 || self.maintenanceMode || self.pushKitToken.length == 0)
  431. return;
  432. for (tableAccount *result in [[NCManageDatabase sharedInstance] getAllAccount]) {
  433. NSString *token = [CCUtility getPushNotificationToken:result.account];
  434. if (![token isEqualToString:self.pushKitToken]) {
  435. if (token != nil) {
  436. // unsubscribing + subscribing
  437. [self unsubscribingNextcloudServerPushNotification:result.account urlBase:result.urlBase user:result.user withSubscribing:true];
  438. } else {
  439. [self subscribingNextcloudServerPushNotification:result.account urlBase:result.urlBase user:result.user];
  440. }
  441. }
  442. }
  443. }
  444. - (void)subscribingNextcloudServerPushNotification:(NSString *)account urlBase:(NSString *)urlBase user:(NSString *)user
  445. {
  446. // test
  447. if (self.account.length == 0 || self.maintenanceMode || self.pushKitToken.length == 0)
  448. return;
  449. [[NCPushNotificationEncryption sharedInstance] generatePushNotificationsKeyPair:account];
  450. NSString *pushTokenHash = [[NCEndToEndEncryption sharedManager] createSHA512:self.pushKitToken];
  451. NSData *pushPublicKey = [CCUtility getPushNotificationPublicKey:account];
  452. NSString *pushDevicePublicKey = [[NSString alloc] initWithData:pushPublicKey encoding:NSUTF8StringEncoding];
  453. NSString *proxyServerPath = [NCBrandOptions sharedInstance].pushNotificationServerProxy;
  454. [[NCCommunication shared] subscribingPushNotificationWithServerUrl:urlBase account:account user:user password:[CCUtility getPassword:account] pushTokenHash:pushTokenHash devicePublicKey:pushDevicePublicKey proxyServerUrl:proxyServerPath customUserAgent:nil addCustomHeaders:nil completionHandler:^(NSString *account, NSString *deviceIdentifier, NSString *signature, NSString *publicKey, NSInteger errorCode, NSString *errorDescription) {
  455. if (errorCode == 0) {
  456. NSString *userAgent = [NSString stringWithFormat:@"%@ (Strict VoIP)", [CCUtility getUserAgent]];
  457. [[NCCommunication shared] subscribingPushProxyWithProxyServerUrl:proxyServerPath pushToken:self.pushKitToken deviceIdentifier:deviceIdentifier signature:signature publicKey:publicKey userAgent:userAgent completionHandler:^(NSInteger errorCode, NSString *errorDescription) {
  458. if (errorCode == 0) {
  459. [[NCCommunicationCommon shared] writeLog:@"Subscribed to Push Notification server & proxy successfully"];
  460. [CCUtility setPushNotificationToken:account token:self.pushKitToken];
  461. [CCUtility setPushNotificationDeviceIdentifier:account deviceIdentifier:deviceIdentifier];
  462. [CCUtility setPushNotificationDeviceIdentifierSignature:account deviceIdentifierSignature:signature];
  463. [CCUtility setPushNotificationSubscribingPublicKey:account publicKey:publicKey];
  464. }
  465. }];
  466. }
  467. }];
  468. }
  469. - (void)unsubscribingNextcloudServerPushNotification:(NSString *)account urlBase:(NSString *)urlBase user:(NSString *)user withSubscribing:(BOOL)subscribing
  470. {
  471. // test
  472. if (self.account.length == 0 || self.maintenanceMode)
  473. return;
  474. NSString *deviceIdentifier = [CCUtility getPushNotificationDeviceIdentifier:account];
  475. NSString *signature = [CCUtility getPushNotificationDeviceIdentifierSignature:account];
  476. NSString *publicKey = [CCUtility getPushNotificationSubscribingPublicKey:account];
  477. [[NCCommunication shared] unsubscribingPushNotificationWithServerUrl:urlBase account:account user:user password:[CCUtility getPassword:account] customUserAgent:nil addCustomHeaders:nil completionHandler:^(NSString *account, NSInteger errorCode, NSString *errorDescription) {
  478. if (errorCode == 0) {
  479. NSString *userAgent = [NSString stringWithFormat:@"%@ (Strict VoIP)", [CCUtility getUserAgent]];
  480. NSString *proxyServerPath = [NCBrandOptions sharedInstance].pushNotificationServerProxy;
  481. [[NCCommunication shared] unsubscribingPushProxyWithProxyServerUrl:proxyServerPath deviceIdentifier:deviceIdentifier signature:signature publicKey:publicKey userAgent:userAgent completionHandler:^(NSInteger errorCode, NSString *errorDescription) {
  482. if (errorCode == 0) {
  483. [[NCCommunicationCommon shared] writeLog:@"Unsubscribed to Push Notification server & proxy successfully."];
  484. [CCUtility setPushNotificationPublicKey:account data:nil];
  485. [CCUtility setPushNotificationSubscribingPublicKey:account publicKey:nil];
  486. [CCUtility setPushNotificationPrivateKey:account data:nil];
  487. [CCUtility setPushNotificationToken:account token:nil];
  488. [CCUtility setPushNotificationDeviceIdentifier:account deviceIdentifier:nil];
  489. [CCUtility setPushNotificationDeviceIdentifierSignature:account deviceIdentifierSignature:nil];
  490. if (self.pushKitToken != nil && subscribing) {
  491. [self subscribingNextcloudServerPushNotification:account urlBase:urlBase user:user];
  492. }
  493. }
  494. }];
  495. }
  496. }];
  497. }
  498. -(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
  499. {
  500. //Called when a notification is delivered to a foreground app.
  501. completionHandler(UNNotificationPresentationOptionAlert);
  502. }
  503. -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(nonnull UNNotificationResponse *)response withCompletionHandler:(nonnull void (^)(void))completionHandler
  504. {
  505. completionHandler();
  506. }
  507. - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
  508. {
  509. self.pushKitToken = [self stringWithDeviceToken:deviceToken];
  510. [self pushNotification];
  511. }
  512. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
  513. {
  514. NSString *message = [userInfo objectForKey:@"subject"];
  515. if (message) {
  516. NSArray *results = [[NCManageDatabase sharedInstance] getAllAccount];
  517. for (tableAccount *result in results) {
  518. if ([CCUtility getPushNotificationPrivateKey:result.account]) {
  519. NSData *decryptionKey = [CCUtility getPushNotificationPrivateKey:result.account];
  520. NSString *decryptedMessage = [[NCPushNotificationEncryption sharedInstance] decryptPushNotification:message withDevicePrivateKey:decryptionKey];
  521. if (decryptedMessage) {
  522. NSData *data = [decryptedMessage dataUsingEncoding:NSUTF8StringEncoding];
  523. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  524. NSInteger nid = [[json objectForKey:@"nid"] integerValue];
  525. BOOL delete = [[json objectForKey:@"delete"] boolValue];
  526. BOOL deleteAll = [[json objectForKey:@"delete-all"] boolValue];
  527. if (delete) {
  528. [self removeNotificationWithNotificationId:nid usingDecryptionKey:decryptionKey];
  529. } else if (deleteAll) {
  530. [self cleanAllNotifications];
  531. }
  532. }
  533. }
  534. }
  535. }
  536. completionHandler(UIBackgroundFetchResultNoData);
  537. }
  538. - (void)cleanAllNotifications
  539. {
  540. [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
  541. }
  542. - (void)removeNotificationWithNotificationId:(NSInteger)notificationId usingDecryptionKey:(NSData *)key
  543. {
  544. // Check in pending notifications
  545. [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) {
  546. for (UNNotificationRequest *notificationRequest in requests) {
  547. NSString *message = [notificationRequest.content.userInfo objectForKey:@"subject"];
  548. NSString *decryptedMessage = [[NCPushNotificationEncryption sharedInstance] decryptPushNotification:message withDevicePrivateKey:key];
  549. if (decryptedMessage) {
  550. NSData *data = [decryptedMessage dataUsingEncoding:NSUTF8StringEncoding];
  551. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  552. NSInteger nid = [[json objectForKey:@"nid"] integerValue];
  553. if (nid == notificationId) {
  554. [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[notificationRequest.identifier]];
  555. }
  556. }
  557. }
  558. }];
  559. // Check in delivered notifications
  560. [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
  561. for (UNNotification *notification in notifications) {
  562. NSString *message = [notification.request.content.userInfo objectForKey:@"subject"];
  563. NSString *decryptedMessage = [[NCPushNotificationEncryption sharedInstance] decryptPushNotification:message withDevicePrivateKey:key];
  564. if (decryptedMessage) {
  565. NSData *data = [decryptedMessage dataUsingEncoding:NSUTF8StringEncoding];
  566. NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  567. NSInteger nid = [[json objectForKey:@"nid"] integerValue];
  568. if (nid == notificationId) {
  569. [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:@[notification.request.identifier]];
  570. }
  571. }
  572. }
  573. }];
  574. }
  575. - (NSString *)stringWithDeviceToken:(NSData *)deviceToken
  576. {
  577. const char *data = [deviceToken bytes];
  578. NSMutableString *token = [NSMutableString string];
  579. for (NSUInteger i = 0; i < [deviceToken length]; i++) {
  580. [token appendFormat:@"%02.2hhX", data[i]];
  581. }
  582. return [token copy];
  583. }
  584. #pragma --------------------------------------------------------------------------------------------
  585. #pragma mark ===== Quick Actions - ShotcutItem =====
  586. #pragma --------------------------------------------------------------------------------------------
  587. - (void)configDynamicShortcutItems
  588. {
  589. NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
  590. UIApplicationShortcutIcon *shortcutMediaIcon = [UIApplicationShortcutIcon iconWithTemplateImageName:@"media"];
  591. UIApplicationShortcutItem *shortcutMedia = [[UIApplicationShortcutItem alloc] initWithType:[NSString stringWithFormat:@"%@.media", bundleId] localizedTitle:NSLocalizedString(@"_media_", nil) localizedSubtitle:nil icon:shortcutMediaIcon userInfo:nil];
  592. // add the array to our app
  593. if (shortcutMedia)
  594. [UIApplication sharedApplication].shortcutItems = @[shortcutMedia];
  595. }
  596. - (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler
  597. {
  598. BOOL handledShortCutItem = [self handleShortCutItem:shortcutItem];
  599. completionHandler(handledShortCutItem);
  600. }
  601. - (BOOL)handleShortCutItem:(UIApplicationShortcutItem *)shortcutItem
  602. {
  603. BOOL handled = NO;
  604. NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
  605. NSString *shortcutMedia = [NSString stringWithFormat:@"%@.media", bundleId];
  606. if ([shortcutItem.type isEqualToString:shortcutMedia] && self.account) {
  607. dispatch_async(dispatch_get_main_queue(), ^{
  608. UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
  609. if ([splitViewController isKindOfClass:[UISplitViewController class]]) {
  610. UINavigationController *navigationControllerMaster = (UINavigationController *)splitViewController.viewControllers.firstObject;
  611. if ([navigationControllerMaster isKindOfClass:[UINavigationController class]]) {
  612. UITabBarController *tabBarController = (UITabBarController *)navigationControllerMaster.topViewController;
  613. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  614. if (splitViewController.isCollapsed) {
  615. [navigationControllerMaster popToRootViewControllerAnimated:false];
  616. UINavigationController *navigationControllerMaster = (UINavigationController *)splitViewController.viewControllers.firstObject;
  617. if ([navigationControllerMaster isKindOfClass:[UINavigationController class]]) {
  618. UITabBarController *tabBarController = (UITabBarController *)navigationControllerMaster.topViewController;
  619. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  620. [tabBarController setSelectedIndex: k_tabBarApplicationIndexMedia];
  621. }
  622. }
  623. } else {
  624. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  625. [tabBarController setSelectedIndex: k_tabBarApplicationIndexMedia];
  626. }
  627. }
  628. }
  629. }
  630. }
  631. });
  632. handled = YES;
  633. }
  634. return handled;
  635. }
  636. #pragma --------------------------------------------------------------------------------------------
  637. #pragma mark ===== ApplicationIconBadgeNumber =====
  638. #pragma --------------------------------------------------------------------------------------------
  639. - (void)updateApplicationIconBadgeNumber
  640. {
  641. if (self.account.length == 0 || self.maintenanceMode) return;
  642. NSInteger counterDownload = [[NCOperationQueue shared] downloadCount];
  643. NSInteger counterUpload = [[NCManageDatabase sharedInstance] getMetadatasWithPredicate:[NSPredicate predicateWithFormat:@"status == %d OR status == %d OR status == %d", k_metadataStatusWaitUpload, k_metadataStatusInUpload, k_metadataStatusUploading]].count;
  644. NSInteger total = counterDownload + counterUpload;
  645. [UIApplication sharedApplication].applicationIconBadgeNumber = total;
  646. UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
  647. if ([splitViewController isKindOfClass:[UISplitViewController class]]) {
  648. UINavigationController *navigationController = (UINavigationController *)[splitViewController.viewControllers firstObject];
  649. if ([navigationController isKindOfClass:[UINavigationController class]]) {
  650. UITabBarController *tabBarController = (UITabBarController *)navigationController.topViewController;
  651. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  652. UITabBarItem *tabBarItem = [tabBarController.tabBar.items objectAtIndex:0];
  653. if (total > 0) {
  654. [tabBarItem setBadgeValue:[NSString stringWithFormat:@"%li", (unsigned long)total]];
  655. } else {
  656. [tabBarItem setBadgeValue:nil];
  657. }
  658. }
  659. }
  660. }
  661. }
  662. #pragma --------------------------------------------------------------------------------------------
  663. #pragma mark ===== TabBarController =====
  664. #pragma --------------------------------------------------------------------------------------------
  665. - (void)createTabBarController:(UITabBarController *)tabBarController
  666. {
  667. UITabBarItem *item;
  668. NSLayoutConstraint *constraint;
  669. CGFloat safeAreaBottom = safeAreaBottom = [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom;
  670. // File
  671. item = [tabBarController.tabBar.items objectAtIndex: k_tabBarApplicationIndexFile];
  672. [item setTitle:NSLocalizedString(@"_home_", nil)];
  673. item.image = [CCGraphics changeThemingColorImage:[UIImage imageNamed:@"tabBarFiles"] width:50 height:50 color:NCBrandColor.sharedInstance.brandElement];
  674. item.selectedImage = item.image;
  675. // Favorites
  676. item = [tabBarController.tabBar.items objectAtIndex: k_tabBarApplicationIndexFavorite];
  677. [item setTitle:NSLocalizedString(@"_favorites_", nil)];
  678. item.image = [CCGraphics changeThemingColorImage:[UIImage imageNamed:@"favorite"] width:50 height:50 color:NCBrandColor.sharedInstance.brandElement];
  679. item.selectedImage = item.image;
  680. // (PLUS INVISIBLE)
  681. item = [tabBarController.tabBar.items objectAtIndex: k_tabBarApplicationIndexPlusHide];
  682. item.title = @"";
  683. item.image = nil;
  684. item.enabled = false;
  685. // Media
  686. item = [tabBarController.tabBar.items objectAtIndex: k_tabBarApplicationIndexMedia];
  687. [item setTitle:NSLocalizedString(@"_media_", nil)];
  688. item.image = [CCGraphics changeThemingColorImage:[UIImage imageNamed:@"media"] width:50 height:50 color:NCBrandColor.sharedInstance.brandElement];
  689. item.selectedImage = item.image;
  690. // More
  691. item = [tabBarController.tabBar.items objectAtIndex: k_tabBarApplicationIndexMore];
  692. [item setTitle:NSLocalizedString(@"_more_", nil)];
  693. item.image = [CCGraphics changeThemingColorImage:[UIImage imageNamed:@"tabBarMore"] width:50 height:50 color:NCBrandColor.sharedInstance.brandElement];
  694. item.selectedImage = item.image;
  695. // Plus Button
  696. int buttonSize = 57;
  697. UIImage *buttonImage = [CCGraphics changeThemingColorImage:[UIImage imageNamed:@"tabBarPlus"] width:120 height:120 color:UIColor.whiteColor];
  698. UIButton *buttonPlus = [UIButton buttonWithType:UIButtonTypeCustom];
  699. buttonPlus.tag = 99;
  700. buttonPlus.accessibilityLabel = NSLocalizedString(@"_accessibility_add_upload_", nil);
  701. [buttonPlus setImage:buttonImage forState:UIControlStateNormal];
  702. buttonPlus.backgroundColor = NCBrandColor.sharedInstance.brandElement;
  703. buttonPlus.layer.cornerRadius = buttonSize / 2;
  704. buttonPlus.layer.masksToBounds = NO;
  705. buttonPlus.layer.shadowOffset = CGSizeMake(0, 0);
  706. buttonPlus.layer.shadowRadius = 3.0f;
  707. buttonPlus.layer.shadowOpacity = 0.5;
  708. [buttonPlus addTarget:self action:@selector(handleTouchTabbarCenter:) forControlEvents:UIControlEventTouchUpInside];
  709. [buttonPlus setTranslatesAutoresizingMaskIntoConstraints:NO];
  710. [tabBarController.tabBar addSubview:buttonPlus];
  711. if (safeAreaBottom > 0) {
  712. // X
  713. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:tabBarController.tabBar attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
  714. [tabBarController.view addConstraint:constraint];
  715. // Y
  716. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:tabBarController.tabBar attribute:NSLayoutAttributeTop multiplier:1.0 constant:-(buttonSize / 2)];
  717. [tabBarController.view addConstraint:constraint];
  718. // Width
  719. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:buttonSize];
  720. [tabBarController.view addConstraint:constraint];
  721. // Height
  722. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:buttonSize];
  723. [tabBarController.view addConstraint:constraint];
  724. } else {
  725. // X
  726. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:tabBarController.tabBar attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
  727. [tabBarController.view addConstraint:constraint];
  728. // Y
  729. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:tabBarController.tabBar attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:-(buttonSize / 2)];
  730. [tabBarController.view addConstraint:constraint];
  731. // Width
  732. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:buttonSize];
  733. [tabBarController.view addConstraint:constraint];
  734. // Height
  735. constraint = [NSLayoutConstraint constraintWithItem:buttonPlus attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:buttonSize];
  736. [tabBarController.view addConstraint:constraint];
  737. }
  738. }
  739. - (void)handleTouchTabbarCenter:(id)sender
  740. {
  741. // Test Maintenance
  742. if (self.maintenanceMode)
  743. return;
  744. tableDirectory *tableDirectory = [[NCManageDatabase sharedInstance] getTableDirectoryWithPredicate:[NSPredicate predicateWithFormat:@"account == %@ AND serverUrl == %@", self.account, self.activeServerUrl]];
  745. if ([tableDirectory.permissions containsString:@"CK"]) {
  746. [self showMenuInViewController:self.window.rootViewController];
  747. } else {
  748. [[NCContentPresenter shared] messageNotification:@"_warning_" description:@"_no_permission_add_file_" delay:k_dismissAfterSecond type:messageTypeInfo errorCode:k_CCErrorInternalError forced:false];
  749. }
  750. }
  751. #pragma --------------------------------------------------------------------------------------------
  752. #pragma mark ===== Theming Color =====
  753. #pragma --------------------------------------------------------------------------------------------
  754. - (void)settingThemingColorBrand
  755. {
  756. if (self.account.length == 0 || self.maintenanceMode)
  757. return;
  758. if ([NCBrandOptions sharedInstance].use_themingColor) {
  759. NSString *themingColor = [[NCManageDatabase sharedInstance] getCapabilitiesServerStringWithAccount:self.account elements:NCElementsJSON.shared.capabilitiesThemingColor];
  760. NSString *themingColorElement = [[NCManageDatabase sharedInstance] getCapabilitiesServerStringWithAccount:self.account elements:NCElementsJSON.shared.capabilitiesThemingColorElement];
  761. NSString *themingColorText = [[NCManageDatabase sharedInstance] getCapabilitiesServerStringWithAccount:self.account elements:NCElementsJSON.shared.capabilitiesThemingColorText];
  762. [CCGraphics settingThemingColor:themingColor themingColorElement:themingColorElement themingColorText:themingColorText];
  763. BOOL isTooLight = NCBrandColor.sharedInstance.brandElement.isTooLight;
  764. BOOL isTooDark = NCBrandColor.sharedInstance.brandElement.isTooDark;
  765. if (isTooLight) {
  766. NCBrandColor.sharedInstance.brandElement = [NCBrandColor.sharedInstance.brandElement darkerBy:10];
  767. } else if (isTooDark) {
  768. NCBrandColor.sharedInstance.brandElement = [NCBrandColor.sharedInstance.brandElement lighterBy:40];
  769. }
  770. } else {
  771. BOOL isTooLight = NCBrandColor.sharedInstance.customer.isTooLight;
  772. BOOL isTooDark = NCBrandColor.sharedInstance.customer.isTooDark;
  773. if (isTooLight) {
  774. NCBrandColor.sharedInstance.brandElement = [NCBrandColor.sharedInstance.customer darkerBy:10];
  775. } else if (isTooDark) {
  776. NCBrandColor.sharedInstance.brandElement = [NCBrandColor.sharedInstance.customer lighterBy:40];
  777. } else {
  778. NCBrandColor.sharedInstance.brandElement = NCBrandColor.sharedInstance.customer;
  779. }
  780. NCBrandColor.sharedInstance.brand = NCBrandColor.sharedInstance.customer;
  781. NCBrandColor.sharedInstance.brandText = NCBrandColor.sharedInstance.customerText;
  782. }
  783. [NCBrandColor.sharedInstance setDarkMode];
  784. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  785. [[NCCollectionCommon shared] createImagesThemingColor];
  786. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_changeTheming object:nil];
  787. });
  788. }
  789. - (void)changeTheming:(UIViewController *)viewController tableView:(UITableView *)tableView collectionView:(UICollectionView *)collectionView form:(BOOL)form
  790. {
  791. [NCBrandColor.sharedInstance setDarkMode];
  792. [self.window setTintColor:NCBrandColor.sharedInstance.textView];
  793. //Tab bar
  794. UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
  795. if ([tabBarController isKindOfClass:[UITabBarController class]]) {
  796. tabBarController.tabBar.barTintColor = NCBrandColor.sharedInstance.backgroundView;
  797. tabBarController.tabBar.backgroundColor = NCBrandColor.sharedInstance.tabBar;
  798. tabBarController.tabBar.tintColor = NCBrandColor.sharedInstance.brandElement;
  799. [tabBarController.tabBar viewWithTag:99].backgroundColor = NCBrandColor.sharedInstance.brandElement;
  800. }
  801. // Nav bar
  802. [self configureNavBarForViewController:viewController];
  803. // View
  804. if (form) viewController.view.backgroundColor = NCBrandColor.sharedInstance.backgroundForm;
  805. else viewController.view.backgroundColor = NCBrandColor.sharedInstance.backgroundView;
  806. // TableView
  807. if (tableView) {
  808. if (form) tableView.backgroundColor = NCBrandColor.sharedInstance.backgroundForm;
  809. else tableView.backgroundColor = NCBrandColor.sharedInstance.backgroundView;
  810. tableView.separatorColor = NCBrandColor.sharedInstance.separator;
  811. [tableView reloadData];
  812. }
  813. // CollectionView
  814. if (collectionView) {
  815. if (form) collectionView.backgroundColor = NCBrandColor.sharedInstance.backgroundForm;
  816. else collectionView.backgroundColor = NCBrandColor.sharedInstance.backgroundView;
  817. [collectionView reloadData];
  818. }
  819. }
  820. #pragma --------------------------------------------------------------------------------------------
  821. #pragma mark ===== Fetch =====
  822. #pragma --------------------------------------------------------------------------------------------
  823. - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
  824. {
  825. // Test Maintenance
  826. if (self.account.length == 0 || self.maintenanceMode) {
  827. completionHandler(UIBackgroundFetchResultNoData);
  828. return;
  829. }
  830. [[NCCommunicationCommon shared] writeLog:@"Start perform Fetch With Completion Handler"];
  831. // Verify new photo
  832. [[NCAutoUpload sharedInstance] initStateAutoUpload];
  833. // after 20 sec
  834. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
  835. [[NCCommunicationCommon shared] writeLog:@"End 20 sec. perform Fetch With Completion Handler"];
  836. completionHandler(UIBackgroundFetchResultNoData);
  837. });
  838. }
  839. #pragma --------------------------------------------------------------------------------------------
  840. #pragma mark ===== Operation Networking & Session =====
  841. #pragma --------------------------------------------------------------------------------------------
  842. //
  843. // Method called by the system when all the background task has end
  844. //
  845. - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler
  846. {
  847. [[NCCommunicationCommon shared] writeLog:[NSString stringWithFormat:@"Start handle Events For Background URLSession: %@", identifier]];
  848. [self updateApplicationIconBadgeNumber];
  849. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
  850. self.backgroundSessionCompletionHandler = completionHandler;
  851. void (^completionHandler)() = self.backgroundSessionCompletionHandler;
  852. self.backgroundSessionCompletionHandler = nil;
  853. completionHandler();
  854. });
  855. }
  856. #pragma --------------------------------------------------------------------------------------------
  857. #pragma mark ===== OpenURL =====
  858. #pragma --------------------------------------------------------------------------------------------
  859. // Method called from iOS system to send a file from other app.
  860. - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options
  861. {
  862. if (self.account.length == 0 || self.maintenanceMode)
  863. return YES;
  864. NSString *scheme = url.scheme;
  865. NSString *fileName;
  866. NSString *serverUrl;
  867. if ([scheme isEqualToString:@"nextcloud"]) {
  868. NSString *action = url.host;
  869. if ([action isEqualToString:@"open-file"]) {
  870. NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
  871. NSArray *queryItems = urlComponents.queryItems;
  872. NSString *user = [CCUtility valueForKey:@"user" fromQueryItems:queryItems];
  873. NSString *path = [CCUtility valueForKey:@"path" fromQueryItems:queryItems];
  874. NSString *link = [CCUtility valueForKey:@"link" fromQueryItems:queryItems];
  875. tableAccount *matchedAccount = nil;
  876. // verify parameter
  877. if (user.length == 0 || path.length == 0 || [[NSURL URLWithString:link] host].length == 0) {
  878. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_error_", nil) message:NSLocalizedString(@"_error_parameter_schema_", nil) preferredStyle:UIAlertControllerStyleAlert];
  879. UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"_ok_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}];
  880. [alertController addAction:okAction];
  881. [self.window.rootViewController presentViewController:alertController animated:YES completion:nil];
  882. } else {
  883. tableAccount *account = [[NCManageDatabase sharedInstance] getAccountActive];
  884. if (account) {
  885. NSURL *accountURL = [NSURL URLWithString:account.urlBase];
  886. NSString *accountUser = account.user;
  887. if ([link containsString:accountURL.host] && [user isEqualToString:accountUser]) {
  888. matchedAccount = account;
  889. } else {
  890. NSArray *accounts = [[NCManageDatabase sharedInstance] getAllAccount];
  891. for (tableAccount *account in accounts) {
  892. NSURL *accountURL = [NSURL URLWithString:account.urlBase];
  893. NSString *accountUser = account.user;
  894. if ([link containsString:accountURL.host] && [user isEqualToString:accountUser]) {
  895. matchedAccount = [[NCManageDatabase sharedInstance] setAccountActive:account.account];
  896. [self settingAccount:matchedAccount.account urlBase:matchedAccount.urlBase user:matchedAccount.user userID:matchedAccount.userID password:[CCUtility getPassword:matchedAccount.account]];
  897. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:k_notificationCenter_initializeMain object:nil userInfo:nil];
  898. }
  899. }
  900. }
  901. if (matchedAccount) {
  902. NSString *webDAV = [[NCUtility shared] getWebDAVWithAccount:self.account];
  903. if ([path containsString:@"/"]) {
  904. fileName = [path lastPathComponent];
  905. serverUrl = [NSString stringWithFormat:@"%@/%@/%@", matchedAccount.urlBase, webDAV, [path stringByDeletingLastPathComponent]];
  906. } else {
  907. fileName = path;
  908. serverUrl = [NSString stringWithFormat:@"%@/%@", matchedAccount.urlBase, webDAV];
  909. }
  910. [[NCCollectionCommon shared] openFileViewInFolderWithServerUrl:serverUrl fileName:fileName];
  911. } else {
  912. NSString *domain = [[NSURL URLWithString:link] host];
  913. NSString *fileName = [path lastPathComponent];
  914. NSString *message = [NSString stringWithFormat:NSLocalizedString(@"_account_not_available_", nil), user, domain, fileName];
  915. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_info_", nil) message:message preferredStyle:UIAlertControllerStyleAlert];
  916. UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"_ok_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}];
  917. [alertController addAction:okAction];
  918. [self.window.rootViewController presentViewController:alertController animated:YES completion:nil];
  919. }
  920. }
  921. }
  922. }
  923. return YES;
  924. }
  925. NSError *error;
  926. NSLog(@"[LOG] the path is: %@", url.path);
  927. NSArray *splitedUrl = [url.path componentsSeparatedByString:@"/"];
  928. self.fileNameUpload = [NSString stringWithFormat:@"%@",[splitedUrl objectAtIndex:([splitedUrl count]-1)]];
  929. if (self.account) {
  930. [[NSFileManager defaultManager]removeItemAtPath:[NSTemporaryDirectory() stringByAppendingString:self.fileNameUpload] error:nil];
  931. [[NSFileManager defaultManager]moveItemAtPath:url.path toPath:[NSTemporaryDirectory() stringByAppendingString:self.fileNameUpload] error:&error];
  932. if (error == nil) {
  933. UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
  934. if ([splitViewController isKindOfClass:[UISplitViewController class]]) {
  935. UINavigationController *navigationControllerMaster = (UINavigationController *)splitViewController.viewControllers.firstObject;
  936. if ([navigationControllerMaster isKindOfClass:[UINavigationController class]]) {
  937. UIViewController *uploadNavigationViewController = [[UIStoryboard storyboardWithName:@"CCUploadFromOtherUpp" bundle:nil] instantiateViewControllerWithIdentifier:@"CCUploadNavigationViewController"];
  938. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
  939. [navigationControllerMaster presentViewController:uploadNavigationViewController animated:YES completion:nil];
  940. });
  941. }
  942. }
  943. }
  944. }
  945. return YES;
  946. }
  947. #pragma --------------------------------------------------------------------------------------------
  948. #pragma mark ===== Passcode + Delegate =====
  949. #pragma --------------------------------------------------------------------------------------------
  950. - (void)passcodeWithAutomaticallyPromptForBiometricValidation:(BOOL)automaticallyPromptForBiometricValidation
  951. {
  952. LAContext *laContext = [LAContext new];
  953. NSError *error;
  954. BOOL isBiometryAvailable = false;
  955. if ([[CCUtility getPasscode] length] == 0 || [self.account length] == 0 || [CCUtility getNotPasscodeAtStart]) return;
  956. if (self.passcodeViewController == nil) {
  957. self.passcodeViewController = [[TOPasscodeViewController alloc] initWithStyle:TOPasscodeViewStyleTranslucentLight passcodeType:TOPasscodeTypeSixDigits];
  958. if (@available(iOS 13.0, *)) {
  959. if ([[UITraitCollection currentTraitCollection] userInterfaceStyle] == UIUserInterfaceStyleDark) {
  960. self.passcodeViewController.style = TOPasscodeViewStyleTranslucentDark;
  961. }
  962. }
  963. self.passcodeViewController.delegate = self;
  964. self.passcodeViewController.keypadButtonShowLettering = false;
  965. if (CCUtility.getEnableTouchFaceID && [laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
  966. if (error == NULL) {
  967. if (laContext.biometryType == LABiometryTypeFaceID) {
  968. self.passcodeViewController.biometryType = TOPasscodeBiometryTypeFaceID;
  969. self.passcodeViewController.allowBiometricValidation = true;
  970. isBiometryAvailable = true;
  971. } else if (laContext.biometryType == LABiometryTypeTouchID) {
  972. self.passcodeViewController.biometryType = TOPasscodeBiometryTypeTouchID;
  973. self.passcodeViewController.allowBiometricValidation = true;
  974. isBiometryAvailable = true;
  975. } else {
  976. isBiometryAvailable = false;
  977. NSLog(@"No Biometric support");
  978. }
  979. }
  980. }
  981. [self.window.rootViewController presentViewController:self.passcodeViewController animated:YES completion:^{
  982. [self enableTouchFaceID:automaticallyPromptForBiometricValidation];
  983. }];
  984. } else {
  985. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  986. [self enableTouchFaceID:automaticallyPromptForBiometricValidation];
  987. });
  988. }
  989. }
  990. - (void)didInputCorrectPasscodeInPasscodeViewController:(TOPasscodeViewController *)passcodeViewController
  991. {
  992. [passcodeViewController dismissViewControllerAnimated:YES completion:^{
  993. self.passcodeViewController = nil;
  994. }];
  995. }
  996. - (BOOL)passcodeViewController:(TOPasscodeViewController *)passcodeViewController isCorrectCode:(NSString *)code
  997. {
  998. return [code isEqualToString:[CCUtility getPasscode]];
  999. }
  1000. - (void)didPerformBiometricValidationRequestInPasscodeViewController:(TOPasscodeViewController *)passcodeViewController
  1001. {
  1002. [[LAContext new] evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:[[NCBrandOptions sharedInstance] brand] reply:^(BOOL success, NSError * _Nullable error) {
  1003. if (success) {
  1004. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  1005. [passcodeViewController dismissViewControllerAnimated:YES completion:^{
  1006. self.passcodeViewController = nil;
  1007. }];
  1008. });
  1009. }
  1010. }];
  1011. }
  1012. - (void)enableTouchFaceID:(BOOL)automaticallyPromptForBiometricValidation
  1013. {
  1014. if (CCUtility.getEnableTouchFaceID && automaticallyPromptForBiometricValidation && self.passcodeViewController.view.window) {
  1015. [[LAContext new] evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:[[NCBrandOptions sharedInstance] brand] reply:^(BOOL success, NSError * _Nullable error) {
  1016. if (success) {
  1017. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  1018. [self.passcodeViewController dismissViewControllerAnimated:YES completion:^{
  1019. self.passcodeViewController = nil;
  1020. }];
  1021. });
  1022. }
  1023. }];
  1024. }
  1025. }
  1026. #pragma --------------------------------------------------------------------------------------------
  1027. #pragma mark ===== Maintenance Mode =====
  1028. #pragma --------------------------------------------------------------------------------------------
  1029. - (void)maintenanceMode:(BOOL)mode
  1030. {
  1031. self.maintenanceMode = mode;
  1032. }
  1033. @end