MOBILE-2795 ios: Handle files shared through iCloud

main
Dani Palou 2019-01-10 13:18:04 +01:00
parent 144163ced7
commit 971aebd658
7 changed files with 72 additions and 20 deletions

View File

@ -35,11 +35,13 @@ export class CoreSharedFilesChooseSitePage implements OnInit {
protected filePath: string; protected filePath: string;
protected fileEntry: any; protected fileEntry: any;
protected isInbox: boolean; // Whether the file is in the Inbox folder.
constructor(private navCtrl: NavController, navParams: NavParams, private sharedFilesHelper: CoreSharedFilesHelperProvider, constructor(private navCtrl: NavController, navParams: NavParams, private sharedFilesHelper: CoreSharedFilesHelperProvider,
private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider, private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider,
private fileProvider: CoreFileProvider) { private fileProvider: CoreFileProvider) {
this.filePath = navParams.get('filePath'); this.filePath = navParams.get('filePath');
this.isInbox = navParams.get('isInbox');
} }
/** /**
@ -57,7 +59,7 @@ export class CoreSharedFilesChooseSitePage implements OnInit {
this.fileName = fileAndDir.name; this.fileName = fileAndDir.name;
// Get the file. // Get the file.
this.fileProvider.getFile(this.filePath).then((fe) => { this.fileProvider.getExternalFile(this.filePath).then((fe) => {
this.fileEntry = fe; this.fileEntry = fe;
this.fileName = this.fileEntry.name; this.fileName = this.fileEntry.name;
}).catch(() => { }).catch(() => {
@ -80,7 +82,7 @@ export class CoreSharedFilesChooseSitePage implements OnInit {
*/ */
storeInSite(siteId: string): void { storeInSite(siteId: string): void {
this.loaded = false; this.loaded = false;
this.sharedFilesHelper.storeSharedFileInSite(this.fileEntry, siteId).then(() => { this.sharedFilesHelper.storeSharedFileInSite(this.fileEntry, siteId, this.isInbox).then(() => {
this.navCtrl.pop(); this.navCtrl.pop();
}).finally(() => { }).finally(() => {
this.loaded = true; this.loaded = true;

View File

@ -77,10 +77,22 @@ export class CoreSharedFilesHelperProvider {
* Go to the choose site view. * Go to the choose site view.
* *
* @param {string} filePath File path to send to the 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(); 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<any>} Promise resolved when done.
*/
protected removeSharedFile(fileEntry: any, isInbox?: boolean): Promise<any> {
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. * 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 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. * 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<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
searchIOSNewSharedFiles(): Promise<any> { searchIOSNewSharedFiles(path?: string): Promise<any> {
return this.initDelegate.ready().then(() => { return this.initDelegate.ready().then(() => {
const navCtrl = this.appProvider.getRootNavController(); if (this.isChoosingSite()) {
if (navCtrl && navCtrl.getActive().id == 'CoreSharedFilesChooseSite') {
// We're already treating a shared file. Abort. // We're already treating a shared file. Abort.
return Promise.reject(null); 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) => { return this.sitesProvider.getSitesIds().then((siteIds) => {
if (!siteIds.length) { if (!siteIds.length) {
// No sites stored, show error and delete the file. // No sites stored, show error and delete the file.
this.domUtils.showErrorModal('core.sharedfiles.errorreceivefilenosites', true); this.domUtils.showErrorModal('core.sharedfiles.errorreceivefilenosites', true);
return this.sharedFilesProvider.deleteInboxFile(fileEntry); return this.removeSharedFile(fileEntry, !path);
} else if (siteIds.length == 1) { } else if (siteIds.length == 1) {
return this.storeSharedFileInSite(fileEntry, siteIds[0]); return this.storeSharedFileInSite(fileEntry, siteIds[0], !path);
} else { } else if (!this.isChoosingSite()) {
this.goToChooseSite(fileEntry.fullPath); 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 {any} fileEntry Shared file entry.
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @param {boolean} [isInbox] Whether the file is in the Inbox folder.
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
storeSharedFileInSite(fileEntry: any, siteId?: string): Promise<any> { storeSharedFileInSite(fileEntry: any, siteId?: string, isInbox?: boolean): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId(); siteId = siteId || this.sitesProvider.getCurrentSiteId();
// First of all check if there's already a file with the same name in the shared files folder. // 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); const sharedFilesDirPath = this.sharedFilesProvider.getSiteSharedFilesDirPath(siteId);
return this.fileProvider.getUniqueNameInFolder(sharedFilesDirPath, fileEntry.name).then((newName) => { 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. // No file with the same name. Use the original file name.
return newName; return newName;
} else { } else {
@ -172,7 +213,7 @@ export class CoreSharedFilesHelperProvider {
return this.sharedFilesProvider.storeFileInSite(fileEntry, name, siteId).catch((err) => { return this.sharedFilesProvider.storeFileInSite(fileEntry, name, siteId).catch((err) => {
this.domUtils.showErrorModal(err || 'Error moving file.'); this.domUtils.showErrorModal(err || 'Error moving file.');
}).finally(() => { }).finally(() => {
this.sharedFilesProvider.deleteInboxFile(fileEntry); this.removeSharedFile(fileEntry, isInbox);
this.domUtils.showAlertTranslated('core.success', 'core.sharedfiles.successstorefile'); this.domUtils.showAlertTranslated('core.success', 'core.sharedfiles.successstorefile');
}); });
}); });

View File

@ -229,7 +229,7 @@ export class CoreSharedFilesProvider {
// Create dir if it doesn't exist already. // Create dir if it doesn't exist already.
return this.fileProvider.createDir(sharedFilesFolder).then(() => { 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 }); this.eventsProvider.trigger(CoreEventsProvider.FILE_SHARED, { siteId: siteId, name: newName });
return newFile; return newFile;

View File

@ -18,6 +18,7 @@ import { CoreSharedFilesProvider } from './providers/sharedfiles';
import { CoreSharedFilesHelperProvider } from './providers/helper'; import { CoreSharedFilesHelperProvider } from './providers/helper';
import { CoreSharedFilesUploadHandler } from './providers/upload-handler'; import { CoreSharedFilesUploadHandler } from './providers/upload-handler';
import { CoreFileUploaderDelegate } from '@core/fileuploader/providers/delegate'; import { CoreFileUploaderDelegate } from '@core/fileuploader/providers/delegate';
import { CoreEventsProvider } from '@providers/events';
// List of providers (without handlers). // List of providers (without handlers).
export const CORE_SHAREDFILES_PROVIDERS: any[] = [ export const CORE_SHAREDFILES_PROVIDERS: any[] = [
@ -38,7 +39,7 @@ export const CORE_SHAREDFILES_PROVIDERS: any[] = [
}) })
export class CoreSharedFilesModule { export class CoreSharedFilesModule {
constructor(platform: Platform, delegate: CoreFileUploaderDelegate, handler: CoreSharedFilesUploadHandler, constructor(platform: Platform, delegate: CoreFileUploaderDelegate, handler: CoreSharedFilesUploadHandler,
helper: CoreSharedFilesHelperProvider) { helper: CoreSharedFilesHelperProvider, eventsProvider: CoreEventsProvider) {
// Register the handler. // Register the handler.
delegate.registerHandler(handler); delegate.registerHandler(handler);
@ -48,6 +49,13 @@ export class CoreSharedFilesModule {
platform.resume.subscribe(() => { platform.resume.subscribe(() => {
helper.searchIOSNewSharedFiles(); 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);
}
});
} }
} }
} }

View File

@ -1052,7 +1052,7 @@ export class CoreFileProvider {
// Index the files by name. // Index the files by name.
entries.forEach((entry) => { entries.forEach((entry) => {
files[entry.name] = entry; files[entry.name.toLowerCase()] = entry;
}); });
// Format extension. // Format extension.
@ -1063,7 +1063,7 @@ export class CoreFileProvider {
} }
newName = fileNameWithoutExtension + extension; newName = fileNameWithoutExtension + extension;
if (typeof files[newName] == 'undefined') { if (typeof files[newName.toLowerCase()] == 'undefined') {
// No file with the same name. // No file with the same name.
return newName; return newName;
} else { } else {

View File

@ -455,7 +455,7 @@ export class CoreMimetypeUtilsProvider {
if (position > -1) { if (position > -1) {
// Check extension corresponds to a mimetype to know if it's valid. // 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') { if (typeof this.getMimeType(extension) != 'undefined') {
return path.substr(0, position); // Remove extension. return path.substr(0, position); // Remove extension.
} }

View File

@ -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. - 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. - 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(). - 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: - The following strings have been deprecated:
core.dfdaymonthyear. Please use core.strftimedatefullshort instead. core.dfdaymonthyear. Please use core.strftimedatefullshort instead.
core.dfdayweekmonth. Please use core.strftimedayshort instead. core.dfdayweekmonth. Please use core.strftimedayshort instead.