Merge pull request #2421 from dpalou/MOBILE-3401

Mobile 3401
main
Juan Leyva 2020-06-22 16:00:33 +02:00 committed by GitHub
commit 9269d558fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 104 additions and 83 deletions

View File

@ -106,17 +106,19 @@ export class CoreIframeComponent implements OnChanges {
if (changes.src) {
const url = this.urlUtils.getYoutubeEmbedUrl(changes.src.currentValue) || changes.src.currentValue;
if (this.platform.is('ios') && !this.urlUtils.isLocalFileUrl(url)) {
if (this.platform.is('ios') && url && !this.urlUtils.isLocalFileUrl(url)) {
// Save a "fake" cookie for the iframe's domain to fix a bug in WKWebView.
try {
const win = <WKWebViewCookiesWindow> window;
const urlParts = CoreUrl.parse(url);
if (urlParts.domain) {
await win.WKWebViewCookies.setCookie({
name: 'MoodleAppCookieForWKWebView',
value: '1',
domain: urlParts.domain,
});
}
} catch (err) {
// Ignore errors.
this.logger.error('Error setting cookie', err);

View File

@ -74,7 +74,7 @@ export class CoreFileUploaderFileHandler implements CoreFileUploaderHandler {
if (this.appProvider.isMobile()) {
handler.action = (maxSize?: number, upload?: boolean, allowOffline?: boolean, mimetypes?: string[]): Promise<any> => {
return this.uploaderHelper.chooseAndUploadFile(maxSize, upload, mimetypes).then((result) => {
return this.uploaderHelper.chooseAndUploadFile(maxSize, upload, allowOffline, mimetypes).then((result) => {
return {
treated: true,
result: result

View File

@ -60,9 +60,10 @@ export class CoreFileUploaderHelperProvider {
* @param maxSize Max size of the upload. -1 for no max size.
* @param upload True if the file should be uploaded, false to return the picked file.
* @param mimetypes List of supported mimetypes. If undefined, all mimetypes supported.
* @param allowOffline True to allow uploading in offline.
* @return Promise resolved when done.
*/
async chooseAndUploadFile(maxSize: number, upload?: boolean, mimetypes?: string[]): Promise<any> {
async chooseAndUploadFile(maxSize: number, upload?: boolean, allowOffline?: boolean, mimetypes?: string[]): Promise<any> {
const result = await this.fileChooser.getFile(mimetypes ? mimetypes.join(',') : undefined);
@ -76,9 +77,28 @@ export class CoreFileUploaderHelperProvider {
result.name = this.getChosenFileNameFromPath(result) || result.name;
}
// Verify that the mimetype is supported.
const error = this.fileUploaderProvider.isInvalidMimetype(mimetypes, result.name, result.mediaType);
if (error) {
return Promise.reject(error);
}
if (upload) {
const size = await this.fileProvider.getExternalFileSize(result.uri);
await this.confirmUploadFile(size, false, allowOffline);
const options = this.fileUploaderProvider.getFileUploadOptions(result.uri, result.name, result.mediaType, true);
return this.uploadFile(result.uri, maxSize, true, options);
} else {
const entry = await this.fileProvider.getExternalFile(result.uri);
entry.name = result.name; // In Android sometimes the file is exported with a different name, use the original one.
return entry;
}
}
/**
@ -664,15 +684,17 @@ export class CoreFileUploaderHelperProvider {
* @param name Name to use when uploading the file. If not defined, use the file's name.
* @return Promise resolved when done.
*/
uploadFileObject(file: any, maxSize?: number, upload?: boolean, allowOffline?: boolean, name?: string): Promise<any> {
async uploadFileObject(file: any, maxSize?: number, upload?: boolean, allowOffline?: boolean, name?: string): Promise<any> {
if (maxSize != -1 && file.size > maxSize) {
return this.errorMaxBytes(maxSize, file.name);
}
return this.confirmUploadFile(file.size, false, allowOffline).then(() => {
if (upload) {
await this.confirmUploadFile(file.size, false, allowOffline);
}
// We have the data of the file to be uploaded, but not its URL (needed). Create a copy of the file to upload it.
return this.copyAndUploadFile(file, upload, name);
});
}
/**

View File

@ -696,6 +696,18 @@ export class CoreFileProvider {
});
}
/**
* Calculate the size of a file.
*
* @param path Absolute path to the file.
* @return Promise to be resolved when the size is calculated.
*/
async getExternalFileSize(path: string): Promise<number> {
const fileEntry = await this.getExternalFile(path);
return this.getSize(fileEntry);
}
/**
* Removes a file that might be outside the app's folder.
*
@ -770,7 +782,7 @@ export class CoreFileProvider {
* @return Promise resolved when the entry is moved.
*/
moveDir(originalPath: string, newPath: string, destDirExists?: boolean): Promise<any> {
return this.moveFileOrDir(originalPath, newPath, true, destDirExists);
return this.copyOrMoveFileOrDir(originalPath, newPath, true, false, destDirExists);
}
/**
@ -783,47 +795,7 @@ export class CoreFileProvider {
* @return Promise resolved when the entry is moved.
*/
moveFile(originalPath: string, newPath: string, destDirExists?: boolean): Promise<any> {
return this.moveFileOrDir(originalPath, newPath, false, destDirExists);
}
/**
* Move a file/dir.
*
* @param originalPath Path to the file/dir to move.
* @param newPath New path of the file/dir.
* @param isDir Whether it's a dir or a file.
* @param destDirExists Set it to true if you know the directory where to put the file/dir exists. If false, the function will
* try to create it (slower).
* @return Promise resolved when the entry is moved.
*/
protected moveFileOrDir(originalPath: string, newPath: string, isDir?: boolean, destDirExists?: boolean): Promise<any> {
const moveFn = isDir ? this.file.moveDir.bind(this.file) : this.file.moveFile.bind(this.file);
return this.init().then(() => {
// Remove basePath if it's in the paths.
originalPath = this.removeStartingSlash(originalPath.replace(this.basePath, ''));
newPath = this.removeStartingSlash(newPath.replace(this.basePath, ''));
const newPathFileAndDir = this.getFileAndDirectoryFromPath(newPath);
if (newPathFileAndDir.directory && !destDirExists) {
// Create the target directory if it doesn't exist.
return this.createDir(newPathFileAndDir.directory);
}
}).then(() => {
return moveFn(this.basePath, originalPath, this.basePath, newPath).catch((error) => {
// The move can fail if the path has encoded characters. Try again if that's the case.
const decodedOriginal = decodeURI(originalPath),
decodedNew = decodeURI(newPath);
if (decodedOriginal != originalPath || decodedNew != newPath) {
return moveFn(this.basePath, decodedOriginal, this.basePath, decodedNew);
} else {
return Promise.reject(error);
}
});
});
return this.copyOrMoveFileOrDir(originalPath, newPath, false, false, destDirExists);
}
/**
@ -836,7 +808,7 @@ export class CoreFileProvider {
* @return Promise resolved when the entry is copied.
*/
copyDir(from: string, to: string, destDirExists?: boolean): Promise<any> {
return this.copyFileOrDir(from, to, true, destDirExists);
return this.copyOrMoveFileOrDir(from, to, true, true, destDirExists);
}
/**
@ -849,23 +821,35 @@ export class CoreFileProvider {
* @return Promise resolved when the entry is copied.
*/
copyFile(from: string, to: string, destDirExists?: boolean): Promise<any> {
return this.copyFileOrDir(from, to, false, destDirExists);
return this.copyOrMoveFileOrDir(from, to, false, true, destDirExists);
}
/**
* Copy a file or a directory.
* Copy or move a file or a directory.
*
* @param from Path to the file/dir to move.
* @param to New path of the file/dir.
* @param isDir Whether it's a dir or a file.
* @param copy Whether to copy. If false, it will move the file.
* @param destDirExists Set it to true if you know the directory where to put the file/dir exists. If false, the function will
* try to create it (slower).
* @return Promise resolved when the entry is copied.
*/
protected copyFileOrDir(from: string, to: string, isDir?: boolean, destDirExists?: boolean): Promise<any> {
const copyFn = isDir ? this.file.copyDir.bind(this.file) : this.file.copyFile.bind(this.file);
protected async copyOrMoveFileOrDir(from: string, to: string, isDir?: boolean, copy?: boolean, destDirExists?: boolean)
: Promise<Entry> {
const fileIsInAppFolder = this.isPathInAppFolder(from);
if (!fileIsInAppFolder) {
return this.copyOrMoveExternalFile(from, to, copy);
}
const moveCopyFn = copy ?
(isDir ? this.file.copyDir.bind(this.file) : this.file.copyFile.bind(this.file)) :
(isDir ? this.file.moveDir.bind(this.file) : this.file.moveFile.bind(this.file));
await this.init();
return this.init().then(() => {
// Paths cannot start with "/". Remove basePath if present.
from = this.removeStartingSlash(from.replace(this.basePath, ''));
to = this.removeStartingSlash(to.replace(this.basePath, ''));
@ -874,21 +858,24 @@ export class CoreFileProvider {
if (toFileAndDir.directory && !destDirExists) {
// Create the target directory if it doesn't exist.
return this.createDir(toFileAndDir.directory);
await this.createDir(toFileAndDir.directory);
}
}).then(() => {
return copyFn(this.basePath, from, this.basePath, to).catch((error) => {
try {
const entry = await moveCopyFn(this.basePath, from, this.basePath, to);
return entry;
} catch (error) {
// The copy can fail if the path has encoded characters. Try again if that's the case.
const decodedFrom = decodeURI(from),
decodedTo = decodeURI(to);
const decodedFrom = decodeURI(from);
const decodedTo = decodeURI(to);
if (from != decodedFrom || to != decodedTo) {
return copyFn(this.basePath, decodedFrom, this.basePath, decodedTo);
return moveCopyFn(this.basePath, decodedFrom, this.basePath, decodedTo);
} else {
return Promise.reject(error);
}
});
});
}
}
/**
@ -1281,6 +1268,16 @@ export class CoreFileProvider {
return src.replace(CoreConfigConstants.ioswebviewscheme + '://localhost/_app_file_', 'file://');
}
/**
* Check if a certain path is in the app's folder (basePath).
*
* @param path Path to check.
* @return Whether it's in the app folder.
*/
protected isPathInAppFolder(path: string): boolean {
return !path || !path.match(/^[a-z0-9]+:\/\//i) || path.indexOf(this.basePath) != -1;
}
}
export class CoreFile extends makeSingleton(CoreFileProvider) {}