From ec3a1bdb56a517fa39bd9502c887e27582dbb590 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Tue, 7 Apr 2020 12:22:47 +0200 Subject: [PATCH] MOBILE-3270 core: Fix upload files from Google Drive --- src/components/local-file/local-file.ts | 2 +- .../pages/capture-media/capture-media.ts | 21 ++++++++---- src/providers/file.ts | 33 ++++++++++++------- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/components/local-file/local-file.ts b/src/components/local-file/local-file.ts index c9f63ed17..cd0c573a3 100644 --- a/src/components/local-file/local-file.ts +++ b/src/components/local-file/local-file.ts @@ -78,7 +78,7 @@ export class CoreLocalFileComponent implements OnInit { this.size = this.textUtils.bytesToSize(metadata.size, 2); } - this.timemodified = this.timeUtils.userDate(metadata.modificationTime, 'core.strftimedatetimeshort'); + this.timemodified = this.timeUtils.userDate(metadata.modificationTime.getTime(), 'core.strftimedatetimeshort'); }); } diff --git a/src/core/emulator/pages/capture-media/capture-media.ts b/src/core/emulator/pages/capture-media/capture-media.ts index 77c1ec99e..89cbbbdab 100644 --- a/src/core/emulator/pages/capture-media/capture-media.ts +++ b/src/core/emulator/pages/capture-media/capture-media.ts @@ -18,6 +18,7 @@ import { CoreFileProvider } from '@providers/file'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTimeUtilsProvider } from '@providers/utils/time'; +import { MediaFile } from '@ionic-native/media-capture'; /** * Page to capture media in browser or desktop. @@ -364,13 +365,21 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy { if (this.isImage && !this.isCaptureImage) { this.dismissWithData(fileEntry.toURL()); } else { - // The capture plugin returns a MediaFile, not a FileEntry. - // The only difference is that it supports a new function that won't be supported in desktop. - fileEntry.getFormatData = (successFn, errorFn): any => { - // Nothing to do. - }; + // The capture plugin should return a MediaFile, not a FileEntry. Convert it. + return this.fileProvider.getMetadata(fileEntry).then((metadata) => { + const mediaFile: MediaFile = { + name: fileEntry.name, + fullPath: fileEntry.fullPath, + type: null, + lastModifiedDate: metadata.modificationTime, + size: metadata.size, + getFormatData: (successFn, errorFn): void => { + // Nothing to do. + } + }; - this.dismissWithData([fileEntry]); + this.dismissWithData([mediaFile]); + }); } }).catch((err) => { this.domUtils.showErrorModal(err); diff --git a/src/providers/file.ts b/src/providers/file.ts index 1bee27880..658560c42 100644 --- a/src/providers/file.ts +++ b/src/providers/file.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { Platform } from 'ionic-angular'; -import { File, FileEntry, DirectoryEntry } from '@ionic-native/file'; +import { File, FileEntry, DirectoryEntry, Entry, Metadata } from '@ionic-native/file'; import { CoreAppProvider } from './app'; import { CoreLoggerProvider } from './logger'; @@ -545,7 +545,7 @@ export class CoreFileProvider { reader.onloadend = (evt): void => { const target = evt.target; // Convert to to be able to use non-standard properties. - if (target.result !== undefined || target.result !== null) { + if (target.result !== undefined && target.result !== null) { if (format == CoreFileProvider.FORMATJSON) { // Convert to object. const parsed = this.textUtils.parseJSON(target.result, null); @@ -558,7 +558,7 @@ export class CoreFileProvider { } else { resolve(target.result); } - } else if (target.error !== undefined || target.error !== null) { + } else if (target.error !== undefined && target.error !== null) { reject(target.error); } else { reject({ code: null, message: 'READER_ONLOADEND_ERR' }); @@ -602,7 +602,7 @@ export class CoreFileProvider { * @param append Whether to append the data to the end of the file. * @return Promise to be resolved when the file is written. */ - writeFile(path: string, data: any, append?: boolean): Promise { + writeFile(path: string, data: any, append?: boolean): Promise { return this.init().then(() => { // Remove basePath if it's in the path. path = this.removeStartingSlash(path.replace(this.basePath, '')); @@ -635,15 +635,18 @@ export class CoreFileProvider { * @param append Whether to append the data to the end of the file. * @return Promise resolved when done. */ - writeFileDataInFile(file: any, path: string, onProgress?: (event: CoreFileProgressEvent) => any, offset: number = 0, - append?: boolean): Promise { + async writeFileDataInFile(file: Blob, path: string, onProgress?: (event: CoreFileProgressEvent) => void, offset: number = 0, + append?: boolean): Promise { offset = offset || 0; // Get the chunk to read. - const blob = file.slice(offset, Math.min(offset + this.CHUNK_SIZE, file.size)); + const readWholeFile = offset === 0 && this.CHUNK_SIZE >= file.size; + const chunk = readWholeFile ? file : file.slice(offset, Math.min(offset + this.CHUNK_SIZE, file.size)); + + try { + const fileEntry = await this.writeFileDataInFileChunk(chunk, path, append); - return this.writeFileDataInFileChunk(blob, path, append).then((fileEntry) => { offset += this.CHUNK_SIZE; onProgress && onProgress({ @@ -659,7 +662,15 @@ export class CoreFileProvider { // Read the next chunk. return this.writeFileDataInFile(file, path, onProgress, offset, true); - }); + } catch (error) { + if (readWholeFile || !error || error.name != 'NotReadableError') { + return Promise.reject(error); + } + + // Permission error when reading file in chunks. This usually happens with Google Drive files. + // Try to read the whole file at once. + return this.writeFileDataInFileChunk(file, path, false); + } } /** @@ -670,7 +681,7 @@ export class CoreFileProvider { * @param append Whether to append the data to the end of the file. * @return Promise resolved when done. */ - protected writeFileDataInFileChunk(chunkData: any, path: string, append?: boolean): Promise { + protected writeFileDataInFileChunk(chunkData: any, path: string, append?: boolean): Promise { // Read the chunk data. return this.readFileData(chunkData, CoreFileProvider.FORMATARRAYBUFFER).then((fileData) => { // Write the data in the file. @@ -1053,7 +1064,7 @@ export class CoreFileProvider { * @param fileEntry FileEntry retrieved from getFile or similar. * @return Promise resolved with metadata. */ - getMetadata(fileEntry: Entry): Promise { + getMetadata(fileEntry: Entry): Promise { if (!fileEntry || !fileEntry.getMetadata) { return Promise.reject(null); }