From 971aebd6589fe6826b7266513cb83191f86da134 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 10 Jan 2019 13:18:04 +0100 Subject: [PATCH] MOBILE-2795 ios: Handle files shared through iCloud --- .../pages/choose-site/choose-site.ts | 6 +- src/core/sharedfiles/providers/helper.ts | 67 +++++++++++++++---- src/core/sharedfiles/providers/sharedfiles.ts | 2 +- src/core/sharedfiles/sharedfiles.module.ts | 10 ++- src/providers/file.ts | 4 +- src/providers/utils/mimetype.ts | 2 +- upgrade.txt | 1 + 7 files changed, 72 insertions(+), 20 deletions(-) diff --git a/src/core/sharedfiles/pages/choose-site/choose-site.ts b/src/core/sharedfiles/pages/choose-site/choose-site.ts index e8cc53e08..d680913a9 100644 --- a/src/core/sharedfiles/pages/choose-site/choose-site.ts +++ b/src/core/sharedfiles/pages/choose-site/choose-site.ts @@ -35,11 +35,13 @@ export class CoreSharedFilesChooseSitePage implements OnInit { protected filePath: string; protected fileEntry: any; + protected isInbox: boolean; // Whether the file is in the Inbox folder. constructor(private navCtrl: NavController, navParams: NavParams, private sharedFilesHelper: CoreSharedFilesHelperProvider, private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider, private fileProvider: CoreFileProvider) { this.filePath = navParams.get('filePath'); + this.isInbox = navParams.get('isInbox'); } /** @@ -57,7 +59,7 @@ export class CoreSharedFilesChooseSitePage implements OnInit { this.fileName = fileAndDir.name; // Get the file. - this.fileProvider.getFile(this.filePath).then((fe) => { + this.fileProvider.getExternalFile(this.filePath).then((fe) => { this.fileEntry = fe; this.fileName = this.fileEntry.name; }).catch(() => { @@ -80,7 +82,7 @@ export class CoreSharedFilesChooseSitePage implements OnInit { */ storeInSite(siteId: string): void { this.loaded = false; - this.sharedFilesHelper.storeSharedFileInSite(this.fileEntry, siteId).then(() => { + this.sharedFilesHelper.storeSharedFileInSite(this.fileEntry, siteId, this.isInbox).then(() => { this.navCtrl.pop(); }).finally(() => { this.loaded = true; diff --git a/src/core/sharedfiles/providers/helper.ts b/src/core/sharedfiles/providers/helper.ts index a3a4341e3..a2ef83342 100644 --- a/src/core/sharedfiles/providers/helper.ts +++ b/src/core/sharedfiles/providers/helper.ts @@ -77,10 +77,22 @@ export class CoreSharedFilesHelperProvider { * Go to the choose site view. * * @param {string} filePath File path to send to the view. + * @param {boolean} [isInbox] Whether the file is in the Inbox folder. */ - goToChooseSite(filePath: string): void { + goToChooseSite(filePath: string, isInbox?: boolean): void { const navCtrl = this.appProvider.getRootNavController(); - navCtrl.push('CoreSharedFilesChooseSitePage', { filePath: filePath }); + navCtrl.push('CoreSharedFilesChooseSitePage', { filePath: filePath, isInbox: isInbox }); + } + + /** + * Whether the user is already choosing a site to store a shared file. + * + * @return {boolean} Whether the user is already choosing a site to store a shared file. + */ + protected isChoosingSite(): boolean { + const navCtrl = this.appProvider.getRootNavController(); + + return navCtrl && navCtrl.getActive().id == 'CoreSharedFilesChooseSitePage'; } /** @@ -115,34 +127,62 @@ export class CoreSharedFilesHelperProvider { }); } + /** + * Delete a shared file. + * + * @param {any} fileEntry The file entry to delete. + * @param {boolean} [isInbox] Whether the file is in the Inbox folder. + * @return {Promise} Promise resolved when done. + */ + protected removeSharedFile(fileEntry: any, isInbox?: boolean): Promise { + if (isInbox) { + return this.sharedFilesProvider.deleteInboxFile(fileEntry); + } else { + return this.fileProvider.removeFileByFileEntry(fileEntry); + } + } + /** * Checks if there is a new file received in iOS and move it to the shared folder of current site. * If more than one site is found, the user will have to choose the site where to store it in. * If more than one file is found, treat only the first one. * + * @param {string} [path] Path to a file received when launching the app. * @return {Promise} Promise resolved when done. */ - searchIOSNewSharedFiles(): Promise { + searchIOSNewSharedFiles(path?: string): Promise { return this.initDelegate.ready().then(() => { - const navCtrl = this.appProvider.getRootNavController(); - if (navCtrl && navCtrl.getActive().id == 'CoreSharedFilesChooseSite') { + if (this.isChoosingSite()) { // We're already treating a shared file. Abort. return Promise.reject(null); } - return this.sharedFilesProvider.checkIOSNewFiles().then((fileEntry) => { + let promise; + if (path) { + // The app was launched with the path to the file, get the file. + promise = this.fileProvider.getExternalFile(path); + } else { + // No path received, search if there is any file in the Inbox folder. + promise = this.sharedFilesProvider.checkIOSNewFiles(); + } + + return promise.then((fileEntry) => { return this.sitesProvider.getSitesIds().then((siteIds) => { if (!siteIds.length) { // No sites stored, show error and delete the file. this.domUtils.showErrorModal('core.sharedfiles.errorreceivefilenosites', true); - return this.sharedFilesProvider.deleteInboxFile(fileEntry); + return this.removeSharedFile(fileEntry, !path); } else if (siteIds.length == 1) { - return this.storeSharedFileInSite(fileEntry, siteIds[0]); - } else { - this.goToChooseSite(fileEntry.fullPath); + return this.storeSharedFileInSite(fileEntry, siteIds[0], !path); + } else if (!this.isChoosingSite()) { + this.goToChooseSite(fileEntry.toURL(), !path); } }); + }).catch((error) => { + if (error) { + this.logger.error('Error searching iOS new shared files', error, path); + } }); }); } @@ -152,16 +192,17 @@ export class CoreSharedFilesHelperProvider { * * @param {any} fileEntry Shared file entry. * @param {string} [siteId] Site ID. If not defined, current site. + * @param {boolean} [isInbox] Whether the file is in the Inbox folder. * @return {Promise} Promise resolved when done. */ - storeSharedFileInSite(fileEntry: any, siteId?: string): Promise { + storeSharedFileInSite(fileEntry: any, siteId?: string, isInbox?: boolean): Promise { siteId = siteId || this.sitesProvider.getCurrentSiteId(); // First of all check if there's already a file with the same name in the shared files folder. const sharedFilesDirPath = this.sharedFilesProvider.getSiteSharedFilesDirPath(siteId); return this.fileProvider.getUniqueNameInFolder(sharedFilesDirPath, fileEntry.name).then((newName) => { - if (newName == fileEntry.name) { + if (newName.toLowerCase() == fileEntry.name.toLowerCase()) { // No file with the same name. Use the original file name. return newName; } else { @@ -172,7 +213,7 @@ export class CoreSharedFilesHelperProvider { return this.sharedFilesProvider.storeFileInSite(fileEntry, name, siteId).catch((err) => { this.domUtils.showErrorModal(err || 'Error moving file.'); }).finally(() => { - this.sharedFilesProvider.deleteInboxFile(fileEntry); + this.removeSharedFile(fileEntry, isInbox); this.domUtils.showAlertTranslated('core.success', 'core.sharedfiles.successstorefile'); }); }); diff --git a/src/core/sharedfiles/providers/sharedfiles.ts b/src/core/sharedfiles/providers/sharedfiles.ts index 1cf41d80f..407c572ae 100644 --- a/src/core/sharedfiles/providers/sharedfiles.ts +++ b/src/core/sharedfiles/providers/sharedfiles.ts @@ -229,7 +229,7 @@ export class CoreSharedFilesProvider { // Create dir if it doesn't exist already. return this.fileProvider.createDir(sharedFilesFolder).then(() => { - return this.fileProvider.moveFile(entry.fullPath, newPath).then((newFile) => { + return this.fileProvider.moveExternalFile(entry.toURL(), newPath).then((newFile) => { this.eventsProvider.trigger(CoreEventsProvider.FILE_SHARED, { siteId: siteId, name: newName }); return newFile; diff --git a/src/core/sharedfiles/sharedfiles.module.ts b/src/core/sharedfiles/sharedfiles.module.ts index d82b98e79..82c41169a 100644 --- a/src/core/sharedfiles/sharedfiles.module.ts +++ b/src/core/sharedfiles/sharedfiles.module.ts @@ -18,6 +18,7 @@ import { CoreSharedFilesProvider } from './providers/sharedfiles'; import { CoreSharedFilesHelperProvider } from './providers/helper'; import { CoreSharedFilesUploadHandler } from './providers/upload-handler'; import { CoreFileUploaderDelegate } from '@core/fileuploader/providers/delegate'; +import { CoreEventsProvider } from '@providers/events'; // List of providers (without handlers). export const CORE_SHAREDFILES_PROVIDERS: any[] = [ @@ -38,7 +39,7 @@ export const CORE_SHAREDFILES_PROVIDERS: any[] = [ }) export class CoreSharedFilesModule { constructor(platform: Platform, delegate: CoreFileUploaderDelegate, handler: CoreSharedFilesUploadHandler, - helper: CoreSharedFilesHelperProvider) { + helper: CoreSharedFilesHelperProvider, eventsProvider: CoreEventsProvider) { // Register the handler. delegate.registerHandler(handler); @@ -48,6 +49,13 @@ export class CoreSharedFilesModule { platform.resume.subscribe(() => { helper.searchIOSNewSharedFiles(); }); + + eventsProvider.on(CoreEventsProvider.APP_LAUNCHED_URL, (url) => { + if (url && url.indexOf('file://') === 0) { + // We received a file in iOS, it's probably a shared file. Treat it. + helper.searchIOSNewSharedFiles(url); + } + }); } } } diff --git a/src/providers/file.ts b/src/providers/file.ts index 08d4139ec..579a7745f 100644 --- a/src/providers/file.ts +++ b/src/providers/file.ts @@ -1052,7 +1052,7 @@ export class CoreFileProvider { // Index the files by name. entries.forEach((entry) => { - files[entry.name] = entry; + files[entry.name.toLowerCase()] = entry; }); // Format extension. @@ -1063,7 +1063,7 @@ export class CoreFileProvider { } newName = fileNameWithoutExtension + extension; - if (typeof files[newName] == 'undefined') { + if (typeof files[newName.toLowerCase()] == 'undefined') { // No file with the same name. return newName; } else { diff --git a/src/providers/utils/mimetype.ts b/src/providers/utils/mimetype.ts index 9df797d94..7ec3c895f 100644 --- a/src/providers/utils/mimetype.ts +++ b/src/providers/utils/mimetype.ts @@ -455,7 +455,7 @@ export class CoreMimetypeUtilsProvider { if (position > -1) { // Check extension corresponds to a mimetype to know if it's valid. - extension = path.substr(position + 1); + extension = path.substr(position + 1).toLowerCase(); if (typeof this.getMimeType(extension) != 'undefined') { return path.substr(0, position); // Remove extension. } diff --git a/upgrade.txt b/upgrade.txt index 86e4a9132..695c38d0f 100644 --- a/upgrade.txt +++ b/upgrade.txt @@ -9,6 +9,7 @@ information provided here is intended especially for developers. - Use of completionstatus on the module object has been deprecated, use completiondata instead. - The function CoreSitesProvider.loadSite has changed, now it will trigger SESSION_EXPIRED event if the site is logged out. Its params and return value have changed. - When using CoreDomUtils.showAlert, please use alert.didDismiss.subscribe() instead of alert.onDidDismiss(). +- The page CoreSharedFilesChooseSitePage now expects to receive the full path to the file (file.toURL()) instead of the relative path. - The following strings have been deprecated: core.dfdaymonthyear. Please use core.strftimedatefullshort instead. core.dfdayweekmonth. Please use core.strftimedayshort instead.