CCDetail.m 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  1. //
  2. // CCDetail.m
  3. // Nextcloud iOS
  4. //
  5. // Created by Marino Faggiana on 16/01/15.
  6. // Copyright (c) 2017 TWS. All rights reserved.
  7. //
  8. // Author Marino Faggiana <m.faggiana@twsweb.it>
  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 "CCDetail.h"
  24. #import "AppDelegate.h"
  25. #import "CCMain.h"
  26. #import "NCUchardet.h"
  27. #import "NCBridgeSwift.h"
  28. #import <KTVHTTPCache/KTVHTTPCache.h>
  29. #import "NCBridgeSwift.h"
  30. #define TOOLBAR_HEIGHT 49.0f
  31. #define alertRequestPasswordPDF 1
  32. @interface CCDetail () <NCTextDelegate, UIDocumentInteractionControllerDelegate>
  33. {
  34. AppDelegate *appDelegate;
  35. UIDocumentInteractionController *docController;
  36. UIBarButtonItem *buttonModifyTxt;
  37. UIBarButtonItem *buttonAction;
  38. UIBarButtonItem *buttonShare;
  39. UIBarButtonItem *buttonDelete;
  40. NSInteger indexNowVisible;
  41. NSString *fileIDNowVisible;
  42. NSMutableOrderedSet *dataSourceDirectoryID;
  43. NSString *fileNameExtension;
  44. NSURL *videoURLProxy;
  45. NSURL *videoURL;
  46. BOOL isMediaObserver;
  47. }
  48. @end
  49. @implementation CCDetail
  50. #pragma --------------------------------------------------------------------------------------------
  51. #pragma mark ===== init =====
  52. #pragma --------------------------------------------------------------------------------------------
  53. - (id)initWithCoder:(NSCoder *)aDecoder
  54. {
  55. if (self = [super initWithCoder:aDecoder]) {
  56. appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  57. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(triggerProgressTask:) name:@"NotificationProgressTask" object:nil];
  58. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeTheming) name:@"changeTheming" object:nil];
  59. self.metadataDetail = [[tableMetadata alloc] init];
  60. self.photos = [[NSMutableArray alloc] init];
  61. self.photoDataSource = [NSMutableArray new];
  62. dataSourceDirectoryID = [[NSMutableOrderedSet alloc] init];
  63. indexNowVisible = -1;
  64. fileIDNowVisible = nil;
  65. appDelegate.activeDetail = self;
  66. }
  67. return self;
  68. }
  69. #pragma --------------------------------------------------------------------------------------------
  70. #pragma mark ===== View =====
  71. #pragma --------------------------------------------------------------------------------------------
  72. - (void)viewDidLoad
  73. {
  74. [super viewDidLoad];
  75. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(insertGeocoderLocation:) name:@"insertGeocoderLocation" object:nil];
  76. self.imageBackground.image = [UIImage imageNamed:@"backgroundDetail"];
  77. // Proxy
  78. static dispatch_once_t onceToken;
  79. dispatch_once(&onceToken, ^{
  80. [self setupHTTPCache];
  81. });
  82. // Change bar bottom line shadow and remove title back button <"title"
  83. self.navigationController.navigationBar.shadowImage = [CCGraphics generateSinglePixelImageWithColor:[NCBrandColor sharedInstance].brand];
  84. self.navigationController.navigationBar.topItem.title = @"";
  85. // Color Navigation Controller
  86. [appDelegate aspectNavigationControllerBar:self.navigationController.navigationBar online:[appDelegate.reachability isReachable] hidden:NO];
  87. // TabBar
  88. self.tabBarController.tabBar.hidden = YES;
  89. self.tabBarController.tabBar.translucent = YES;
  90. // Open View
  91. if ([self.metadataDetail.fileNameView length] > 0 || [self.metadataDetail.directoryID length] > 0 || [self.metadataDetail.fileID length] > 0) {
  92. // open view
  93. [self viewFile];
  94. }
  95. }
  96. - (void)viewWillAppear:(BOOL)animated
  97. {
  98. [super viewWillAppear:animated];
  99. self.tabBarController.tabBar.hidden = YES;
  100. self.tabBarController.tabBar.translucent = YES;
  101. }
  102. - (void)viewDidDisappear:(BOOL)animated
  103. {
  104. [super viewDidDisappear:animated];
  105. // If AVPlayer in play -> Stop
  106. if (appDelegate.player != nil && appDelegate.player.rate != 0) {
  107. [appDelegate.player pause];
  108. }
  109. // remove Observer AVPlayer
  110. if (isMediaObserver) {
  111. isMediaObserver = NO;
  112. @try{
  113. [appDelegate.player removeObserver:self forKeyPath:@"rate" context:nil];
  114. [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:[appDelegate.player currentItem]];
  115. }@catch(id anException) { }
  116. }
  117. }
  118. - (void)changeTheming
  119. {
  120. [appDelegate changeTheming:self];
  121. if (self.toolbar) {
  122. self.toolbar.barTintColor = [NCBrandColor sharedInstance].tabBar;
  123. self.toolbar.tintColor = [NCBrandColor sharedInstance].brandElement;
  124. }
  125. }
  126. - (void)changeToDisplayMode
  127. {
  128. if (_readerPDFViewController)
  129. [self.readerPDFViewController updateContentViews];
  130. }
  131. #pragma --------------------------------------------------------------------------------------------
  132. #pragma mark ===== View File =====
  133. #pragma --------------------------------------------------------------------------------------------
  134. - (void)viewFile
  135. {
  136. // Title
  137. self.navigationController.navigationBar.topItem.title = _metadataDetail.fileNameView;
  138. // verifico se esiste l'icona e se la posso creare
  139. if ([[NSFileManager defaultManager] fileExistsAtPath:[CCUtility getDirectoryProviderStorageIconFileID:self.metadataDetail.fileID fileNameView:self.metadataDetail.fileNameView]] == NO) {
  140. [CCGraphics createNewImageFrom:self.metadataDetail.fileNameView fileID:self.metadataDetail.fileID extension:[self.metadataDetail.fileNameView pathExtension] filterGrayScale:NO typeFile:self.metadataDetail.typeFile writeImage:YES];
  141. }
  142. // remove Observer AVPlayer
  143. if (isMediaObserver) {
  144. isMediaObserver = NO;
  145. [appDelegate.player removeObserver:self forKeyPath:@"rate" context:nil];
  146. [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:[appDelegate.player currentItem]];
  147. }
  148. // IMAGE
  149. if ([self.metadataDetail.typeFile isEqualToString: k_metadataTypeFile_image]) {
  150. self.edgesForExtendedLayout = UIRectEdgeAll;
  151. [self viewImage];
  152. }
  153. // AUDIO VIDEO
  154. if ([self.metadataDetail.typeFile isEqualToString: k_metadataTypeFile_video] || [self.metadataDetail.typeFile isEqualToString: k_metadataTypeFile_audio]) {
  155. self.edgesForExtendedLayout = UIRectEdgeAll;
  156. [self createToolbar];
  157. [self viewMedia];
  158. }
  159. // DOCUMENT
  160. if ([self.metadataDetail.typeFile isEqualToString: k_metadataTypeFile_document]) {
  161. BOOL openWithRichDocument = false;
  162. fileNameExtension = [[self.metadataDetail.fileNameView pathExtension] uppercaseString];
  163. if ([fileNameExtension isEqualToString:@"PDF"]) {
  164. self.edgesForExtendedLayout = UIRectEdgeBottom;
  165. [self createToolbar];
  166. [self viewPDF:@""];
  167. return;
  168. }
  169. // Very if mimeType is compatible with Rich Document viewer
  170. NSString *mimeType = [CCUtility getMimeType:self.metadataDetail.fileNameView];
  171. NSArray *richdocumentsMimetypes = [[NCManageDatabase sharedInstance] getRichdocumentsMimetypes];
  172. if (richdocumentsMimetypes.count > 0 & mimeType != nil && [mimeType componentsSeparatedByString:@"."].count > 2) {
  173. NSArray *mimeTypeArray = [mimeType componentsSeparatedByString:@"."];
  174. NSString *mimeType = [NSString stringWithFormat:@"%@.%@",mimeTypeArray[mimeTypeArray.count-2], mimeTypeArray[mimeTypeArray.count-1]];
  175. for (NSString *richdocumentMimetype in richdocumentsMimetypes) {
  176. if ([richdocumentMimetype containsString:mimeType]) {
  177. openWithRichDocument = true;
  178. }
  179. }
  180. }
  181. if (openWithRichDocument) {
  182. OCnetworking *ocNetworking = [[OCnetworking alloc] initWithDelegate:nil metadataNet:nil withUser:appDelegate.activeUser withUserID:appDelegate.activeUserID withPassword:appDelegate.activePassword withUrl:appDelegate.activeUrl];
  183. [ocNetworking createLinkRichdocumentsWithFileID:self.metadataDetail.fileID success:^(NSString *link) {
  184. [[NCRichdocument sharedInstance] viewRichDocumentAt:link viewDetail:self];
  185. } failure:^(NSString *message, NSInteger errorCode) {
  186. [appDelegate messageNotification:@"_error_" description:message visible:YES delay:k_dismissAfterSecond type:TWMessageBarMessageTypeError errorCode:errorCode];
  187. [self.navigationController popViewControllerAnimated:YES];
  188. }];
  189. return;
  190. }
  191. self.edgesForExtendedLayout = UIRectEdgeBottom;
  192. [self createToolbar];
  193. [self viewDocument];
  194. }
  195. }
  196. #pragma --------------------------------------------------------------------------------------------
  197. #pragma mark ===== Toolbar =====
  198. #pragma --------------------------------------------------------------------------------------------
  199. - (void)createToolbar
  200. {
  201. CGFloat safeAreaBottom = 0;
  202. NSString *serverUrl = [[NCManageDatabase sharedInstance] getServerUrl:_metadataDetail.directoryID];
  203. if (!serverUrl)
  204. return;
  205. if (@available(iOS 11, *)) {
  206. safeAreaBottom = [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom;
  207. }
  208. self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height - TOOLBAR_HEIGHT - safeAreaBottom, self.view.bounds.size.width, TOOLBAR_HEIGHT)];
  209. UIBarButtonItem *flexible = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
  210. UIBarButtonItem *fixedSpaceMini = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:self action:nil];
  211. fixedSpaceMini.width = 25;
  212. buttonModifyTxt = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"actionSheetModify"] style:UIBarButtonItemStylePlain target:self action:@selector(modifyTxtButtonPressed:)];
  213. if (![NCBrandOptions sharedInstance].disable_openin_file) {
  214. buttonAction = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"openFile"] style:UIBarButtonItemStylePlain target:self action:@selector(actionButtonPressed:)];
  215. }
  216. buttonShare = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"share"] style:UIBarButtonItemStylePlain target:self action:@selector(shareButtonPressed:)];
  217. buttonDelete = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(deleteButtonPressed:)];
  218. if ([CCUtility isDocumentModifiableExtension:fileNameExtension]) {
  219. if ([CCUtility isFolderEncrypted:serverUrl account:appDelegate.activeAccount]) // E2EE
  220. [self.toolbar setItems:[NSArray arrayWithObjects: buttonModifyTxt, flexible, buttonDelete, fixedSpaceMini, buttonAction, nil]];
  221. else
  222. [self.toolbar setItems:[NSArray arrayWithObjects: buttonModifyTxt, flexible, buttonDelete, fixedSpaceMini, buttonShare, fixedSpaceMini, buttonAction, nil]];
  223. } else {
  224. if ([CCUtility isFolderEncrypted:serverUrl account:appDelegate.activeAccount]) // E2EE
  225. [self.toolbar setItems:[NSArray arrayWithObjects: flexible, buttonDelete, fixedSpaceMini, buttonAction, nil]];
  226. else
  227. [self.toolbar setItems:[NSArray arrayWithObjects: flexible, buttonDelete, fixedSpaceMini, buttonShare, fixedSpaceMini, buttonAction, nil]];
  228. }
  229. [self.toolbar setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin];
  230. self.toolbar.barTintColor = [NCBrandColor sharedInstance].tabBar;
  231. self.toolbar.tintColor = [NCBrandColor sharedInstance].brandElement;
  232. [self.view addSubview:self.toolbar];
  233. }
  234. #pragma --------------------------------------------------------------------------------------------
  235. #pragma mark ===== View Document =====
  236. #pragma --------------------------------------------------------------------------------------------
  237. - (void)viewDocument
  238. {
  239. CGFloat safeAreaBottom = 0;
  240. if (@available(iOS 11, *)) {
  241. safeAreaBottom = [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom;
  242. }
  243. if ([CCUtility fileProviderStorageExists:self.metadataDetail.fileID fileNameView:self.metadataDetail.fileNameView] == NO) {
  244. [self.navigationController popViewControllerAnimated:YES];
  245. return;
  246. }
  247. NSString *fileNamePath = [NSTemporaryDirectory() stringByAppendingString:self.metadataDetail.fileNameView];
  248. [[NSFileManager defaultManager] removeItemAtPath:fileNamePath error:nil];
  249. [[NSFileManager defaultManager] linkItemAtPath:[CCUtility getDirectoryProviderStorageFileID:self.metadataDetail.fileID fileNameView:self.metadataDetail.fileNameView] toPath:fileNamePath error:nil];
  250. NSURL *url = [NSURL fileURLWithPath:fileNamePath];
  251. WKPreferences *wkPreferences = [[WKPreferences alloc] init];
  252. wkPreferences.javaScriptEnabled = true;
  253. WKWebViewConfiguration *wkConfig = [[WKWebViewConfiguration alloc] init];
  254. wkConfig.preferences = wkPreferences;
  255. self.webView = [[WKWebView alloc] initWithFrame:(CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height - TOOLBAR_HEIGHT - safeAreaBottom)) configuration:wkConfig];
  256. self.webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  257. [self.webView setBackgroundColor:[NCBrandColor sharedInstance].backgroundView];
  258. [self.webView setOpaque:NO];
  259. if ( [fileNameExtension isEqualToString:@"CSS"] || [fileNameExtension isEqualToString:@"PY"] || [fileNameExtension isEqualToString:@"XML"] || [fileNameExtension isEqualToString:@"JS"] ) {
  260. NSString *dataFile = [[NSString alloc] initWithData:[NSData dataWithContentsOfURL:url] encoding:NSASCIIStringEncoding];
  261. if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
  262. [self.webView loadHTMLString:[NSString stringWithFormat:@"<div style='font-size:%@;font-family:%@;'><pre>%@",@"40",@"Sans-Serif",dataFile] baseURL:nil];
  263. }else{
  264. [self.webView loadHTMLString:[NSString stringWithFormat:@"<div style='font-size:%@;font-family:%@;'><pre>%@",@"20",@"Sans-Serif",dataFile] baseURL:nil];
  265. }
  266. } else if ([CCUtility isDocumentModifiableExtension:fileNameExtension]) {
  267. NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
  268. NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:nil delegateQueue:nil];
  269. NSMutableURLRequest *headRequest = [NSMutableURLRequest requestWithURL:url];
  270. [headRequest setHTTPMethod:@"HEAD"];
  271. NSURLSessionDataTask *task = [session dataTaskWithRequest:headRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
  272. dispatch_async(dispatch_get_main_queue(), ^{
  273. NSString *encodingName = [[NCUchardet sharedNUCharDet] encodingStringDetectWithData:data];
  274. [self.webView loadData:[NSData dataWithContentsOfURL: url] MIMEType:response.MIMEType characterEncodingName:encodingName baseURL:url];
  275. });
  276. }];
  277. [task resume];
  278. } else {
  279. [self.webView loadRequest:[NSMutableURLRequest requestWithURL:url]];
  280. }
  281. [self.view addSubview:self.webView];
  282. }
  283. #pragma --------------------------------------------------------------------------------------------
  284. #pragma mark ===== View Media =====
  285. #pragma --------------------------------------------------------------------------------------------
  286. - (void)viewMedia
  287. {
  288. CGFloat safeAreaBottom = 0;
  289. if (@available(iOS 11, *)) {
  290. safeAreaBottom = [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom;
  291. }
  292. NSString *serverUrl = [[NCManageDatabase sharedInstance] getServerUrl:_metadataDetail.directoryID];
  293. if (!serverUrl)
  294. return;
  295. if ([CCUtility fileProviderStorageExists:self.metadataDetail.fileID fileNameView:self.metadataDetail.fileNameView]) {
  296. videoURL = [NSURL fileURLWithPath:[CCUtility getDirectoryProviderStorageFileID:self.metadataDetail.fileID fileNameView:self.metadataDetail.fileNameView]];
  297. videoURLProxy = videoURL;
  298. } else {
  299. videoURL = [NSURL URLWithString:[[NSString stringWithFormat:@"%@/%@", serverUrl, _metadataDetail.fileName] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]];
  300. videoURLProxy = [KTVHTTPCache proxyURLWithOriginalURL:videoURL];
  301. NSMutableDictionary *header = [NSMutableDictionary new];
  302. NSData *authData = [[NSString stringWithFormat:@"%@:%@", appDelegate.activeUser, appDelegate.activePassword] dataUsingEncoding:NSUTF8StringEncoding];
  303. NSString *authValue = [NSString stringWithFormat: @"Basic %@",[authData base64EncodedStringWithOptions:0]];
  304. [header setValue:authValue forKey:@"Authorization"];
  305. [header setValue:[CCUtility getUserAgent] forKey:@"User-Agent"];
  306. [KTVHTTPCache downloadSetAdditionalHeaders:header];
  307. // Disable Button Action (the file is in download via Proxy Server)
  308. buttonAction.enabled = false;
  309. }
  310. appDelegate.player = [AVPlayer playerWithURL:videoURLProxy];
  311. appDelegate.playerController = [AVPlayerViewController new];
  312. appDelegate.playerController.player = appDelegate.player;
  313. appDelegate.playerController.view.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height - TOOLBAR_HEIGHT - safeAreaBottom);
  314. appDelegate.playerController.allowsPictureInPicturePlayback = false;
  315. [self addChildViewController:appDelegate.playerController];
  316. [self.view addSubview:appDelegate.playerController.view];
  317. [appDelegate.playerController didMoveToParentViewController:self];
  318. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:[appDelegate.player currentItem]];
  319. [appDelegate.player addObserver:self forKeyPath:@"rate" options:0 context:nil];
  320. isMediaObserver = YES;
  321. [appDelegate.player play];
  322. }
  323. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
  324. if ([keyPath isEqualToString:@"rate"]) {
  325. if ([appDelegate.player rate]) {
  326. NSLog(@"start");
  327. }
  328. else {
  329. NSLog(@"pause");
  330. }
  331. [self saveCacheToFileProvider];
  332. }
  333. }
  334. - (void)itemDidFinishPlaying:(NSNotification *)notification
  335. {
  336. AVPlayerItem *player = [notification object];
  337. [player seekToTime:kCMTimeZero];
  338. }
  339. - (void)saveCacheToFileProvider
  340. {
  341. if (![CCUtility fileProviderStorageExists:self.metadataDetail.fileID fileNameView:self.metadataDetail.fileNameView]) {
  342. NSURL *url = [KTVHTTPCache cacheCompleteFileURLIfExistedWithURL:videoURL];
  343. if (url) {
  344. [CCUtility copyFileAtPath:[url path] toPath:[CCUtility getDirectoryProviderStorageFileID:self.metadataDetail.fileID fileNameView:self.metadataDetail.fileNameView]];
  345. [[NCManageDatabase sharedInstance] addLocalFileWithMetadata:self.metadataDetail];
  346. [KTVHTTPCache cacheDeleteCacheWithURL:videoURL];
  347. // reload Data Source
  348. [[NCMainCommon sharedInstance] reloadDatasourceWithServerUrl:[[NCManageDatabase sharedInstance] getServerUrl:self.metadataDetail.directoryID] fileID:self.metadataDetail.fileID action:k_action_MOD];
  349. // Enabled Button Action (the file is in local)
  350. buttonAction.enabled = true;
  351. }
  352. }
  353. }
  354. - (void)setupHTTPCache
  355. {
  356. [KTVHTTPCache cacheSetMaxCacheLength:k_maxHTTPCache];
  357. #if TARGET_IPHONE_SIMULATOR
  358. [KTVHTTPCache logSetConsoleLogEnable:YES];
  359. #endif
  360. NSError * error;
  361. [KTVHTTPCache proxyStart:&error];
  362. if (error) {
  363. NSLog(@"Proxy Start Failure, %@", error);
  364. } else {
  365. NSLog(@"Proxy Start Success");
  366. }
  367. [KTVHTTPCache tokenSetURLFilter:^NSURL * (NSURL * URL) {
  368. NSLog(@"URL Filter reviced URL : %@", URL);
  369. return URL;
  370. }];
  371. [KTVHTTPCache downloadSetUnsupportContentTypeFilter:^BOOL(NSURL * URL, NSString * contentType) {
  372. NSLog(@"Unsupport Content-Type Filter reviced URL : %@, %@", URL, contentType);
  373. return NO;
  374. }];
  375. }
  376. #pragma --------------------------------------------------------------------------------------------
  377. #pragma mark ===== View Image =====
  378. #pragma --------------------------------------------------------------------------------------------
  379. - (void)viewImage
  380. {
  381. self.photoBrowser = [[MWPhotoBrowser alloc] initWithDelegate:self];
  382. indexNowVisible = -1;
  383. fileIDNowVisible = nil;
  384. [self.photos removeAllObjects];
  385. [dataSourceDirectoryID removeAllObjects];
  386. // if not images, exit
  387. if ([self.photoDataSource count] == 0)
  388. return;
  389. // test
  390. NSString *serverUrl = [[NCManageDatabase sharedInstance] getServerUrl:_metadataDetail.directoryID];
  391. if (!serverUrl)
  392. return;
  393. NSUInteger index = 0;
  394. for (tableMetadata *metadata in self.photoDataSource) {
  395. // start from here ?
  396. if (self.metadataDetail.fileID && [metadata.fileID isEqualToString:self.metadataDetail.fileID])
  397. [self.photoBrowser setCurrentPhotoIndex:index];
  398. [self.photos addObject:[MWPhoto photoWithImage:nil]];
  399. // add directory
  400. [dataSourceDirectoryID addObject:metadata.directoryID];
  401. index++;
  402. }
  403. // PhotoBrowser
  404. if ([NCBrandOptions sharedInstance].disable_openin_file) {
  405. self.photoBrowser.displayActionButton = NO;
  406. } else {
  407. self.photoBrowser.displayActionButton = YES;
  408. }
  409. self.photoBrowser.displayDeleteButton = YES;
  410. if ([CCUtility isFolderEncrypted:serverUrl account:appDelegate.activeAccount]) // E2EE
  411. self.photoBrowser.displayShareButton = NO;
  412. else
  413. self.photoBrowser.displayShareButton = YES;
  414. self.photoBrowser.displayNavArrows = YES;
  415. self.photoBrowser.displaySelectionButtons = NO;
  416. self.photoBrowser.alwaysShowControls = NO;
  417. self.photoBrowser.zoomPhotosToFill = NO;
  418. self.photoBrowser.autoPlayOnAppear = NO;
  419. self.photoBrowser.delayToHideElements = 15;
  420. if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
  421. self.photoBrowser.enableSwipeToDismiss = NO;
  422. if (self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
  423. [self addChildViewController:self.photoBrowser];
  424. [self.view addSubview:self.photoBrowser.view];
  425. [self.photoBrowser didMoveToParentViewController:self];
  426. } else {
  427. [self.navigationController pushViewController:self.photoBrowser animated:NO];
  428. }
  429. }
  430. - (NSUInteger)numberOfPhotosInPhotoBrowser:(MWPhotoBrowser *)photoBrowser
  431. {
  432. return [self.photoDataSource count];
  433. }
  434. - (NSString *)photoBrowser:(MWPhotoBrowser *)photoBrowser titleForPhotoAtIndex:(NSUInteger)index
  435. {
  436. tableMetadata *metadata = [self.photoDataSource objectAtIndex:index];
  437. NSString *titleDir = metadata.fileNameView;
  438. self.title = titleDir;
  439. return titleDir;
  440. }
  441. - (void)photoBrowser:(MWPhotoBrowser *)photoBrowser didDisplayPhotoAtIndex:(NSUInteger)index
  442. {
  443. tableMetadata *metadata = [self.photoDataSource objectAtIndex:index];
  444. indexNowVisible = index;
  445. fileIDNowVisible = metadata.fileID;
  446. photoBrowser.toolbar.hidden = NO;
  447. // Download image ?
  448. if (metadata) {
  449. NSString *serverUrl = [[NCManageDatabase sharedInstance] getServerUrl:metadata.directoryID];
  450. NSInteger status;
  451. tableMetadata *metadataDB = [[NCManageDatabase sharedInstance] getMetadataWithPredicate:[NSPredicate predicateWithFormat:@"fileID == %@", metadata.fileID]];
  452. if (metadataDB) {
  453. status = metadataDB.status;
  454. } else {
  455. status = k_metadataStatusNormal;
  456. }
  457. NSString *ext = [[metadata.fileNameView pathExtension] uppercaseString];
  458. if ([CCUtility fileProviderStorageExists:metadata.fileID fileNameView:metadata.fileNameView] == NO && status == k_metadataStatusNormal) {
  459. if ([[NSFileManager defaultManager] fileExistsAtPath:[CCUtility getDirectoryProviderStorageIconFileID:metadata.fileID fileNameView:metadata.fileNameView]] == NO) {
  460. [CCGraphics addImageToTitle:NSLocalizedString(@"_...loading..._", nil) colorTitle:[NCBrandColor sharedInstance].brandText imageTitle:[CCGraphics changeThemingColorImage:[UIImage imageNamed:@"load"] multiplier:2 color:[NCBrandColor sharedInstance].brandText] imageRight:NO navigationItem:self.navigationItem];
  461. CGFloat width = [[NCUtility sharedInstance] getScreenWidthForPreview];
  462. CGFloat height = [[NCUtility sharedInstance] getScreenHeightForPreview];
  463. OCnetworking *ocNetworking = [[OCnetworking alloc] initWithDelegate:nil metadataNet:nil withUser:appDelegate.activeUser withUserID:appDelegate.activeUserID withPassword:appDelegate.activePassword withUrl:appDelegate.activeUrl];
  464. [ocNetworking downloadPreviewWithMetadata:metadata serverUrl:serverUrl withWidth:width andHeight:height completion:^(NSString *message, NSInteger errorCode) {
  465. self.navigationItem.titleView = nil;
  466. self.title = metadata.fileNameView;
  467. if (([CCUtility getOptimizedPhoto] == YES && errorCode != 0) || [CCUtility getOptimizedPhoto] == NO || [ext isEqualToString:@"GIF"]) {
  468. [self downloadPhotoBrowser:metadata serverUrl:serverUrl];
  469. }
  470. [self.photoBrowser reloadData];
  471. }];
  472. } else {
  473. if ([CCUtility getOptimizedPhoto] == NO || [ext isEqualToString:@"GIF"]) {
  474. [self downloadPhotoBrowser:metadata serverUrl:serverUrl];
  475. }
  476. }
  477. }
  478. }
  479. // Title
  480. if (metadata)
  481. self.title = metadata.fileNameView;
  482. }
  483. - (id <MWPhoto>)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index
  484. {
  485. UIImage *image;
  486. tableMetadata *metadata = [self.photoDataSource objectAtIndex:index];
  487. if (index < self.photos.count) {
  488. if (metadata.fileID) {
  489. UIImage *imagePreview = [UIImage imageWithContentsOfFile:[CCUtility getDirectoryProviderStorageIconFileID:metadata.fileID fileNameView:metadata.fileNameView]];
  490. // if (!imagePreview) imagePreview = [CCGraphics changeThemingColorImage:[UIImage imageNamed:@"file_photo"] multiplier:3 color:[[NCBrandColor sharedInstance] icon]];
  491. if ([metadata.typeFile isEqualToString: k_metadataTypeFile_image]) {
  492. NSString *fileImage = [CCUtility getDirectoryProviderStorageFileID:metadata.fileID fileNameView:metadata.fileNameView];
  493. NSString *ext = [CCUtility getExtension:metadata.fileNameView];
  494. if ([ext isEqualToString:@"GIF"]) image = [UIImage animatedImageWithAnimatedGIFURL:[NSURL fileURLWithPath:fileImage]];
  495. else image = [UIImage imageWithContentsOfFile:fileImage];
  496. if (image) {
  497. MWPhoto *photo = [MWPhoto photoWithImage:image];
  498. // Location ??
  499. [self setLocationCaptionPhoto:photo fileID:metadata.fileID];
  500. [self.photos replaceObjectAtIndex:index withObject:photo];
  501. } else {
  502. if (metadata.status == k_metadataStatusDownloadError) {
  503. [self.photos replaceObjectAtIndex:index withObject:[MWPhoto photoWithImage:[UIImage imageNamed:@"filePreviewError"]]];
  504. } else {
  505. if (imagePreview)
  506. [self.photos replaceObjectAtIndex:index withObject:[MWPhoto photoWithImage:imagePreview]];
  507. }
  508. }
  509. }
  510. if ([metadata.typeFile isEqualToString: k_metadataTypeFile_video]) {
  511. if ([CCUtility fileProviderStorageExists:metadata.fileID fileNameView:metadata.fileNameView]) {
  512. NSURL *url = [NSURL fileURLWithPath:[CCUtility getDirectoryProviderStorageFileID:metadata.fileID fileNameView:metadata.fileNameView]];
  513. MWPhoto *video = [MWPhoto photoWithImage:[CCGraphics thumbnailImageForVideo:url atTime:1.0]];
  514. video.videoURL = url;
  515. [self.photos replaceObjectAtIndex:index withObject:video];
  516. } else {
  517. if (metadata.status == k_metadataStatusDownloadError) {
  518. [self.photos replaceObjectAtIndex:index withObject:[MWPhoto photoWithImage:[UIImage imageNamed:@"filePreviewError"]]];
  519. } else {
  520. if (imagePreview)
  521. [self.photos replaceObjectAtIndex:index withObject:[MWPhoto photoWithImage:imagePreview]];
  522. }
  523. }
  524. }
  525. if ([metadata.typeFile isEqualToString: k_metadataTypeFile_audio]) {
  526. if ([CCUtility fileProviderStorageExists:metadata.fileID fileNameView:metadata.fileNameView]) {
  527. MWPhoto *audio;
  528. UIImage *audioImage;
  529. NSURL *url = [NSURL fileURLWithPath:[CCUtility getDirectoryProviderStorageFileID:metadata.fileID fileNameView:metadata.fileNameView]];
  530. if ([[NSFileManager defaultManager] fileExistsAtPath:[CCUtility getDirectoryProviderStorageIconFileID:metadata.fileID fileNameView:metadata.fileNameView]]) {
  531. audioImage = [UIImage imageWithContentsOfFile:[CCUtility getDirectoryProviderStorageIconFileID:metadata.fileID fileNameView:metadata.fileNameView]];
  532. } else {
  533. audioImage = [UIImage imageNamed:@"notaMusic"]; //[CCGraphics scaleImage:[UIImage imageNamed:@"notaMusic"] toSize:CGSizeMake(200, 200) isAspectRation:YES];
  534. }
  535. audio = [MWPhoto photoWithImage:audioImage];
  536. audio.videoURL = url;
  537. [self.photos replaceObjectAtIndex:index withObject:audio];
  538. } else {
  539. if (metadata.status == k_metadataStatusDownloadError) {
  540. [self.photos replaceObjectAtIndex:index withObject:[MWPhoto photoWithImage:[UIImage imageNamed:@"filePreviewError"]]];
  541. } else {
  542. if (imagePreview)
  543. [self.photos replaceObjectAtIndex:index withObject:[MWPhoto photoWithImage:imagePreview]];
  544. }
  545. }
  546. }
  547. }
  548. // energy saving memory
  549. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  550. int iPrev = (int)index - 2;
  551. if (iPrev >= 0) {
  552. if ([self.photos objectAtIndex:iPrev] != nil)
  553. [self.photos replaceObjectAtIndex:iPrev withObject:[MWPhoto photoWithImage:nil]];
  554. }
  555. int iNext = (int)index + 2;
  556. if (iNext < _photos.count) {
  557. if ([self.photos objectAtIndex:iNext] != nil)
  558. [self.photos replaceObjectAtIndex:iNext withObject:[MWPhoto photoWithImage:nil]];
  559. }
  560. });
  561. return [self.photos objectAtIndex:index];
  562. }
  563. return nil;
  564. }
  565. - (void)photoBrowser:(MWPhotoBrowser *)photoBrowser actionButtonPressedForPhotoAtIndex:(NSUInteger)index
  566. {
  567. tableMetadata *metadata = [self.photoDataSource objectAtIndex:index];
  568. if (metadata == nil) return;
  569. docController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:[CCUtility getDirectoryProviderStorageFileID:metadata.fileID fileNameView:metadata.fileNameView]]];
  570. docController.delegate = self;
  571. if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
  572. [docController presentOptionsMenuFromRect:photoBrowser.view.frame inView:photoBrowser.view animated:YES];
  573. [docController presentOptionsMenuFromBarButtonItem:photoBrowser.actionButton animated:YES];
  574. }
  575. - (void)photoBrowser:(MWPhotoBrowser *)photoBrowser shareButtonPressedForPhotoAtIndex:(NSUInteger)index
  576. {
  577. tableMetadata *metadata = [self.photoDataSource objectAtIndex:index];
  578. [appDelegate.activeMain openWindowShare:metadata];
  579. }
  580. - (void)photoBrowser:(MWPhotoBrowser *)photoBrowser deleteButtonPressedForPhotoAtIndex:(NSUInteger)index deleteButton:(UIBarButtonItem *)deleteButton
  581. {
  582. tableMetadata *metadata = [self.photoDataSource objectAtIndex:index];
  583. if (metadata == nil || [CCUtility fileProviderStorageExists:metadata.fileID fileNameView:metadata.fileNameView] == NO) {
  584. [appDelegate messageNotification:@"_info_" description:@"_file_not_found_" visible:YES delay:k_dismissAfterSecond type:TWMessageBarMessageTypeInfo errorCode:0];
  585. return;
  586. }
  587. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
  588. [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_delete_", nil)
  589. style:UIAlertActionStyleDestructive
  590. handler:^(UIAlertAction *action) {
  591. [self deleteFile:metadata];
  592. }]];
  593. [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_cancel_", nil)
  594. style:UIAlertActionStyleCancel
  595. handler:^(UIAlertAction *action) {
  596. }]];
  597. alertController.popoverPresentationController.barButtonItem = deleteButton;
  598. if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
  599. [alertController.view layoutIfNeeded];
  600. [self.parentViewController presentViewController:alertController animated:YES completion:NULL];
  601. }
  602. - (void)photoBrowserDidFinishPresentation:(MWPhotoBrowser *)photoBrowser
  603. {
  604. [self.navigationController popViewControllerAnimated:YES];
  605. }
  606. - (void)triggerProgressTask:(NSNotification *)notification
  607. {
  608. /*
  609. NSDictionary *dict = notification.userInfo;
  610. NSString *fileID = [dict valueForKey:@"fileID"];
  611. //NSString *serverUrl = [dict valueForKey:@"serverUrl"];
  612. //long status = [[dict valueForKey:@"status"] longValue];
  613. float progress = [[dict valueForKey:@"progress"] floatValue];
  614. //long long totalBytes = [[dict valueForKey:@"totalBytes"] longLongValue];
  615. //long long totalBytesExpected = [[dict valueForKey:@"totalBytesExpected"] longLongValue];
  616. if ([fileID isEqualToString:_fileIDNowVisible])
  617. [_hud progress:progress];
  618. */
  619. }
  620. - (void)downloadPhotoBrowserSuccessFailure:(tableMetadata *)metadata selector:(NSString *)selector errorCode:(NSInteger)errorCode
  621. {
  622. // if a message for a directory of these
  623. if (![metadata.fileID isEqualToString:fileIDNowVisible])
  624. return;
  625. // Title
  626. self.navigationItem.titleView = nil;
  627. self.title = metadata.fileNameView;
  628. if (errorCode == 0) {
  629. // verifico se esiste l'icona e se la posso creare
  630. if ([[NSFileManager defaultManager] fileExistsAtPath:[CCUtility getDirectoryProviderStorageIconFileID:metadata.fileID fileNameView:metadata.fileNameView]] == NO) {
  631. [CCGraphics createNewImageFrom:metadata.fileNameView fileID:metadata.fileID extension:[metadata.fileNameView pathExtension] filterGrayScale:NO typeFile:metadata.typeFile writeImage:YES];
  632. }
  633. [self.photoBrowser reloadData];
  634. } else {
  635. [appDelegate messageNotification:@"_download_selected_files_" description:@"_error_download_photobrowser_" visible:YES delay:k_dismissAfterSecond type:TWMessageBarMessageTypeError errorCode:errorCode];
  636. [self.navigationController popViewControllerAnimated:YES];
  637. }
  638. }
  639. - (void)downloadPhotoBrowser:(tableMetadata *)metadata serverUrl:(NSString *)serverUrl
  640. {
  641. tableMetadata *metadataForDownload = [[NCManageDatabase sharedInstance] initNewMetadata:metadata];
  642. metadataForDownload.session = k_download_session;
  643. metadataForDownload.sessionError = @"";
  644. metadataForDownload.sessionSelector = selectorLoadViewImage;
  645. metadataForDownload.status = k_metadataStatusWaitDownload;
  646. // Add Metadata for Download
  647. (void)[[NCManageDatabase sharedInstance] addMetadata:metadataForDownload];
  648. [appDelegate performSelectorOnMainThread:@selector(loadAutoDownloadUpload) withObject:nil waitUntilDone:YES];
  649. [[NCMainCommon sharedInstance] reloadDatasourceWithServerUrl:serverUrl fileID:metadataForDownload.fileID action:k_action_MOD];
  650. [CCGraphics addImageToTitle:NSLocalizedString(@"_...loading..._", nil) colorTitle:[NCBrandColor sharedInstance].brandText imageTitle:[CCGraphics changeThemingColorImage:[UIImage imageNamed:@"load"] multiplier:2 color:[NCBrandColor sharedInstance].brandText] imageRight:NO navigationItem:self.navigationItem];
  651. }
  652. - (void)insertGeocoderLocation:(NSNotification *)notification
  653. {
  654. if (notification.userInfo.count == 0)
  655. return;
  656. NSString *fileID = [[notification.userInfo allKeys] objectAtIndex:0];
  657. //NSDate *date = [[notification.userInfo allValues] objectAtIndex:0];
  658. // test [Chrash V 1.14,15]
  659. if (indexNowVisible >= [self.photos count])
  660. return;
  661. if ([fileID isEqualToString:fileIDNowVisible]) {
  662. MWPhoto *photo = [self.photos objectAtIndex:indexNowVisible];
  663. [self setLocationCaptionPhoto:photo fileID:fileID];
  664. [self.photoBrowser reloadData];
  665. }
  666. }
  667. - (void)setLocationCaptionPhoto:(MWPhoto *)photo fileID:(NSString *)fileID
  668. {
  669. tableLocalFile *localFile;
  670. // read Geocoder
  671. localFile = [[NCManageDatabase sharedInstance] getTableLocalFileWithPredicate:[NSPredicate predicateWithFormat:@"fileID == %@", fileID]];
  672. if ([localFile.exifLatitude doubleValue] != 0 || [localFile.exifLongitude doubleValue] != 0) {
  673. // Fix BUG Geo latitude & longitude
  674. if ([localFile.exifLatitude doubleValue] == 9999 || [localFile.exifLongitude doubleValue] == 9999) {
  675. tableMetadata *metadata = [[NCManageDatabase sharedInstance] getMetadataWithPredicate:[NSPredicate predicateWithFormat:@"fileID == %@", fileID]];
  676. if (metadata) {
  677. [[CCExifGeo sharedInstance] setExifLocalTableEtag:metadata];
  678. }
  679. }
  680. [[CCExifGeo sharedInstance] setGeocoderEtag:fileID exifDate:localFile.exifDate latitude:localFile.exifLatitude longitude:localFile.exifLongitude];
  681. localFile = [[NCManageDatabase sharedInstance] getTableLocalFileWithPredicate:[NSPredicate predicateWithFormat:@"fileID == %@", fileID]];
  682. if ([localFile.exifLatitude floatValue] != 0 || [localFile.exifLongitude floatValue] != 0) {
  683. NSString *location = [[NCManageDatabase sharedInstance] getLocationFromGeoLatitude:localFile.exifLatitude longitude:localFile.exifLongitude];
  684. if ([localFile.exifDate isEqualToDate:[NSDate distantPast]] == NO && location) {
  685. NSString *localizedDateTime = [NSDateFormatter localizedStringFromDate:localFile.exifDate dateStyle:NSDateFormatterFullStyle timeStyle:NSDateFormatterMediumStyle];
  686. photo.caption = [NSString stringWithFormat:NSLocalizedString(@"%@\n%@", nil), localizedDateTime, location];
  687. }
  688. }
  689. }
  690. }
  691. #pragma --------------------------------------------------------------------------------------------
  692. #pragma mark ===== View PDF =====
  693. #pragma --------------------------------------------------------------------------------------------
  694. - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
  695. {
  696. [alertView dismissWithClickedButtonIndex:buttonIndex animated:YES];
  697. [[alertView textFieldAtIndex:0] resignFirstResponder];
  698. if (alertView.tag == alertRequestPasswordPDF) [self performSelector:@selector(viewPDF:) withObject:[alertView textFieldAtIndex:0].text afterDelay:0.3];
  699. }
  700. - (void)viewPDF:(NSString *)password
  701. {
  702. // remove cache PDF
  703. NSString *filePlistReader = [NSString stringWithFormat:@"%@/%@.plist", [CCUtility getDirectoryReaderMetadata], self.metadataDetail.fileNameView.stringByDeletingPathExtension];
  704. [CCUtility removeFileAtPath:filePlistReader];
  705. NSString *fileNamePath = [CCUtility getDirectoryProviderStorageFileID:self.metadataDetail.fileID fileNameView:self.metadataDetail.fileNameView];
  706. if ([CCUtility fileProviderStorageExists:self.metadataDetail.fileID fileNameView:self.metadataDetail.fileNameView] == NO) {
  707. // read file error
  708. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_error_", nil) message:NSLocalizedString(@"_read_file_error_", nil) preferredStyle:UIAlertControllerStyleAlert];
  709. UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"_ok_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}];
  710. [alertController addAction:okAction];
  711. [self presentViewController:alertController animated:YES completion:nil];
  712. }
  713. CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)[NSURL fileURLWithPath:fileNamePath]);
  714. if (pdf) {
  715. // Encrypted
  716. if (CGPDFDocumentIsEncrypted(pdf) == YES) {
  717. // Try a blank password first, per Apple's Quartz PDF example
  718. if (CGPDFDocumentUnlockWithPassword(pdf, "") == YES) {
  719. // blank password
  720. [self readerPDF:fileNamePath password:@""];
  721. } else {
  722. if ([password length] == 0) {
  723. // password request
  724. UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"_insert_password_pfd_",nil) message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(@"_ok_", nil), nil];
  725. [alertView setAlertViewStyle:UIAlertViewStylePlainTextInput];
  726. alertView.tag = alertRequestPasswordPDF;
  727. [alertView show];
  728. } else {
  729. const char *key = [password UTF8String];
  730. // failure
  731. if (CGPDFDocumentUnlockWithPassword(pdf, key) == NO) {
  732. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_error_", nil) message:NSLocalizedString(@"_password_pdf_error_", nil) preferredStyle:UIAlertControllerStyleAlert];
  733. UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"_ok_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}];
  734. [alertController addAction:okAction];
  735. [self presentViewController:alertController animated:YES completion:nil];
  736. } else {
  737. // pdf with password
  738. [self readerPDF:fileNamePath password:password];
  739. }
  740. }
  741. }
  742. } else{
  743. // No password
  744. [self readerPDF:fileNamePath password:@""];
  745. }
  746. } else {
  747. // read file error
  748. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_error_", nil) message:NSLocalizedString(@"_read_file_error_", nil) preferredStyle:UIAlertControllerStyleAlert];
  749. UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"_ok_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}];
  750. [alertController addAction:okAction];
  751. [self presentViewController:alertController animated:YES completion:nil];
  752. }
  753. }
  754. - (void)readerPDF:(NSString *)fileName password:(NSString *)password
  755. {
  756. ReaderDocument *documentPDF = [ReaderDocument withDocumentFilePath:fileName password:password];
  757. CGFloat safeAreaBottom = 0;
  758. if (@available(iOS 11, *)) {
  759. safeAreaBottom = [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom;
  760. }
  761. if (documentPDF != nil) {
  762. self.readerPDFViewController = [[ReaderViewController alloc] initWithReaderDocument:documentPDF];
  763. self.readerPDFViewController.delegate = self;
  764. self.readerPDFViewController.view.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height - TOOLBAR_HEIGHT - safeAreaBottom);
  765. [self.readerPDFViewController updateContentViews];
  766. [self addChildViewController:self.readerPDFViewController];
  767. [self.view addSubview:self.readerPDFViewController.view];
  768. [self.readerPDFViewController didMoveToParentViewController:self];
  769. } else {
  770. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_error_", nil) message:NSLocalizedString(@"_read_file_error_", nil) preferredStyle:UIAlertControllerStyleAlert];
  771. UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"_ok_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}];
  772. [alertController addAction:okAction];
  773. [self presentViewController:alertController animated:YES completion:nil];
  774. }
  775. }
  776. - (void)handleSingleTapReader
  777. {
  778. UILayoutGuide *layoutGuide;
  779. CGFloat safeAreaTop = 0;
  780. CGFloat safeAreaBottom = 0;
  781. if (@available(iOS 11, *)) {
  782. layoutGuide = [UIApplication sharedApplication].delegate.window.safeAreaLayoutGuide;
  783. safeAreaTop = [UIApplication sharedApplication].delegate.window.safeAreaInsets.top;
  784. safeAreaBottom = [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom;
  785. }
  786. self.navigationController.navigationBarHidden = !self.navigationController.navigationBarHidden;
  787. self.toolbar.hidden = !self.toolbar.isHidden;
  788. if (self.toolbar.isHidden) {
  789. self.readerPDFViewController.view.frame = CGRectMake(0, safeAreaTop, self.view.bounds.size.width, self.view.bounds.size.height - safeAreaTop - safeAreaBottom);
  790. } else {
  791. self.readerPDFViewController.view.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height - TOOLBAR_HEIGHT - safeAreaBottom);
  792. }
  793. [self.readerPDFViewController updateContentViews];
  794. }
  795. - (void)handleSwipeUpDown
  796. {
  797. // REMOVE IT'S UNUSABLE
  798. /*
  799. self.navigationController.navigationBarHidden = false; // iOS App is unusable after swipe up or down with PDF in fullscreen #526
  800. [self removeAllView];
  801. [self.navigationController popViewControllerAnimated:YES];
  802. */
  803. }
  804. #pragma --------------------------------------------------------------------------------------------
  805. #pragma mark ===== Delete =====
  806. #pragma --------------------------------------------------------------------------------------------
  807. - (void)deleteFile:(tableMetadata *)metadata
  808. {
  809. NSString *serverUrl = [[NCManageDatabase sharedInstance] getServerUrl:metadata.directoryID];
  810. tableDirectory *tableDirectory = [[NCManageDatabase sharedInstance] getTableDirectoryWithPredicate:[NSPredicate predicateWithFormat:@"account == %@ AND e2eEncrypted == 1 AND serverUrl == %@", appDelegate.activeAccount, serverUrl]];
  811. [[NCMainCommon sharedInstance ] deleteFileWithMetadatas:[[NSArray alloc] initWithObjects:metadata, nil] e2ee:tableDirectory.e2eEncrypted serverUrl:serverUrl folderFileID:tableDirectory.fileID completion:^(NSInteger errorCode, NSString *message) {
  812. if (errorCode == 0) {
  813. // reload data source
  814. [[NCMainCommon sharedInstance] reloadDatasourceWithServerUrl:serverUrl fileID:metadata.fileID action:k_action_DEL];
  815. // Not image
  816. if ([self.metadataDetail.typeFile isEqualToString: k_metadataTypeFile_image] == NO) {
  817. // exit
  818. [self.navigationController popViewControllerAnimated:YES];
  819. } else {
  820. for (NSUInteger index=0; index < [self.photoDataSource count] && _photoBrowser; index++ ) {
  821. tableMetadata *metadataTemp = [self.photoDataSource objectAtIndex:index];
  822. if ([metadata isInvalidated] || [metadataTemp.fileID isEqualToString:metadata.fileID]) {
  823. [self.photoDataSource removeObjectAtIndex:index];
  824. [self.photos removeObjectAtIndex:index];
  825. [self.photoBrowser reloadData];
  826. // exit
  827. if ([self.photoDataSource count] == 0) {
  828. [self.navigationController popViewControllerAnimated:YES];
  829. }
  830. }
  831. }
  832. }
  833. } else {
  834. NSLog(@"[LOG] DeleteFileOrFolder failure error %d, %@", (int)errorCode, message);
  835. }
  836. }];
  837. }
  838. #pragma --------------------------------------------------------------------------------------------
  839. #pragma mark ===== ButtonPressed =====
  840. #pragma --------------------------------------------------------------------------------------------
  841. - (void)dismissTextView
  842. {
  843. if (self.webView) {
  844. NSString *fileNamePath = [NSTemporaryDirectory() stringByAppendingString:self.metadataDetail.fileNameView];
  845. [[NSFileManager defaultManager] removeItemAtPath:fileNamePath error:nil];
  846. [[NSFileManager defaultManager] linkItemAtPath:[CCUtility getDirectoryProviderStorageFileID:self.metadataDetail.fileID fileNameView:self.metadataDetail.fileNameView] toPath:fileNamePath error:nil];
  847. [self.webView reload];
  848. }
  849. }
  850. - (void)modifyTxtButtonPressed:(UIBarButtonItem *)sender
  851. {
  852. tableMetadata *metadata = [[NCManageDatabase sharedInstance] getMetadataWithPredicate:[NSPredicate predicateWithFormat:@"fileID == %@", self.metadataDetail.fileID]];
  853. if (metadata) {
  854. UINavigationController* navigationController = [[UIStoryboard storyboardWithName:@"NCText" bundle:nil] instantiateViewControllerWithIdentifier:@"NCText"];
  855. NCText *viewController = (NCText *)navigationController.topViewController;
  856. viewController.metadata = metadata;
  857. viewController.delegate = self;
  858. navigationController.modalPresentationStyle = UIModalPresentationPageSheet;
  859. navigationController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
  860. [self presentViewController:navigationController animated:YES completion:nil];
  861. }
  862. }
  863. - (void)actionButtonPressed:(UIBarButtonItem *)sender
  864. {
  865. if ([self.metadataDetail.fileNameView length] == 0) return;
  866. NSString *filePath = [CCUtility getDirectoryProviderStorageFileID:self.metadataDetail.fileID fileNameView:self.metadataDetail.fileNameView];
  867. docController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
  868. docController.delegate = self;
  869. if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
  870. [docController presentOptionsMenuFromRect:self.view.frame inView:self.view animated:YES];
  871. [docController presentOptionsMenuFromBarButtonItem:sender animated:YES];
  872. }
  873. - (void)shareButtonPressed:(UIBarButtonItem *)sender
  874. {
  875. [appDelegate.activeMain openWindowShare:self.metadataDetail];
  876. }
  877. - (void)deleteButtonPressed:(UIBarButtonItem *)sender
  878. {
  879. if ([self.metadataDetail.fileNameView length] == 0) return;
  880. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
  881. [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_delete_", nil)
  882. style:UIAlertActionStyleDestructive
  883. handler:^(UIAlertAction *action) {
  884. [self deleteFile:self.metadataDetail];
  885. }]];
  886. [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_cancel_", nil)
  887. style:UIAlertActionStyleCancel
  888. handler:^(UIAlertAction *action) {
  889. [alertController dismissViewControllerAnimated:YES completion:nil];
  890. }]];
  891. alertController.popoverPresentationController.barButtonItem = buttonDelete;
  892. if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
  893. [alertController.view layoutIfNeeded];
  894. [self presentViewController:alertController animated:YES completion:NULL];
  895. }
  896. @end