MOBILE-3932 resource: Display file info in resource index page
parent
5a2016cb67
commit
29e2119143
|
@ -909,6 +909,8 @@
|
|||
"addon.mod_resource.modifieddate": "resource",
|
||||
"addon.mod_resource.modulenameplural": "resource",
|
||||
"addon.mod_resource.openthefile": "local_moodlemobileapp",
|
||||
"addon.mod_resource.resourcestatusoutdated": "local_moodlemobileapp",
|
||||
"addon.mod_resource.resourcestatusoutdatedconfirm": "local_moodlemobileapp",
|
||||
"addon.mod_resource.uploadeddate": "resource",
|
||||
"addon.mod_scorm.asset": "scorm",
|
||||
"addon.mod_scorm.assetlaunched": "scorm",
|
||||
|
@ -1358,9 +1360,23 @@
|
|||
"assets.countries.ZA": "countries",
|
||||
"assets.countries.ZM": "countries",
|
||||
"assets.countries.ZW": "countries",
|
||||
"assets.mimetypes.application/dash_xml": "mimetypes",
|
||||
"assets.mimetypes.application/epub_zip": "mimetypes",
|
||||
"assets.mimetypes.application/json": "mimetypes",
|
||||
"assets.mimetypes.application/msword": "mimetypes",
|
||||
"assets.mimetypes.application/pdf": "mimetypes",
|
||||
"assets.mimetypes.application/vnd.google-apps.audio": "local_moodlemobileapp",
|
||||
"assets.mimetypes.application/vnd.google-apps.document": "local_moodlemobileapp",
|
||||
"assets.mimetypes.application/vnd.google-apps.drawing": "local_moodlemobileapp",
|
||||
"assets.mimetypes.application/vnd.google-apps.file": "local_moodlemobileapp",
|
||||
"assets.mimetypes.application/vnd.google-apps.folder": "local_moodlemobileapp",
|
||||
"assets.mimetypes.application/vnd.google-apps.form": "local_moodlemobileapp",
|
||||
"assets.mimetypes.application/vnd.google-apps.fusiontable": "local_moodlemobileapp",
|
||||
"assets.mimetypes.application/vnd.google-apps.presentation": "local_moodlemobileapp",
|
||||
"assets.mimetypes.application/vnd.google-apps.script": "local_moodlemobileapp",
|
||||
"assets.mimetypes.application/vnd.google-apps.site": "local_moodlemobileapp",
|
||||
"assets.mimetypes.application/vnd.google-apps.spreadsheet": "local_moodlemobileapp",
|
||||
"assets.mimetypes.application/vnd.google-apps.video": "local_moodlemobileapp",
|
||||
"assets.mimetypes.application/vnd.moodle.backup": "mimetypes",
|
||||
"assets.mimetypes.application/vnd.ms-excel": "mimetypes",
|
||||
"assets.mimetypes.application/vnd.ms-excel.sheet.macroEnabled.12": "mimetypes",
|
||||
|
@ -1379,6 +1395,7 @@
|
|||
"assets.mimetypes.application/x-iwork-numbers-sffnumbers": "mimetypes",
|
||||
"assets.mimetypes.application/x-iwork-pages-sffpages": "mimetypes",
|
||||
"assets.mimetypes.application/x-javascript": "mimetypes",
|
||||
"assets.mimetypes.application/x-mpegURL": "mimetypes",
|
||||
"assets.mimetypes.application/x-mspublisher": "mimetypes",
|
||||
"assets.mimetypes.application/x-shockwave-flash": "mimetypes",
|
||||
"assets.mimetypes.application/xhtml_xml": "mimetypes",
|
||||
|
@ -1393,6 +1410,8 @@
|
|||
"assets.mimetypes.group:html_track": "mimetypes",
|
||||
"assets.mimetypes.group:html_video": "mimetypes",
|
||||
"assets.mimetypes.group:image": "mimetypes",
|
||||
"assets.mimetypes.group:media_source": "mimetypes",
|
||||
"assets.mimetypes.group:optimised_image": "mimetypes",
|
||||
"assets.mimetypes.group:presentation": "mimetypes",
|
||||
"assets.mimetypes.group:sourcecode": "mimetypes",
|
||||
"assets.mimetypes.group:spreadsheet": "mimetypes",
|
||||
|
@ -1593,6 +1612,7 @@
|
|||
"core.custom": "form",
|
||||
"core.datastoredoffline": "local_moodlemobileapp",
|
||||
"core.date": "moodle",
|
||||
"core.datecreated": "repository",
|
||||
"core.day": "moodle",
|
||||
"core.days": "moodle",
|
||||
"core.decsep": "langconfig",
|
||||
|
@ -2208,6 +2228,7 @@
|
|||
"core.sitehome.sitehome": "moodle",
|
||||
"core.sitehome.sitenews": "moodle",
|
||||
"core.sitemaintenance": "admin",
|
||||
"core.size": "moodle",
|
||||
"core.sizeb": "moodle",
|
||||
"core.sizegb": "moodle",
|
||||
"core.sizekb": "moodle",
|
||||
|
@ -2262,6 +2283,7 @@
|
|||
"core.toggledelete": "local_moodlemobileapp",
|
||||
"core.tryagain": "local_moodlemobileapp",
|
||||
"core.twoparagraphs": "local_moodlemobileapp",
|
||||
"core.type": "repository",
|
||||
"core.uhoh": "local_moodlemobileapp",
|
||||
"core.unexpectederror": "local_moodlemobileapp",
|
||||
"core.unicodenotsupported": "local_moodlemobileapp",
|
||||
|
|
|
@ -42,22 +42,71 @@
|
|||
</div>
|
||||
|
||||
<ng-container *ngIf="mode == 'external'">
|
||||
<ion-button expand="block" class="ion-margin" (click)="open(openFileAction.OPEN)">
|
||||
<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-list>
|
||||
<ion-item class="ion-text-wrap" *ngIf="type">
|
||||
<ion-label>
|
||||
<h3>{{ 'core.type' | translate }}</h3>
|
||||
<p>{{ type }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<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>
|
||||
<ng-container *ngIf="!isExternalFile">
|
||||
<ion-item class="ion-text-wrap" *ngIf="readableSize">
|
||||
<ion-label>
|
||||
<h3>{{ 'core.size' | translate }}</h3>
|
||||
<p>{{ readableSize }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item class="ion-text-wrap" *ngIf="timecreated > 0">
|
||||
<ion-label>
|
||||
<h3>{{ 'core.datecreated' | translate }}</h3>
|
||||
<p>{{ timecreated | coreFormatDate }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item class="ion-text-wrap" *ngIf="timemodified > 0">
|
||||
<ion-label>
|
||||
<h3>{{ 'core.lastmodified' | translate }}</h3>
|
||||
<p>{{ timemodified | coreFormatDate }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item class="ion-text-wrap" *ngIf="downloadTimeReadable">
|
||||
<ion-label>
|
||||
<h3>{{ 'core.lastdownloaded' | translate }}</h3>
|
||||
<p>{{ downloadTimeReadable }}</p>
|
||||
<ion-grid *ngIf="prefetchStatus === outdatedStatus" class="addon-mod_resource-outdated">
|
||||
<ion-row class="ion-align-items-center">
|
||||
<ion-col size="auto">
|
||||
<ion-icon color="warning" name="fas-exclamation-triangle" aria-hidden="true"></ion-icon>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<p><strong>{{ 'addon.mod_resource.resourcestatusoutdated' | translate }}</strong></p>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
|
||||
<ion-button expand="block" class="ion-margin" (click)="open(openFileAction.OPEN)">
|
||||
<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 && (!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>
|
||||
</ion-list>
|
||||
</ng-container>
|
||||
</core-loading>
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
@import "~theme/globals";
|
||||
|
||||
:host {
|
||||
.addon-mod_resource-outdated {
|
||||
@include padding(4px, 0px, 0px, 0px);
|
||||
|
||||
ion-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import { Component, OnDestroy, OnInit, Optional } from '@angular/core';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { CoreCourseModuleMainResourceComponent } from '@features/course/classes/main-resource-component';
|
||||
|
@ -21,6 +22,7 @@ import { CoreCourseModulePrefetchDelegate } from '@features/course/services/modu
|
|||
import { CoreApp } from '@services/app';
|
||||
import { CoreFileHelper } from '@services/file-helper';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUtils, OpenFileAction } from '@services/utils/utils';
|
||||
|
@ -39,6 +41,7 @@ import { AddonModResourceHelper } from '../../services/resource-helper';
|
|||
@Component({
|
||||
selector: 'addon-mod-resource-index',
|
||||
templateUrl: 'addon-mod-resource-index.html',
|
||||
styleUrls: ['index.scss'],
|
||||
})
|
||||
export class AddonModResourceIndexComponent extends CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy {
|
||||
|
||||
|
@ -55,6 +58,14 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
|
|||
isStreamedFile = false;
|
||||
shouldOpenInBrowser = false;
|
||||
|
||||
// Variables for 'external' mode.
|
||||
type = '';
|
||||
readableSize = '';
|
||||
timecreated = -1;
|
||||
timemodified = -1;
|
||||
isExternalFile = false;
|
||||
outdatedStatus = CoreConstants.OUTDATED;
|
||||
|
||||
protected onlineObserver?: Subscription;
|
||||
|
||||
constructor(@Optional() courseContentsPage?: CoreCourseContentsPage) {
|
||||
|
@ -70,15 +81,13 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
|
|||
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();
|
||||
});
|
||||
// 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 {
|
||||
|
@ -153,13 +162,25 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
|
|||
} else {
|
||||
this.mode = 'external';
|
||||
this.warning = '';
|
||||
let mimetype: string;
|
||||
|
||||
if (this.isIOS) {
|
||||
this.shouldOpenInBrowser = CoreFileHelper.shouldOpenInBrowser(contents[0]);
|
||||
}
|
||||
|
||||
const mimetype = await CoreUtils.getMimeTypeFromUrl(CoreFileHelper.getFileUrl(contents[0]));
|
||||
if ('contentsinfo' in this.module && this.module.contentsinfo) {
|
||||
mimetype = this.module.contentsinfo.mimetypes[0];
|
||||
this.readableSize = CoreTextUtils.bytesToSize(this.module.contentsinfo.filessize, 1);
|
||||
this.timemodified = this.module.contentsinfo.lastmodified * 1000;
|
||||
} else {
|
||||
mimetype = await CoreUtils.getMimeTypeFromUrl(CoreFileHelper.getFileUrl(contents[0]));
|
||||
this.readableSize = CoreTextUtils.bytesToSize(contents[0].filesize, 1);
|
||||
this.timemodified = contents[0].timemodified * 1000;
|
||||
}
|
||||
|
||||
this.timecreated = contents[0].timecreated * 1000;
|
||||
this.isExternalFile = !!contents[0].isexternalfile;
|
||||
this.type = CoreMimetypeUtils.getMimetypeDescription(mimetype);
|
||||
this.isStreamedFile = CoreMimetypeUtils.isStreamedMimetype(mimetype);
|
||||
}
|
||||
} finally {
|
||||
|
@ -183,6 +204,16 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
|
|||
downloadable = await AddonModResourceHelper.isMainFileDownloadable(this.module);
|
||||
|
||||
if (downloadable) {
|
||||
if (this.prefetchStatus === CoreConstants.OUTDATED && !this.isOnline) {
|
||||
// Warn the user that the file isn't updated.
|
||||
const alert = await CoreDomUtils.showAlert(
|
||||
undefined,
|
||||
Translate.instant('addon.mod_resource.resourcestatusoutdated'),
|
||||
);
|
||||
|
||||
await alert.onWillDismiss();
|
||||
}
|
||||
|
||||
return AddonModResourceHelper.openModuleFile(this.module, this.courseId, { iOSOpenFileAction });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,5 +3,7 @@
|
|||
"modifieddate": "Modified {{$a}}",
|
||||
"modulenameplural": "Files",
|
||||
"openthefile": "Open",
|
||||
"resourcestatusoutdated": "This file has changed since you last opened it.",
|
||||
"resourcestatusoutdatedconfirm": "There is a newer version of this file. To see it, please connect your device to the internet.",
|
||||
"uploadeddate": "Uploaded {{$a}}"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,21 @@
|
|||
{
|
||||
"application/dash_xml": "Dynamic Adaptive Streaming over HTTP (MPEG-DASH)",
|
||||
"application/epub_zip": "EPUB ebook",
|
||||
"application/json": "{{$a.MIMETYPE2}} text",
|
||||
"application/msword": "Word document",
|
||||
"application/pdf": "PDF document",
|
||||
"application/vnd.google-apps.audio": "Google Drive audio",
|
||||
"application/vnd.google-apps.document": "Google Docs",
|
||||
"application/vnd.google-apps.drawing": "Google Drawing",
|
||||
"application/vnd.google-apps.file": "Google Drive file",
|
||||
"application/vnd.google-apps.folder": "Google Drive folder",
|
||||
"application/vnd.google-apps.form": "Google Forms",
|
||||
"application/vnd.google-apps.fusiontable": "Google Fusion Tables",
|
||||
"application/vnd.google-apps.presentation": "Google Slides",
|
||||
"application/vnd.google-apps.script": "Google Apps Scripts",
|
||||
"application/vnd.google-apps.site": "Google Sites",
|
||||
"application/vnd.google-apps.spreadsheet": "Google Sheets",
|
||||
"application/vnd.google-apps.video": "Google Drive video",
|
||||
"application/vnd.moodle.backup": "Moodle backup",
|
||||
"application/vnd.ms-excel": "Excel spreadsheet",
|
||||
"application/vnd.ms-excel.sheet.macroEnabled.12": "Excel 2007 macro-enabled workbook",
|
||||
|
@ -20,6 +34,7 @@
|
|||
"application/x-iwork-numbers-sffnumbers": "iWork Numbers spreadsheet",
|
||||
"application/x-iwork-pages-sffpages": "iWork Pages document",
|
||||
"application/x-javascript": "JavaScript source",
|
||||
"application/x-mpegURL": "HTTP Live Streaming (HLS)",
|
||||
"application/x-mspublisher": "Publisher document",
|
||||
"application/x-shockwave-flash": "Flash animation",
|
||||
"application/xhtml_xml": "XHTML document",
|
||||
|
@ -34,6 +49,8 @@
|
|||
"group:html_track": "HTML track files",
|
||||
"group:html_video": "Video files natively supported by browsers",
|
||||
"group:image": "Image files",
|
||||
"group:media_source": "Streaming media",
|
||||
"group:optimised_image": "Image files to be optimised, such as badges",
|
||||
"group:presentation": "Presentation files",
|
||||
"group:sourcecode": "Source code",
|
||||
"group:spreadsheet": "Spreadsheet files",
|
||||
|
@ -51,4 +68,4 @@
|
|||
"text/rtf": "RTF document",
|
||||
"text/vtt": "Web Video Text Track",
|
||||
"video": "Video file ({{$a.EXT}})"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
|
|||
prefetchStatus?: string; // Used when calling fillContextMenu.
|
||||
prefetchText?: string; // Used when calling fillContextMenu.
|
||||
size?: string; // Used when calling fillContextMenu.
|
||||
downloadTimeReadable?: string; // Last download time in a readable format. Used when calling fillContextMenu.
|
||||
isDestroyed = false; // Whether the component is destroyed, used when calling fillContextMenu.
|
||||
contextMenuStatusObserver?: CoreEventObserver; // Observer of package status, used when calling fillContextMenu.
|
||||
contextFileStatusObserver?: CoreEventObserver; // Observer of file status, used when calling fillContextMenu.
|
||||
|
|
|
@ -905,17 +905,30 @@ export class CoreCourseHelperProvider {
|
|||
}
|
||||
|
||||
if (!path) {
|
||||
path = await this.downloadModuleWithMainFile(
|
||||
module,
|
||||
courseId,
|
||||
fixedUrl,
|
||||
files,
|
||||
status,
|
||||
component,
|
||||
componentId,
|
||||
siteId,
|
||||
options,
|
||||
);
|
||||
try {
|
||||
path = await this.downloadModuleWithMainFile(
|
||||
module,
|
||||
courseId,
|
||||
fixedUrl,
|
||||
files,
|
||||
status,
|
||||
component,
|
||||
componentId,
|
||||
siteId,
|
||||
options,
|
||||
);
|
||||
} catch (error) {
|
||||
if (status !== CoreConstants.OUTDATED) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Use the local file even if it's outdated.
|
||||
try {
|
||||
path = await CoreFilepool.getInternalUrlByUrl(siteId, mainFile.fileurl);
|
||||
} catch {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -1056,6 +1069,7 @@ export class CoreCourseHelperProvider {
|
|||
instance.size = moduleInfo.sizeReadable;
|
||||
instance.prefetchStatusIcon = moduleInfo.statusIcon;
|
||||
instance.prefetchStatus = moduleInfo.status;
|
||||
instance.downloadTimeReadable = CoreTextUtils.ucFirst(moduleInfo.downloadTimeReadable);
|
||||
|
||||
if (moduleInfo.status != CoreConstants.NOT_DOWNLOADABLE) {
|
||||
// Module is downloadable, get the text to display to prefetch.
|
||||
|
@ -1478,6 +1492,8 @@ export class CoreCourseHelperProvider {
|
|||
// Currently, some modules pass invalidateCache=false because they already invalidate data in downloadResourceIfNeeded.
|
||||
// If this function is changed to do more actions if invalidateCache=true, please review those modules.
|
||||
CoreCourseModulePrefetchDelegate.invalidateModuleStatusCache(module);
|
||||
|
||||
await CoreUtils.ignoreErrors(CoreCourseModulePrefetchDelegate.invalidateCourseUpdates(courseId));
|
||||
}
|
||||
|
||||
const results = await Promise.all([
|
||||
|
@ -2191,6 +2207,7 @@ type ComponentWithContextMenu = {
|
|||
size?: string;
|
||||
prefetchStatus?: string;
|
||||
prefetchText?: string;
|
||||
downloadTimeReadable?: string;
|
||||
contextMenuStatusObserver?: CoreEventObserver;
|
||||
contextFileStatusObserver?: CoreEventObserver;
|
||||
};
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
"custom": "Custom",
|
||||
"datastoredoffline": "Data stored in the device because it couldn't be sent. It will be sent automatically later.",
|
||||
"date": "Date",
|
||||
"datecreated": "Created",
|
||||
"day": "day",
|
||||
"days": "days",
|
||||
"decsep": ".",
|
||||
|
@ -271,6 +272,7 @@
|
|||
"showmore": "Show more...",
|
||||
"site": "Site",
|
||||
"sitemaintenance": "The site is undergoing maintenance and is currently not available",
|
||||
"size": "Size",
|
||||
"sizeb": "bytes",
|
||||
"sizegb": "GB",
|
||||
"sizekb": "KB",
|
||||
|
@ -309,6 +311,7 @@
|
|||
"toggledelete": "Toggle delete buttons",
|
||||
"tryagain": "Try again",
|
||||
"twoparagraphs": "{{p1}}<br><br>{{p2}}",
|
||||
"type": "Type",
|
||||
"uhoh": "Uh oh!",
|
||||
"unexpectederror": "Unexpected error. Please close and reopen the application then try again.",
|
||||
"unicodenotsupported": "Some emojis are not supported on this site. Such characters will be removed when the message is sent.",
|
||||
|
|
Loading…
Reference in New Issue