diff --git a/scripts/langindex.json b/scripts/langindex.json
index af613b569..c2cbfdb35 100644
--- a/scripts/langindex.json
+++ b/scripts/langindex.json
@@ -1984,6 +1984,7 @@
"core.openmodinbrowser": "local_moodlemobileapp",
"core.opensecurityquestion": "local_moodlemobileapp",
"core.opensettings": "local_moodlemobileapp",
+ "core.openwith": "local_moodlemobileapp",
"core.othergroups": "group",
"core.pagea": "moodle",
"core.parentlanguage": "langconfig",
diff --git a/src/addons/mod/resource/components/index/addon-mod-resource-index.html b/src/addons/mod/resource/components/index/addon-mod-resource-index.html
index efddbf59d..da8328553 100644
--- a/src/addons/mod/resource/components/index/addon-mod-resource-index.html
+++ b/src/addons/mod/resource/components/index/addon-mod-resource-index.html
@@ -45,11 +45,16 @@
-
-
+
+
{{ 'addon.mod_resource.openthefile' | translate }}
-
+
+
+
+ {{ 'core.openwith' | translate }}
+
+
diff --git a/src/addons/mod/resource/components/index/index.ts b/src/addons/mod/resource/components/index/index.ts
index c6afd4d61..1245be191 100644
--- a/src/addons/mod/resource/components/index/index.ts
+++ b/src/addons/mod/resource/components/index/index.ts
@@ -20,9 +20,10 @@ import {
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
import { CoreCourse, CoreCourseWSModule } from '@features/course/services/course';
import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
+import { CoreApp } from '@services/app';
import { CoreSites } from '@services/sites';
import { CoreTextUtils } from '@services/utils/text';
-import { CoreUtils } from '@services/utils/utils';
+import { CoreUtils, OpenFileAction } from '@services/utils/utils';
import { Translate } from '@singletons';
import {
AddonModResource,
@@ -49,6 +50,8 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
contentText = '';
displayDescription = true;
warning = '';
+ isIOS = false;
+ openFileAction = OpenFileAction;
constructor(@Optional() courseContentsPage?: CoreCourseContentsPage) {
super('AddonModResourceIndexComponent', courseContentsPage);
@@ -61,6 +64,7 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
super.ngOnInit();
this.canGetResource = AddonModResource.isGetResourceWSAvailable();
+ this.isIOS = CoreApp.isIOS();
await this.loadContent();
try {
@@ -155,9 +159,10 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
/**
* Opens a file.
*
+ * @param iOSOpenFileAction Action to do in iOS.
* @return Promise resolved when done.
*/
- async open(): Promise {
+ async open(iOSOpenFileAction?: OpenFileAction): Promise {
let downloadable = await CoreCourseModulePrefetchDelegate.isModuleDownloadable(this.module, this.courseId);
if (downloadable) {
@@ -166,7 +171,7 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
downloadable = await AddonModResourceHelper.isMainFileDownloadable(this.module);
if (downloadable) {
- return AddonModResourceHelper.openModuleFile(this.module, this.courseId);
+ return AddonModResourceHelper.openModuleFile(this.module, this.courseId, { iOSOpenFileAction });
}
}
diff --git a/src/addons/mod/resource/lang.json b/src/addons/mod/resource/lang.json
index bd7e9cefb..2449d53e3 100644
--- a/src/addons/mod/resource/lang.json
+++ b/src/addons/mod/resource/lang.json
@@ -2,6 +2,6 @@
"errorwhileloadingthecontent": "Error while loading the content.",
"modifieddate": "Modified {{$a}}",
"modulenameplural": "Files",
- "openthefile": "Open the file",
+ "openthefile": "Open",
"uploadeddate": "Uploaded {{$a}}"
-}
\ No newline at end of file
+}
diff --git a/src/addons/mod/resource/services/handlers/module.ts b/src/addons/mod/resource/services/handlers/module.ts
index 24590f58a..672482df8 100644
--- a/src/addons/mod/resource/services/handlers/module.ts
+++ b/src/addons/mod/resource/services/handlers/module.ts
@@ -18,6 +18,7 @@ import { CoreCourse, CoreCourseAnyModuleData, CoreCourseModuleContentFile } from
import { CoreCourseModule } from '@features/course/services/course-helper';
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate';
import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
+import { CoreFileHelper } from '@services/file-helper';
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreTextUtils } from '@services/utils/text';
@@ -71,6 +72,7 @@ export class AddonModResourceModuleHandlerService implements CoreCourseModuleHan
handlerData.buttons![0].hidden = status !== CoreConstants.DOWNLOADED ||
AddonModResourceHelper.isDisplayedInIframe(module);
};
+ const openWithPicker = CoreFileHelper.defaultIsOpenWithPicker();
const handlerData: CoreCourseModuleHandlerData = {
icon: CoreCourse.getModuleIconSrc(this.modName, 'modicon' in module ? module.modicon : undefined),
@@ -88,8 +90,8 @@ export class AddonModResourceModuleHandlerService implements CoreCourseModuleHan
updateStatus: updateStatus.bind(this),
buttons: [{
hidden: true,
- icon: 'document',
- label: 'addon.mod_resource.openthefile',
+ icon: openWithPicker ? 'fas-share-square' : 'fas-file',
+ label: module.name + ': ' + Translate.instant(openWithPicker ? 'core.openwith' : 'addon.mod_resource.openthefile'),
action: async (event: Event, module: CoreCourseModule, courseId: number): Promise => {
const hide = await this.hideOpenButton(module, courseId);
if (!hide) {
diff --git a/src/addons/mod/resource/services/resource-helper.ts b/src/addons/mod/resource/services/resource-helper.ts
index 48d170947..f8ae97537 100644
--- a/src/addons/mod/resource/services/resource-helper.ts
+++ b/src/addons/mod/resource/services/resource-helper.ts
@@ -25,6 +25,7 @@ import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreTextUtils } from '@services/utils/text';
+import { CoreUtilsOpenFileOptions } from '@services/utils/utils';
import { makeSingleton } from '@singletons';
import { AddonModResource, AddonModResourceProvider } from './resource';
@@ -171,9 +172,10 @@ export class AddonModResourceHelperProvider {
*
* @param module Module where to get the contents.
* @param courseId Course Id, used for completion purposes.
+ * @param options Options to open the file.
* @return Resolved when done.
*/
- async openModuleFile(module: CoreCourseWSModule, courseId: number): Promise {
+ async openModuleFile(module: CoreCourseWSModule, courseId: number, options: CoreUtilsOpenFileOptions = {}): Promise {
const modal = await CoreDomUtils.showModalLoading();
try {
@@ -184,6 +186,8 @@ export class AddonModResourceHelperProvider {
AddonModResourceProvider.COMPONENT,
module.id,
module.contents,
+ undefined,
+ options,
);
try {
diff --git a/src/core/components/file/core-file.html b/src/core/components/file/core-file.html
index 7bfac250f..e58497f65 100644
--- a/src/core/components/file/core-file.html
+++ b/src/core/components/file/core-file.html
@@ -7,11 +7,16 @@
{{ fileSizeReadable }}
{{ timemodified * 1000 | coreFormatDate }}
-
+
+
+
+
+
diff --git a/src/core/components/file/file.ts b/src/core/components/file/file.ts
index 85874ef89..f33a1ee4c 100644
--- a/src/core/components/file/file.ts
+++ b/src/core/components/file/file.ts
@@ -21,7 +21,7 @@ import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreUrlUtils } from '@services/utils/url';
-import { CoreUtils } from '@services/utils/utils';
+import { CoreUtils, CoreUtilsOpenFileOptions, OpenFileAction } from '@services/utils/utils';
import { CoreTextUtils } from '@services/utils/text';
import { CoreConstants } from '@/core/constants';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
@@ -48,16 +48,21 @@ export class CoreFileComponent implements OnInit, OnDestroy {
@Output() onDelete: EventEmitter; // Will notify when the delete button is clicked.
isDownloading?: boolean;
+ isDownloaded?: boolean;
fileIcon?: string;
fileName!: string;
fileSizeReadable?: string;
state?: string;
timemodified!: number;
+ isIOS = false;
+ openButtonIcon = '';
+ openButtonLabel = '';
protected fileUrl!: string;
protected siteId?: string;
protected fileSize?: number;
protected observer?: CoreEventObserver;
+ protected defaultIsOpenWithPicker = false;
constructor() {
this.onDelete = new EventEmitter();
@@ -81,6 +86,11 @@ export class CoreFileComponent implements OnInit, OnDestroy {
this.fileSize = this.file.filesize;
this.fileName = this.file.filename || '';
+ this.isIOS = CoreApp.isIOS();
+ this.defaultIsOpenWithPicker = CoreFileHelper.defaultIsOpenWithPicker();
+ this.openButtonIcon = this.defaultIsOpenWithPicker ? 'fas-file' : 'fas-share-square';
+ this.openButtonLabel = this.defaultIsOpenWithPicker ? 'core.openfile' : 'core.openwith';
+
if (CoreUtils.isTrueOrOne(this.showSize) && this.fileSize && this.fileSize >= 0) {
this.fileSizeReadable = CoreTextUtils.bytesToSize(this.fileSize, 2);
}
@@ -128,20 +138,28 @@ export class CoreFileComponent implements OnInit, OnDestroy {
this.state = state;
this.isDownloading = this.canDownload && state === CoreConstants.DOWNLOADING;
+ this.isDownloaded = this.canDownload && CoreFileHelper.isStateDownloaded(state);
}
/**
* Convenience function to open a file, downloading it if needed.
*
+ * @param isOpenButton Whether the open button was clicked.
* @return Promise resolved when file is opened.
*/
- protected openFile(): Promise {
+ openFile(isOpenButton = false): Promise {
+ const options: CoreUtilsOpenFileOptions = {};
+ if (isOpenButton) {
+ // Use the non-default method.
+ options.iOSOpenFileAction = this.defaultIsOpenWithPicker ? OpenFileAction.OPEN : OpenFileAction.OPEN_WITH;
+ }
+
return CoreFileHelper.downloadAndOpenFile(this.file!, this.component, this.componentId, this.state, (event) => {
if (event && 'calculating' in event && event.calculating) {
// The process is calculating some data required for the download, show the spinner.
this.isDownloading = true;
}
- }).catch((error) => {
+ }, undefined, options).catch((error) => {
CoreDomUtils.showErrorModalDefault(error, 'core.errordownloading', true);
});
}
@@ -152,7 +170,7 @@ export class CoreFileComponent implements OnInit, OnDestroy {
* @param e Click event.
* @param openAfterDownload Whether the file should be opened after download.
*/
- async download(e?: Event, openAfterDownload: boolean = false): Promise {
+ async download(e?: Event, openAfterDownload = false): Promise {
e && e.preventDefault();
e && e.stopPropagation();
diff --git a/src/core/components/local-file/core-local-file.html b/src/core/components/local-file/core-local-file.html
index ed990252c..c558c7f7f 100644
--- a/src/core/components/local-file/core-local-file.html
+++ b/src/core/components/local-file/core-local-file.html
@@ -1,5 +1,5 @@