commit
6d0d3248b1
248
package.json
248
package.json
|
@ -33,141 +33,141 @@
|
|||
"ionic:build:before": "gulp"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "^11.0.1",
|
||||
"@angular/common": "~10.0.0",
|
||||
"@angular/core": "~10.0.0",
|
||||
"@angular/forms": "~10.0.0",
|
||||
"@angular/platform-browser": "~10.0.0",
|
||||
"@angular/platform-browser-dynamic": "~10.0.0",
|
||||
"@angular/router": "~10.0.0",
|
||||
"@ionic-native/badge": "^5.33.0",
|
||||
"@ionic-native/camera": "^5.33.0",
|
||||
"@ionic-native/chooser": "^5.33.0",
|
||||
"@ionic-native/clipboard": "^5.33.0",
|
||||
"@ionic-native/core": "^5.33.0",
|
||||
"@ionic-native/device": "^5.33.0",
|
||||
"@ionic-native/diagnostic": "^5.33.0",
|
||||
"@ionic-native/file": "^5.33.0",
|
||||
"@ionic-native/file-opener": "^5.33.0",
|
||||
"@ionic-native/file-transfer": "^5.33.0",
|
||||
"@ionic-native/geolocation": "^5.33.0",
|
||||
"@ionic-native/http": "^5.33.0",
|
||||
"@ionic-native/in-app-browser": "^5.33.0",
|
||||
"@ionic-native/ionic-webview": "^5.33.0",
|
||||
"@ionic-native/keyboard": "^5.33.0",
|
||||
"@ionic-native/local-notifications": "^5.33.0",
|
||||
"@ionic-native/media": "^5.33.0",
|
||||
"@ionic-native/media-capture": "^5.33.0",
|
||||
"@ionic-native/network": "^5.33.0",
|
||||
"@ionic-native/push": "^5.33.0",
|
||||
"@ionic-native/qr-scanner": "^5.33.0",
|
||||
"@ionic-native/splash-screen": "^5.33.0",
|
||||
"@ionic-native/sqlite": "^5.33.0",
|
||||
"@ionic-native/status-bar": "^5.33.0",
|
||||
"@ionic-native/web-intent": "^5.33.0",
|
||||
"@ionic-native/zip": "^5.33.0",
|
||||
"@ionic/angular": "^5.6.6",
|
||||
"@ngx-translate/core": "^13.0.0",
|
||||
"@ngx-translate/http-loader": "^6.0.0",
|
||||
"@types/chart.js": "^2.9.31",
|
||||
"@angular/animations": "11.0.1",
|
||||
"@angular/common": "10.0.14",
|
||||
"@angular/core": "10.0.14",
|
||||
"@angular/forms": "10.0.14",
|
||||
"@angular/platform-browser": "10.0.14",
|
||||
"@angular/platform-browser-dynamic": "10.0.14",
|
||||
"@angular/router": "10.0.14",
|
||||
"@ionic-native/badge": "5.33.0",
|
||||
"@ionic-native/camera": "5.33.0",
|
||||
"@ionic-native/chooser": "5.33.0",
|
||||
"@ionic-native/clipboard": "5.33.0",
|
||||
"@ionic-native/core": "5.33.0",
|
||||
"@ionic-native/device": "5.33.0",
|
||||
"@ionic-native/diagnostic": "5.33.0",
|
||||
"@ionic-native/file": "5.33.0",
|
||||
"@ionic-native/file-opener": "5.33.0",
|
||||
"@ionic-native/file-transfer": "5.33.0",
|
||||
"@ionic-native/geolocation": "5.33.0",
|
||||
"@ionic-native/http": "5.33.0",
|
||||
"@ionic-native/in-app-browser": "5.33.0",
|
||||
"@ionic-native/ionic-webview": "5.33.0",
|
||||
"@ionic-native/keyboard": "5.33.0",
|
||||
"@ionic-native/local-notifications": "5.33.0",
|
||||
"@ionic-native/media": "5.33.0",
|
||||
"@ionic-native/media-capture": "5.33.0",
|
||||
"@ionic-native/network": "5.33.0",
|
||||
"@ionic-native/push": "5.33.0",
|
||||
"@ionic-native/qr-scanner": "5.33.0",
|
||||
"@ionic-native/splash-screen": "5.33.0",
|
||||
"@ionic-native/sqlite": "5.33.0",
|
||||
"@ionic-native/status-bar": "5.33.0",
|
||||
"@ionic-native/web-intent": "5.33.0",
|
||||
"@ionic-native/zip": "5.33.0",
|
||||
"@ionic/angular": "5.6.6",
|
||||
"@ngx-translate/core": "13.0.0",
|
||||
"@ngx-translate/http-loader": "6.0.0",
|
||||
"@types/chart.js": "2.9.31",
|
||||
"@types/cordova": "0.0.34",
|
||||
"@types/cordova-plugin-file-transfer": "^1.6.2",
|
||||
"@types/dom-mediacapture-record": "^1.0.7",
|
||||
"chart.js": "^2.9.4",
|
||||
"com-darryncampbell-cordova-plugin-intent": "^1.3.0",
|
||||
"cordova": "^10.0.0",
|
||||
"cordova-android": "^9.1.0",
|
||||
"cordova-android-support-gradle-release": "^3.0.1",
|
||||
"cordova-clipboard": "^1.3.0",
|
||||
"cordova-ios": "^6.2.0",
|
||||
"cordova-plugin-add-swift-support": "^2.0.2",
|
||||
"cordova-plugin-advanced-http": "^3.1.0",
|
||||
"cordova-plugin-badge": "^0.8.8",
|
||||
"cordova-plugin-camera": "^5.0.1",
|
||||
"cordova-plugin-chooser": "^1.3.2",
|
||||
"cordova-plugin-customurlscheme": "^5.0.2",
|
||||
"cordova-plugin-device": "^2.0.3",
|
||||
"cordova-plugin-file": "^6.0.2",
|
||||
"cordova-plugin-file-opener2": "^3.0.5",
|
||||
"@types/cordova-plugin-file-transfer": "1.6.2",
|
||||
"@types/dom-mediacapture-record": "1.0.7",
|
||||
"chart.js": "2.9.4",
|
||||
"com-darryncampbell-cordova-plugin-intent": "1.3.0",
|
||||
"cordova": "10.0.0",
|
||||
"cordova-android": "9.1.0",
|
||||
"cordova-android-support-gradle-release": "3.0.1",
|
||||
"cordova-clipboard": "1.3.0",
|
||||
"cordova-ios": "6.2.0",
|
||||
"cordova-plugin-add-swift-support": "2.0.2",
|
||||
"cordova-plugin-advanced-http": "3.1.0",
|
||||
"cordova-plugin-badge": "0.8.8",
|
||||
"cordova-plugin-camera": "5.0.1",
|
||||
"cordova-plugin-chooser": "1.3.2",
|
||||
"cordova-plugin-customurlscheme": "5.0.2",
|
||||
"cordova-plugin-device": "2.0.3",
|
||||
"cordova-plugin-file": "6.0.2",
|
||||
"cordova-plugin-file-opener2": "3.0.5",
|
||||
"cordova-plugin-file-transfer": "git+https://github.com/moodlemobile/cordova-plugin-file-transfer.git",
|
||||
"cordova-plugin-geolocation": "^4.1.0",
|
||||
"cordova-plugin-globalization": "^1.11.0",
|
||||
"cordova-plugin-inappbrowser": "^5.0.0",
|
||||
"cordova-plugin-ionic-keyboard": "^2.2.0",
|
||||
"cordova-plugin-ionic-webview": "^5.0.0",
|
||||
"cordova-plugin-geolocation": "4.1.0",
|
||||
"cordova-plugin-globalization": "1.11.0",
|
||||
"cordova-plugin-inappbrowser": "5.0.0",
|
||||
"cordova-plugin-ionic-keyboard": "2.2.0",
|
||||
"cordova-plugin-ionic-webview": "5.0.0",
|
||||
"cordova-plugin-local-notification": "git+https://github.com/moodlemobile/cordova-plugin-local-notification.git#moodle",
|
||||
"cordova-plugin-media": "^5.0.3",
|
||||
"cordova-plugin-media-capture": "^3.0.3",
|
||||
"cordova-plugin-network-information": "^2.0.2",
|
||||
"cordova-plugin-media": "5.0.3",
|
||||
"cordova-plugin-media-capture": "3.0.3",
|
||||
"cordova-plugin-network-information": "2.0.2",
|
||||
"cordova-plugin-qrscanner": "git+https://github.com/moodlemobile/cordova-plugin-qrscanner.git#dist",
|
||||
"cordova-plugin-screen-orientation": "^3.0.2",
|
||||
"cordova-plugin-splashscreen": "^6.0.0",
|
||||
"cordova-plugin-statusbar": "^2.4.3",
|
||||
"cordova-plugin-whitelist": "^1.3.4",
|
||||
"cordova-plugin-screen-orientation": "3.0.2",
|
||||
"cordova-plugin-splashscreen": "6.0.0",
|
||||
"cordova-plugin-statusbar": "2.4.3",
|
||||
"cordova-plugin-whitelist": "1.3.4",
|
||||
"cordova-plugin-wkuserscript": "git+https://github.com/moodlemobile/cordova-plugin-wkuserscript.git",
|
||||
"cordova-plugin-wkwebview-cookies": "git+https://github.com/moodlemobile/cordova-plugin-wkwebview-cookies.git",
|
||||
"cordova-plugin-zip": "^3.1.0",
|
||||
"cordova-sqlite-storage": "^6.0.0",
|
||||
"cordova-support-google-services": "^1.2.1",
|
||||
"cordova.plugins.diagnostic": "^5.0.2",
|
||||
"core-js": "^3.9.1",
|
||||
"es6-promise-plugin": "^4.2.2",
|
||||
"jszip": "^3.5.0",
|
||||
"cordova-plugin-zip": "3.1.0",
|
||||
"cordova-sqlite-storage": "6.0.0",
|
||||
"cordova-support-google-services": "1.3.2",
|
||||
"cordova.plugins.diagnostic": "5.0.2",
|
||||
"core-js": "3.9.1",
|
||||
"es6-promise-plugin": "4.2.2",
|
||||
"jszip": "3.5.0",
|
||||
"mathjax": "2.7.7",
|
||||
"moment": "^2.29.0",
|
||||
"nl.kingsquare.cordova.background-audio": "^1.0.1",
|
||||
"phonegap-plugin-multidex": "^1.0.0",
|
||||
"moment": "2.29.0",
|
||||
"nl.kingsquare.cordova.background-audio": "1.0.1",
|
||||
"phonegap-plugin-multidex": "1.0.0",
|
||||
"phonegap-plugin-push": "git+https://github.com/moodlemobile/phonegap-plugin-push.git#moodle-v3",
|
||||
"rxjs": "~6.5.5",
|
||||
"ts-md5": "^1.2.7",
|
||||
"tslib": "^2.0.0",
|
||||
"zone.js": "~0.10.3"
|
||||
"rxjs": "6.5.5",
|
||||
"ts-md5": "1.2.7",
|
||||
"tslib": "2.0.1",
|
||||
"zone.js": "0.10.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/architect": "^0.1101.2",
|
||||
"@angular-devkit/build-angular": "~0.1000.0",
|
||||
"@angular-eslint/builder": "^4.2.0",
|
||||
"@angular-eslint/eslint-plugin": "^4.2.0",
|
||||
"@angular-eslint/eslint-plugin-template": "^4.2.0",
|
||||
"@angular-eslint/schematics": "^4.2.0",
|
||||
"@angular-eslint/template-parser": "^4.2.0",
|
||||
"@angular/cli": "~10.0.5",
|
||||
"@angular/compiler": "~10.0.0",
|
||||
"@angular/compiler-cli": "~10.0.0",
|
||||
"@angular/language-service": "~10.0.0",
|
||||
"@ionic/angular-toolkit": "^2.3.0",
|
||||
"@ionic/cli": "^6.14.1",
|
||||
"@types/faker": "^5.1.3",
|
||||
"@types/node": "^12.12.64",
|
||||
"@types/resize-observer-browser": "^0.1.5",
|
||||
"@types/webpack-env": "^1.16.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
||||
"@typescript-eslint/parser": "^4.22.0",
|
||||
"check-es-compat": "^1.1.1",
|
||||
"@angular-devkit/architect": "0.1101.2",
|
||||
"@angular-devkit/build-angular": "0.1000.8",
|
||||
"@angular-eslint/builder": "4.2.0",
|
||||
"@angular-eslint/eslint-plugin": "4.2.0",
|
||||
"@angular-eslint/eslint-plugin-template": "4.2.0",
|
||||
"@angular-eslint/schematics": "4.2.0",
|
||||
"@angular-eslint/template-parser": "4.2.0",
|
||||
"@angular/cli": "10.0.8",
|
||||
"@angular/compiler": "10.0.14",
|
||||
"@angular/compiler-cli": "10.0.14",
|
||||
"@angular/language-service": "10.0.14",
|
||||
"@ionic/angular-toolkit": "2.3.3",
|
||||
"@ionic/cli": "6.14.1",
|
||||
"@types/faker": "5.1.3",
|
||||
"@types/node": "12.12.64",
|
||||
"@types/resize-observer-browser": "0.1.5",
|
||||
"@types/webpack-env": "1.16.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.22.0",
|
||||
"@typescript-eslint/parser": "4.22.0",
|
||||
"check-es-compat": "1.1.1",
|
||||
"cordova-plugin-prevent-override": "git+https://github.com/moodlemobile/cordova-plugin-prevent-override.git",
|
||||
"eslint": "^7.25.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-header": "^3.1.1",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-jest": "^24.3.6",
|
||||
"eslint-plugin-jsdoc": "^32.3.3",
|
||||
"eslint-plugin-prefer-arrow": "^1.2.3",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
"faker": "^5.1.0",
|
||||
"fs-extra": "^9.1.0",
|
||||
"eslint": "7.25.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-header": "3.1.1",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"eslint-plugin-jest": "24.3.6",
|
||||
"eslint-plugin-jsdoc": "32.3.3",
|
||||
"eslint-plugin-prefer-arrow": "1.2.3",
|
||||
"eslint-plugin-promise": "5.1.0",
|
||||
"faker": "5.1.0",
|
||||
"fs-extra": "9.1.0",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-clip-empty-files": "^0.1.2",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-flatten": "^0.4.0",
|
||||
"gulp-htmlmin": "^5.0.1",
|
||||
"gulp-rename": "^2.0.0",
|
||||
"gulp-slash": "^1.1.3",
|
||||
"jest": "^26.5.0",
|
||||
"jest-preset-angular": "^8.3.1",
|
||||
"jsonc-parser": "^2.3.1",
|
||||
"ts-jest": "^26.4.1",
|
||||
"ts-node": "~8.3.0",
|
||||
"typescript": "^3.9.9"
|
||||
"gulp-clip-empty-files": "0.1.2",
|
||||
"gulp-concat": "2.6.1",
|
||||
"gulp-flatten": "0.4.0",
|
||||
"gulp-htmlmin": "5.0.1",
|
||||
"gulp-rename": "2.0.0",
|
||||
"gulp-slash": "1.1.3",
|
||||
"jest": "26.5.2",
|
||||
"jest-preset-angular": "8.3.1",
|
||||
"jsonc-parser": "2.3.1",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-node": "8.3.0",
|
||||
"typescript": "3.9.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.x"
|
||||
|
@ -236,6 +236,6 @@
|
|||
}
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"keytar": "^7.2.0"
|
||||
"keytar": "7.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1993,6 +1993,7 @@
|
|||
"core.percentagenumber": "local_moodlemobileapp",
|
||||
"core.phone": "moodle",
|
||||
"core.pictureof": "moodle",
|
||||
"core.play": "local_moodlemobileapp",
|
||||
"core.previous": "moodle",
|
||||
"core.proceed": "moodle",
|
||||
"core.pulltorefresh": "local_moodlemobileapp",
|
||||
|
|
|
@ -40,6 +40,8 @@ export class AddonModFolderIndexPage extends CoreCourseModuleMainActivityPage<Ad
|
|||
super.ngOnInit();
|
||||
this.folderInstance = CoreNavigator.getRouteParam<AddonModFolderFolder>('folderInstance');
|
||||
this.subfolder = CoreNavigator.getRouteParam<AddonModFolderFolderFormattedData>('subfolder');
|
||||
|
||||
this.title = this.subfolder?.filename || this.module.name;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -259,6 +259,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
|||
forum: this.forum,
|
||||
},
|
||||
backdropDismiss: false,
|
||||
cssClass: 'core-modal-fullscreen',
|
||||
});
|
||||
|
||||
if (!modalData) {
|
||||
|
|
|
@ -47,11 +47,18 @@
|
|||
|
||||
<ng-container *ngIf="mode == 'external'">
|
||||
<ion-button expand="block" class="ion-margin" (click)="open(openFileAction.OPEN)">
|
||||
<ion-icon name="far-file" slot="start" aria-hidden="true"></ion-icon>
|
||||
{{ 'addon.mod_resource.openthefile' | translate }}
|
||||
<ng-container *ngIf="isStreamedFile">
|
||||
<ion-icon name="fas-play" slot="start" aria-hidden="true"></ion-icon>
|
||||
{{ 'core.play' | translate }}
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!isStreamedFile">
|
||||
<ion-icon name="far-file" slot="start" aria-hidden="true"></ion-icon>
|
||||
{{ 'addon.mod_resource.openthefile' | translate }}
|
||||
</ng-container>
|
||||
</ion-button>
|
||||
|
||||
<ion-button *ngIf="isIOS" expand="block" class="ion-margin" (click)="open(openFileAction.OPEN_WITH)">
|
||||
<ion-button *ngIf="isIOS && (!shouldOpenInBrowser || !isOnline)" expand="block" class="ion-margin"
|
||||
(click)="open(openFileAction.OPEN_WITH)">
|
||||
<ion-icon name="far-share-square" slot="start" aria-hidden="true"></ion-icon>
|
||||
{{ 'core.openwith' | translate }}
|
||||
</ion-button>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, OnInit, Optional } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit, Optional } from '@angular/core';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import {
|
||||
CoreCourseModuleMainResourceComponent,
|
||||
|
@ -21,10 +21,13 @@ 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 { CoreFileHelper } from '@services/file-helper';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUtils, OpenFileAction } from '@services/utils/utils';
|
||||
import { Translate } from '@singletons';
|
||||
import { Network, NgZone, Translate } from '@singletons';
|
||||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
AddonModResource,
|
||||
AddonModResourceCustomData,
|
||||
|
@ -40,7 +43,7 @@ import { AddonModResourceHelper } from '../../services/resource-helper';
|
|||
selector: 'addon-mod-resource-index',
|
||||
templateUrl: 'addon-mod-resource-index.html',
|
||||
})
|
||||
export class AddonModResourceIndexComponent extends CoreCourseModuleMainResourceComponent implements OnInit {
|
||||
export class AddonModResourceIndexComponent extends CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy {
|
||||
|
||||
component = AddonModResourceProvider.COMPONENT;
|
||||
|
||||
|
@ -52,19 +55,35 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
|
|||
warning = '';
|
||||
isIOS = false;
|
||||
openFileAction = OpenFileAction;
|
||||
isOnline = false;
|
||||
isStreamedFile = false;
|
||||
shouldOpenInBrowser = false;
|
||||
|
||||
protected onlineObserver?: Subscription;
|
||||
|
||||
constructor(@Optional() courseContentsPage?: CoreCourseContentsPage) {
|
||||
super('AddonModResourceIndexComponent', courseContentsPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
* @inheritdoc
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
super.ngOnInit();
|
||||
|
||||
this.canGetResource = AddonModResource.isGetResourceWSAvailable();
|
||||
this.isIOS = CoreApp.isIOS();
|
||||
this.isOnline = CoreApp.isOnline();
|
||||
|
||||
if (this.isIOS) {
|
||||
// Refresh online status when changes.
|
||||
this.onlineObserver = Network.onChange().subscribe(() => {
|
||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||
NgZone.run(() => {
|
||||
this.isOnline = CoreApp.isOnline();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
await this.loadContent();
|
||||
try {
|
||||
|
@ -76,19 +95,14 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
|
|||
}
|
||||
|
||||
/**
|
||||
* Perform the invalidate content function.
|
||||
*
|
||||
* @return Resolved when done.
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected async invalidateContent(): Promise<void> {
|
||||
return AddonModResource.invalidateContent(this.module.id, this.courseId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download resource contents.
|
||||
*
|
||||
* @param refresh Whether we're refreshing data.
|
||||
* @return Promise resolved when done.
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected async fetchContent(refresh?: boolean): Promise<void> {
|
||||
// Load module contents if needed. Passing refresh is needed to force reloading contents.
|
||||
|
@ -150,6 +164,14 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
|
|||
} else {
|
||||
this.mode = 'external';
|
||||
this.warning = '';
|
||||
|
||||
if (this.isIOS) {
|
||||
this.shouldOpenInBrowser = CoreFileHelper.shouldOpenInBrowser(this.module.contents[0]);
|
||||
}
|
||||
|
||||
const mimetype = await CoreUtils.getMimeTypeFromUrl(CoreFileHelper.getFileUrl(this.module.contents[0]));
|
||||
|
||||
this.isStreamedFile = CoreMimetypeUtils.isStreamedMimetype(mimetype);
|
||||
}
|
||||
} finally {
|
||||
this.fillContextMenu(refresh);
|
||||
|
@ -179,4 +201,12 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
|
|||
await CoreSites.getCurrentSite()?.openInBrowserWithAutoLoginIfSameSite(this.module.url!);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
super.ngOnDestroy();
|
||||
this.onlineObserver?.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
[canTrustDownload]="!alwaysDownload" (action)="download()" size="small">
|
||||
</core-download-refresh>
|
||||
|
||||
<ion-button fill="clear" *ngIf="isDownloaded && isIOS" (click)="openFile(true)" color="dark"
|
||||
<ion-button fill="clear" *ngIf="isDownloaded && isIOS" (click)="openFile($event, true)" color="dark"
|
||||
[title]="openButtonLabel | translate">
|
||||
<ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
|
|
|
@ -144,10 +144,14 @@ export class CoreFileComponent implements OnInit, OnDestroy {
|
|||
/**
|
||||
* Convenience function to open a file, downloading it if needed.
|
||||
*
|
||||
* @param ev Click event (if any).
|
||||
* @param isOpenButton Whether the open button was clicked.
|
||||
* @return Promise resolved when file is opened.
|
||||
*/
|
||||
openFile(isOpenButton = false): Promise<void> {
|
||||
openFile(ev?: Event, isOpenButton = false): Promise<void> {
|
||||
ev?.preventDefault();
|
||||
ev?.stopPropagation();
|
||||
|
||||
const options: CoreUtilsOpenFileOptions = {};
|
||||
if (isOpenButton) {
|
||||
// Use the non-default method.
|
||||
|
|
|
@ -117,7 +117,7 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck {
|
|||
// eslint-disable-next-line @angular-eslint/no-conflicting-lifecycle
|
||||
async ngOnChanges(changes: Record<string, SimpleChange>): Promise<void> {
|
||||
// Only compile if text/javascript has changed or the forceCompile flag has been set to true.
|
||||
if (this.text && (changes.text || changes.javascript ||
|
||||
if (this.text !== undefined && (changes.text || changes.javascript ||
|
||||
(changes.forceCompile && CoreUtils.isTrueOrOne(this.forceCompile)))) {
|
||||
|
||||
// Create a new component and a new module.
|
||||
|
|
|
@ -681,21 +681,29 @@ export class CoreCourseHelperProvider {
|
|||
throw new CoreError(Translate.instant('core.filenotfound'));
|
||||
}
|
||||
|
||||
if (!CoreFileHelper.isOpenableInApp(module.contents[0])) {
|
||||
const mainFile = files[0];
|
||||
|
||||
if (!CoreFileHelper.isOpenableInApp(mainFile)) {
|
||||
await CoreFileHelper.showConfirmOpenUnsupportedFile();
|
||||
}
|
||||
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
const mainFile = files[0];
|
||||
|
||||
// Check if the file should be opened in browser.
|
||||
if (CoreFileHelper.shouldOpenInBrowser(mainFile)) {
|
||||
return this.openModuleFileInBrowser(mainFile.fileurl, site, module, courseId, component, componentId, files);
|
||||
return this.openModuleFileInBrowser(mainFile.fileurl, site, module, courseId, component, componentId, files, options);
|
||||
}
|
||||
|
||||
// File shouldn't be opened in browser. Download the module if it needs to be downloaded.
|
||||
const result = await this.downloadModuleWithMainFileIfNeeded(module, courseId, component || '', componentId, files, siteId);
|
||||
const result = await this.downloadModuleWithMainFileIfNeeded(
|
||||
module,
|
||||
courseId,
|
||||
component || '',
|
||||
componentId,
|
||||
files,
|
||||
siteId,
|
||||
options,
|
||||
);
|
||||
|
||||
if (CoreUrlUtils.isLocalFileUrl(result.path)) {
|
||||
return CoreUtils.openFile(result.path, options);
|
||||
|
@ -740,6 +748,7 @@ export class CoreCourseHelperProvider {
|
|||
* @param component The component to link the files to.
|
||||
* @param componentId An ID to use in conjunction with the component.
|
||||
* @param files List of files of the module. If not provided, use module.contents.
|
||||
* @param options Options to open the file. Only used if not opened in browser.
|
||||
* @return Resolved on success.
|
||||
*/
|
||||
protected async openModuleFileInBrowser(
|
||||
|
@ -750,6 +759,7 @@ export class CoreCourseHelperProvider {
|
|||
component?: string,
|
||||
componentId?: string | number,
|
||||
files?: CoreCourseModuleContentFile[],
|
||||
options: CoreUtilsOpenFileOptions = {},
|
||||
): Promise<void> {
|
||||
if (!CoreApp.isOnline()) {
|
||||
// Not online, get the offline file. It will fail if not found.
|
||||
|
@ -760,7 +770,7 @@ export class CoreCourseHelperProvider {
|
|||
throw new CoreNetworkError();
|
||||
}
|
||||
|
||||
return CoreUtils.openFile(path);
|
||||
return CoreUtils.openFile(path, options);
|
||||
}
|
||||
|
||||
// Open in browser.
|
||||
|
@ -791,6 +801,7 @@ export class CoreCourseHelperProvider {
|
|||
* @param componentId An ID to use in conjunction with the component.
|
||||
* @param files List of files of the module. If not provided, use module.contents.
|
||||
* @param siteId The site ID. If not defined, current site.
|
||||
* @param options Options to open the file.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
async downloadModuleWithMainFileIfNeeded(
|
||||
|
@ -800,6 +811,7 @@ export class CoreCourseHelperProvider {
|
|||
componentId?: string | number,
|
||||
files?: CoreCourseModuleContentFile[],
|
||||
siteId?: string,
|
||||
options: CoreUtilsOpenFileOptions = {},
|
||||
): Promise<{ fixedUrl: string; path: string; status?: string }> {
|
||||
|
||||
siteId = siteId || CoreSites.getCurrentSiteId();
|
||||
|
@ -840,7 +852,17 @@ export class CoreCourseHelperProvider {
|
|||
}
|
||||
|
||||
if (!path) {
|
||||
path = await this.downloadModuleWithMainFile(module, courseId, fixedUrl, files, status, component, componentId, siteId);
|
||||
path = await this.downloadModuleWithMainFile(
|
||||
module,
|
||||
courseId,
|
||||
fixedUrl,
|
||||
files,
|
||||
status,
|
||||
component,
|
||||
componentId,
|
||||
siteId,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -862,6 +884,7 @@ export class CoreCourseHelperProvider {
|
|||
* @param component The component to link the files to.
|
||||
* @param componentId An ID to use in conjunction with the component.
|
||||
* @param siteId The site ID. If not defined, current site.
|
||||
* @param options Options to open the file.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async downloadModuleWithMainFile(
|
||||
|
@ -873,6 +896,7 @@ export class CoreCourseHelperProvider {
|
|||
component?: string,
|
||||
componentId?: string | number,
|
||||
siteId?: string,
|
||||
options: CoreUtilsOpenFileOptions = {},
|
||||
): Promise<string> {
|
||||
siteId = siteId || CoreSites.getCurrentSiteId();
|
||||
|
||||
|
@ -885,7 +909,7 @@ export class CoreCourseHelperProvider {
|
|||
throw new CoreNetworkError();
|
||||
}
|
||||
|
||||
const shouldDownloadFirst = await CoreFilepool.shouldDownloadFileBeforeOpen(fixedUrl, mainFile.filesize);
|
||||
const shouldDownloadFirst = await CoreFilepool.shouldDownloadFileBeforeOpen(fixedUrl, mainFile.filesize, options);
|
||||
|
||||
if (shouldDownloadFirst) {
|
||||
// Download and then return the local URL.
|
||||
|
|
|
@ -46,7 +46,7 @@ export class CoreSitePluginsMainMenuHomeHandler extends CoreSitePluginsBaseHandl
|
|||
return {
|
||||
title: this.title,
|
||||
class: this.handlerSchema.displaydata?.class,
|
||||
page: `siteplugins/${this.plugin.component}/${this.handlerSchema.method}/0`,
|
||||
page: `siteplugins/homecontent/${this.plugin.component}/${this.handlerSchema.method}`,
|
||||
pageParams: {
|
||||
title: this.title,
|
||||
initResult: this.initResult,
|
||||
|
|
|
@ -28,6 +28,13 @@ const routes: Routes = [
|
|||
},
|
||||
];
|
||||
|
||||
const homeRoutes: Routes = [
|
||||
{
|
||||
path: 'siteplugins/homecontent/:component/:method',
|
||||
loadChildren: () => import('./pages/plugin-page/plugin-page.module').then( m => m.CoreSitePluginsPluginPageModule),
|
||||
},
|
||||
];
|
||||
|
||||
const courseIndexRoutes: Routes = [
|
||||
{
|
||||
path: 'siteplugins/:handlerUniqueName',
|
||||
|
@ -47,7 +54,7 @@ const moduleRoutes: Routes = [
|
|||
imports: [
|
||||
CoreMainMenuTabRoutingModule.forChild(moduleRoutes.concat(routes)),
|
||||
CoreCourseIndexRoutingModule.forChild({ children: courseIndexRoutes }),
|
||||
CoreMainMenuHomeRoutingModule.forChild({ children: routes }),
|
||||
CoreMainMenuHomeRoutingModule.forChild({ children: homeRoutes }),
|
||||
CoreSitePluginsComponentsModule,
|
||||
],
|
||||
providers: [
|
||||
|
|
|
@ -225,6 +225,7 @@
|
|||
"percentagenumber": "{{$a}}%",
|
||||
"phone": "Phone",
|
||||
"pictureof": "Picture of {{$a}}",
|
||||
"play": "Play",
|
||||
"previous": "Previous",
|
||||
"proceed": "Proceed",
|
||||
"pulltorefresh": "Pull to refresh",
|
||||
|
|
|
@ -73,7 +73,17 @@ export class CoreFileHelperProvider {
|
|||
await this.showConfirmOpenUnsupportedFile();
|
||||
}
|
||||
|
||||
let url = await this.downloadFileIfNeeded(file, fileUrl, component, componentId, timemodified, state, onProgress, siteId);
|
||||
let url = await this.downloadFileIfNeeded(
|
||||
file,
|
||||
fileUrl,
|
||||
component,
|
||||
componentId,
|
||||
timemodified,
|
||||
state,
|
||||
onProgress,
|
||||
siteId,
|
||||
options,
|
||||
);
|
||||
|
||||
if (!url) {
|
||||
return;
|
||||
|
@ -127,6 +137,7 @@ export class CoreFileHelperProvider {
|
|||
* @param state The file's state. If not provided, it will be calculated.
|
||||
* @param onProgress Function to call on progress.
|
||||
* @param siteId The site ID. If not defined, current site.
|
||||
* @param options Options to open the file.
|
||||
* @return Resolved with the URL to use on success.
|
||||
*/
|
||||
protected async downloadFileIfNeeded(
|
||||
|
@ -138,6 +149,7 @@ export class CoreFileHelperProvider {
|
|||
state?: string,
|
||||
onProgress?: CoreFileHelperOnProgress,
|
||||
siteId?: string,
|
||||
options: CoreUtilsOpenFileOptions = {},
|
||||
): Promise<string> {
|
||||
siteId = siteId || CoreSites.getCurrentSiteId();
|
||||
|
||||
|
@ -172,7 +184,7 @@ export class CoreFileHelperProvider {
|
|||
onProgress({ calculating: true });
|
||||
}
|
||||
|
||||
const shouldDownloadFirst = await CoreFilepool.shouldDownloadFileBeforeOpen(fixedUrl, file.filesize || 0);
|
||||
const shouldDownloadFirst = await CoreFilepool.shouldDownloadFileBeforeOpen(fixedUrl, file.filesize || 0, options);
|
||||
if (shouldDownloadFirst) {
|
||||
// Download the file first.
|
||||
if (state == CoreConstants.DOWNLOADING) {
|
||||
|
|
|
@ -26,7 +26,7 @@ import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
|||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUtils, PromiseDefer } from '@services/utils/utils';
|
||||
import { CoreUtils, CoreUtilsOpenFileOptions, PromiseDefer } from '@services/utils/utils';
|
||||
import { SQLiteDB } from '@classes/sqlitedb';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
|
@ -2781,7 +2781,7 @@ export class CoreFilepoolProvider {
|
|||
|
||||
const mimetype = await CoreUtils.getMimeTypeFromUrl(url);
|
||||
// If the file is streaming (audio or video) we reject.
|
||||
if (mimetype.indexOf('video') != -1 || mimetype.indexOf('audio') != -1) {
|
||||
if (CoreMimetypeUtils.isStreamedMimetype(mimetype)) {
|
||||
throw new CoreError('File is audio or video.');
|
||||
}
|
||||
}
|
||||
|
@ -2791,6 +2791,7 @@ export class CoreFilepoolProvider {
|
|||
*
|
||||
* @param url File online URL.
|
||||
* @param size File size.
|
||||
* @param options Options.
|
||||
* @return Promise resolved with boolean: whether file should be downloaded before opening it.
|
||||
* @description
|
||||
* Convenience function to check if a file should be downloaded before opening it.
|
||||
|
@ -2800,16 +2801,21 @@ export class CoreFilepoolProvider {
|
|||
* - The file cannot be streamed.
|
||||
* If the file is big and can be streamed, the promise returned by this function will be rejected.
|
||||
*/
|
||||
async shouldDownloadFileBeforeOpen(url: string, size: number): Promise<boolean> {
|
||||
async shouldDownloadFileBeforeOpen(url: string, size: number, options: CoreUtilsOpenFileOptions = {}): Promise<boolean> {
|
||||
if (size >= 0 && size <= CoreFilepoolProvider.DOWNLOAD_THRESHOLD) {
|
||||
// The file is small, download it.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CoreUtils.shouldOpenWithDialog(options)) {
|
||||
// Open with dialog needs a local file.
|
||||
return true;
|
||||
}
|
||||
|
||||
const mimetype = await CoreUtils.getMimeTypeFromUrl(url);
|
||||
|
||||
// If the file is streaming (audio or video), return false.
|
||||
return mimetype.indexOf('video') == -1 && mimetype.indexOf('audio') == -1;
|
||||
return !CoreMimetypeUtils.isStreamedMimetype(mimetype);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -562,6 +562,16 @@ export class CoreMimetypeUtilsProvider {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a mimetype belongs to a file that can be streamed (audio, video).
|
||||
*
|
||||
* @param mimetype Mimetype.
|
||||
* @return Boolean.
|
||||
*/
|
||||
isStreamedMimetype(mimetype: string): boolean {
|
||||
return mimetype.indexOf('video') != -1 || mimetype.indexOf('audio') != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the extension from a path (if any).
|
||||
*
|
||||
|
|
|
@ -933,8 +933,7 @@ export class CoreUtilsProvider {
|
|||
}
|
||||
|
||||
try {
|
||||
const openFileAction = options.iOSOpenFileAction ?? CoreConstants.CONFIG.iOSDefaultOpenFileAction;
|
||||
if (CoreApp.isIOS() && openFileAction == OpenFileAction.OPEN_WITH) {
|
||||
if (this.shouldOpenWithDialog(options)) {
|
||||
await FileOpener.showOpenWithDialog(path, mimetype || '');
|
||||
} else {
|
||||
await FileOpener.open(path, mimetype || '');
|
||||
|
@ -1652,6 +1651,18 @@ export class CoreUtilsProvider {
|
|||
return this.wait(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given some options, check if a file should be opened with showOpenWithDialog.
|
||||
*
|
||||
* @param options Options.
|
||||
* @return Boolean.
|
||||
*/
|
||||
shouldOpenWithDialog(options: CoreUtilsOpenFileOptions = {}): boolean {
|
||||
const openFileAction = options.iOSOpenFileAction ?? CoreConstants.CONFIG.iOSDefaultOpenFileAction;
|
||||
|
||||
return CoreApp.isIOS() && openFileAction == OpenFileAction.OPEN_WITH;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const CoreUtils = makeSingleton(CoreUtilsProvider);
|
||||
|
|
Loading…
Reference in New Issue