forked from EVOgeek/Vmeda.Online
		
	Merge pull request #3280 from dpalou/MOBILE-4054
MOBILE-4054 core: Allow not displaying again open file warning
This commit is contained in:
		
						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.
 | ||||||
|                 } |                 } | ||||||
|  | |||||||
							
								
								
									
										58
									
								
								src/tests/behat/open_files.feature
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/tests/behat/open_files.feature
									
									
									
									
									
										Normal file
									
								
							| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user