Merge pull request #3280 from dpalou/MOBILE-4054
MOBILE-4054 core: Allow not displaying again open file warningmain
commit
9fc6ae9b56
|
@ -127,7 +127,7 @@ export class CoreLocalFileComponent implements OnInit {
|
||||||
|
|
||||||
if (!CoreFileHelper.isOpenableInApp(this.file)) {
|
if (!CoreFileHelper.isOpenableInApp(this.file)) {
|
||||||
try {
|
try {
|
||||||
await CoreFileHelper.showConfirmOpenUnsupportedFile();
|
await CoreFileHelper.showConfirmOpenUnsupportedFile(false, this.file);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return; // Cancelled, stop.
|
return; // Cancelled, stop.
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ export class CoreLinkDirective implements OnInit {
|
||||||
|
|
||||||
if (!CoreFileHelper.isOpenableInApp({ filename })) {
|
if (!CoreFileHelper.isOpenableInApp({ filename })) {
|
||||||
try {
|
try {
|
||||||
await CoreFileHelper.showConfirmOpenUnsupportedFile();
|
await CoreFileHelper.showConfirmOpenUnsupportedFile(false, { filename });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return; // Cancelled, stop.
|
return; // Cancelled, stop.
|
||||||
}
|
}
|
||||||
|
|
|
@ -721,7 +721,7 @@ export class CoreCourseHelperProvider {
|
||||||
const mainFile = files[0];
|
const mainFile = files[0];
|
||||||
|
|
||||||
if (!CoreFileHelper.isOpenableInApp(mainFile)) {
|
if (!CoreFileHelper.isOpenableInApp(mainFile)) {
|
||||||
await CoreFileHelper.showConfirmOpenUnsupportedFile();
|
await CoreFileHelper.showConfirmOpenUnsupportedFile(false, mainFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
const site = await CoreSites.getSite(siteId);
|
const site = await CoreSites.getSite(siteId);
|
||||||
|
|
|
@ -28,6 +28,8 @@ import { CoreConstants } from '@/core/constants';
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError } from '@classes/errors/error';
|
||||||
import { makeSingleton, Translate } from '@singletons';
|
import { makeSingleton, Translate } from '@singletons';
|
||||||
import { CoreNetworkError } from '@classes/errors/network-error';
|
import { CoreNetworkError } from '@classes/errors/network-error';
|
||||||
|
import { CoreConfig } from './config';
|
||||||
|
import { CoreCanceledError } from '@classes/errors/cancelederror';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provider to provide some helper functions regarding files and packages.
|
* Provider to provide some helper functions regarding files and packages.
|
||||||
|
@ -71,7 +73,7 @@ export class CoreFileHelperProvider {
|
||||||
const timemodified = this.getFileTimemodified(file);
|
const timemodified = this.getFileTimemodified(file);
|
||||||
|
|
||||||
if (!this.isOpenableInApp(file)) {
|
if (!this.isOpenableInApp(file)) {
|
||||||
await this.showConfirmOpenUnsupportedFile();
|
await this.showConfirmOpenUnsupportedFile(false, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = await this.downloadFileIfNeeded(
|
let url = await this.downloadFileIfNeeded(
|
||||||
|
@ -413,13 +415,42 @@ export class CoreFileHelperProvider {
|
||||||
* Show a confirm asking the user if we wants to open the file.
|
* Show a confirm asking the user if we wants to open the file.
|
||||||
*
|
*
|
||||||
* @param onlyDownload Whether the user is only downloading the file, not opening it.
|
* @param onlyDownload Whether the user is only downloading the file, not opening it.
|
||||||
|
* @param file The file that will be opened.
|
||||||
* @return Promise resolved if confirmed, rejected otherwise.
|
* @return Promise resolved if confirmed, rejected otherwise.
|
||||||
*/
|
*/
|
||||||
showConfirmOpenUnsupportedFile(onlyDownload?: boolean): Promise<void> {
|
async showConfirmOpenUnsupportedFile(onlyDownload = false, file: {filename?: string; name?: string}): Promise<void> {
|
||||||
|
file = file || {}; // Just in case some plugin doesn't pass it. This can be removed in the future, @since app 4.1.
|
||||||
|
|
||||||
|
// Check if the user decided not to see the warning.
|
||||||
|
const regex = /(?:\.([^.]+))?$/;
|
||||||
|
const regexResult = regex.exec(file.filename || file.name || '');
|
||||||
|
|
||||||
|
const configKey = 'CoreFileUnsupportedWarningDisabled-' + (regexResult?.[1] ?? 'unknown');
|
||||||
|
const dontShowWarning = await CoreConfig.get(configKey, 0);
|
||||||
|
if (dontShowWarning) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const message = Translate.instant('core.cannotopeninapp' + (onlyDownload ? 'download' : ''));
|
const message = Translate.instant('core.cannotopeninapp' + (onlyDownload ? 'download' : ''));
|
||||||
const okButton = Translate.instant(onlyDownload ? 'core.downloadfile' : 'core.openfile');
|
const okButton = Translate.instant(onlyDownload ? 'core.downloadfile' : 'core.openfile');
|
||||||
|
|
||||||
return CoreDomUtils.showConfirm(message, undefined, okButton, undefined, { cssClass: 'core-modal-force-on-top' });
|
try {
|
||||||
|
const dontShowAgain = await CoreDomUtils.showPrompt(
|
||||||
|
message,
|
||||||
|
undefined,
|
||||||
|
Translate.instant('core.dontshowagain'),
|
||||||
|
'checkbox',
|
||||||
|
{ okText: okButton },
|
||||||
|
{ cssClass: 'core-modal-force-on-top' },
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dontShowAgain) {
|
||||||
|
CoreConfig.set(configKey, 1);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// User canceled.
|
||||||
|
throw new CoreCanceledError('');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1490,7 +1490,8 @@ export class CoreDomUtilsProvider {
|
||||||
* @param header Modal header.
|
* @param header Modal header.
|
||||||
* @param placeholderOrLabel Placeholder (for textual/numeric inputs) or label (for radio/checkbox). By default, "Password".
|
* @param placeholderOrLabel Placeholder (for textual/numeric inputs) or label (for radio/checkbox). By default, "Password".
|
||||||
* @param type Type of the input element. By default, password.
|
* @param type Type of the input element. By default, password.
|
||||||
* @param buttons Buttons. If not provided, OK and Cancel buttons will be displayed.
|
* @param buttons Buttons. If not provided or it's an object with texts, OK and Cancel buttons will be displayed.
|
||||||
|
* @para options Other alert options.
|
||||||
* @return Promise resolved with the input data (true for checkbox/radio) if the user clicks OK, rejected if cancels.
|
* @return Promise resolved with the input data (true for checkbox/radio) if the user clicks OK, rejected if cancels.
|
||||||
*/
|
*/
|
||||||
showPrompt(
|
showPrompt(
|
||||||
|
@ -1498,7 +1499,8 @@ export class CoreDomUtilsProvider {
|
||||||
header?: string,
|
header?: string,
|
||||||
placeholderOrLabel?: string,
|
placeholderOrLabel?: string,
|
||||||
type: TextFieldTypes | 'checkbox' | 'radio' | 'textarea' = 'password',
|
type: TextFieldTypes | 'checkbox' | 'radio' | 'textarea' = 'password',
|
||||||
buttons?: PromptButton[],
|
buttons?: PromptButton[] | { okText?: string; cancelText?: string },
|
||||||
|
options: AlertOptions = {},
|
||||||
): Promise<any> { // eslint-disable-line @typescript-eslint/no-explicit-any
|
): Promise<any> { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
placeholderOrLabel = placeholderOrLabel ?? Translate.instant('core.login.password');
|
placeholderOrLabel = placeholderOrLabel ?? Translate.instant('core.login.password');
|
||||||
|
@ -1517,21 +1519,19 @@ export class CoreDomUtilsProvider {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const options: AlertOptions = {
|
options.header = header;
|
||||||
header,
|
options.message = message;
|
||||||
message,
|
options.inputs = [
|
||||||
inputs: [
|
{
|
||||||
{
|
name: 'promptinput',
|
||||||
name: 'promptinput',
|
placeholder: placeholderOrLabel,
|
||||||
placeholder: placeholderOrLabel,
|
label: placeholderOrLabel,
|
||||||
label: placeholderOrLabel,
|
type,
|
||||||
type,
|
value: (isCheckbox || isRadio) ? true : undefined,
|
||||||
value: (isCheckbox || isRadio) ? true : undefined,
|
},
|
||||||
},
|
];
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
if (buttons?.length) {
|
if (Array.isArray(buttons) && buttons.length) {
|
||||||
options.buttons = buttons.map((button) => ({
|
options.buttons = buttons.map((button) => ({
|
||||||
...button,
|
...button,
|
||||||
handler: (data) => {
|
handler: (data) => {
|
||||||
|
@ -1549,14 +1549,14 @@ export class CoreDomUtilsProvider {
|
||||||
// Default buttons.
|
// Default buttons.
|
||||||
options.buttons = [
|
options.buttons = [
|
||||||
{
|
{
|
||||||
text: Translate.instant('core.cancel'),
|
text: buttons && 'cancelText' in buttons ? buttons.cancelText : Translate.instant('core.cancel'),
|
||||||
role: 'cancel',
|
role: 'cancel',
|
||||||
handler: () => {
|
handler: () => {
|
||||||
reject();
|
reject();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: Translate.instant('core.ok'),
|
text: buttons && 'okText' in buttons ? buttons.okText : Translate.instant('core.ok'),
|
||||||
handler: resolvePromise,
|
handler: resolvePromise,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -520,7 +520,7 @@ export class CoreIframeUtilsProvider {
|
||||||
|
|
||||||
if (!CoreFileHelper.isOpenableInApp({ filename })) {
|
if (!CoreFileHelper.isOpenableInApp({ filename })) {
|
||||||
try {
|
try {
|
||||||
await CoreFileHelper.showConfirmOpenUnsupportedFile();
|
await CoreFileHelper.showConfirmOpenUnsupportedFile(false, { filename });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return; // Cancelled, stop.
|
return; // Cancelled, stop.
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ export class CoreWindow {
|
||||||
|
|
||||||
if (!CoreFileHelper.isOpenableInApp({ filename })) {
|
if (!CoreFileHelper.isOpenableInApp({ filename })) {
|
||||||
try {
|
try {
|
||||||
await CoreFileHelper.showConfirmOpenUnsupportedFile();
|
await CoreFileHelper.showConfirmOpenUnsupportedFile(false, { filename });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return; // Cancelled, stop.
|
return; // Cancelled, stop.
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
@app @javascript
|
||||||
|
Feature: It opens files properly.
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given the following "users" exist:
|
||||||
|
| username |
|
||||||
|
| student1 |
|
||||||
|
And the following "courses" exist:
|
||||||
|
| fullname | shortname |
|
||||||
|
| Course 1 | C1 |
|
||||||
|
And the following "course enrolments" exist:
|
||||||
|
| user | course | role |
|
||||||
|
| student1 | C1 | student |
|
||||||
|
And the following "activities" exist:
|
||||||
|
| activity | name | intro | display | course | defaultfilename |
|
||||||
|
| resource | Test TXT | Test TXT description | 5 | C1 | A txt.txt |
|
||||||
|
| resource | Test RTF | Test RTF description | 5 | C1 | A rtf.rtf |
|
||||||
|
| resource | Test DOC | Test DOC description | 5 | C1 | A doc.doc |
|
||||||
|
And the following config values are set as admin:
|
||||||
|
| filetypeexclusionlist | rtf,doc | tool_mobile |
|
||||||
|
|
||||||
|
Scenario: Open a file
|
||||||
|
Given I entered the resource activity "Test TXT" on course "Course 1" as "student1" in the app
|
||||||
|
When I press "Open" near "Last modified" in the app
|
||||||
|
Then the app should have opened a browser tab with url "^blob:(first)?"
|
||||||
|
|
||||||
|
When I switch to the browser tab opened by the app
|
||||||
|
Then I should see "Test resource A txt.txt file"
|
||||||
|
|
||||||
|
When I close the browser tab opened by the app
|
||||||
|
And I press the back button in the app
|
||||||
|
And I press "Test RTF" in the app
|
||||||
|
And I press "Open" near "Last modified" in the app
|
||||||
|
Then I should find "This file may not work as expected on this device" in the app
|
||||||
|
|
||||||
|
When I press "Open file" in the app
|
||||||
|
Then the app should have opened a browser tab with url "^blob:(second)?"
|
||||||
|
|
||||||
|
When I switch to the browser tab opened by the app
|
||||||
|
Then I should see "Test resource A rtf.rtf file"
|
||||||
|
|
||||||
|
When I close the browser tab opened by the app
|
||||||
|
And I press "Open" near "Last modified" in the app
|
||||||
|
Then I should find "This file may not work as expected on this device" in the app
|
||||||
|
|
||||||
|
When I select "Don't show again." in the app
|
||||||
|
And I press "Open file" in the app
|
||||||
|
Then the app should have opened a browser tab with url "^blob:(third)?"
|
||||||
|
|
||||||
|
When I close the browser tab opened by the app
|
||||||
|
And I press "Open" near "Last modified" in the app
|
||||||
|
Then the app should have opened a browser tab with url "^blob:(fourth)?"
|
||||||
|
|
||||||
|
When I close the browser tab opened by the app
|
||||||
|
And I press the back button in the app
|
||||||
|
And I press "Test DOC" in the app
|
||||||
|
And I press "Open" in the app
|
||||||
|
Then I should find "This file may not work as expected on this device" in the app
|
Loading…
Reference in New Issue