MOBILE-2302 core: Implement core-file component

main
Dani Palou 2017-12-18 13:06:12 +01:00
parent 86a9d0dcea
commit 2b03bcf3e4
54 changed files with 418 additions and 33 deletions

View File

@ -216,3 +216,12 @@ core-format-text, *[core-format-text] {
display: inline;
}
}
// Media item, ideal for icons.
.item-media {
min-height: $item-media-height + ($content-padding * 2);
> img:first-child {
max-width: $item-media-width;
max-height: $item-media-height;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -329,6 +329,21 @@ export class SQLiteDB {
});
}
/**
* Format the data to insert in the database. Removes undefined entries so they are stored as null instead of 'undefined'.
*
* @param {object} data Data to insert.
*/
protected formatDataToInsert(data: object) : void {
// Remove undefined entries and convert null to "NULL".
for (let name in data) {
let value = data[name];
if (typeof value == 'undefined') {
delete data[name];
}
}
}
/**
* Get all the records from a table.
*
@ -585,6 +600,8 @@ export class SQLiteDB {
* @return {any[]} Array with the SQL query and the params.
*/
protected getSqlInsertQuery(table: string, data: object) : any[] {
this.formatDataToInsert(data);
let keys = Object.keys(data),
fields = keys.join(','),
questionMarks = ',?'.repeat(keys.length).substr(1);
@ -773,6 +790,8 @@ export class SQLiteDB {
sql,
params;
this.formatDataToInsert(data);
for (let key in data) {
sets.push(`${key} = ?`);
}

View File

@ -24,6 +24,7 @@ import { CoreIframeComponent } from './iframe/iframe';
import { CoreProgressBarComponent } from './progress-bar/progress-bar';
import { CoreEmptyBoxComponent } from './empty-box/empty-box';
import { CoreSearchBoxComponent } from './search-box/search-box';
import { CoreFileComponent } from './file/file';
@NgModule({
declarations: [
@ -34,7 +35,8 @@ import { CoreSearchBoxComponent } from './search-box/search-box';
CoreIframeComponent,
CoreProgressBarComponent,
CoreEmptyBoxComponent,
CoreSearchBoxComponent
CoreSearchBoxComponent,
CoreFileComponent
],
imports: [
IonicModule,
@ -49,7 +51,8 @@ import { CoreSearchBoxComponent } from './search-box/search-box';
CoreIframeComponent,
CoreProgressBarComponent,
CoreEmptyBoxComponent,
CoreSearchBoxComponent
CoreSearchBoxComponent,
CoreFileComponent
]
})
export class CoreComponentsModule {}

View File

@ -0,0 +1,13 @@
<a ion-item text-wrap class="item-media" (click)="download($event, true)" [class.item-2-button-right]="canDelete">
<img [src]="fileIcon" alt="" role="presentation" item-start />
<p>{{fileName}}</p>
<div class="buttons" item-end>
<button ion-button clear icon-only (click)="download($event)" *ngIf="!isDownloading && showDownload" [attr.aria-label]="'core.download' | translate">
<ion-icon [name]="isDownloaded ? 'refresh' : 'cloud-download'"></ion-icon>
</button>
<button ion-button clear icon-only (click)="delete($event)" *ngIf="!isDownloading && canDelete" [attr.aria-label]="'core.delete' | translate" color="danger">
<ion-icon name="trash"></ion-icon>
</button>
</div>
<ion-spinner *ngIf="isDownloading" item-end></ion-spinner>
</a>

View File

@ -0,0 +1,28 @@
core-loading {
.mm-loading-container {
width: 100%;
text-align: center;
padding-top: 10px;
clear: both;
}
.mm-loading-content {
padding-bottom: 1px; /* This makes height be real */
}
&.mm-loading-noheight .mm-loading-content {
height: auto;
}
}
.scroll-content > .padding > core-loading > .mm-loading-container,
ion-content[padding] > .scroll-content > core-loading > .mm-loading-container,
.mm-loading-center .mm-loading-container {
display: table;
.mm-loading-spinner {
display: table-cell;
text-align: center;
vertical-align: middle;
}
}

View File

@ -0,0 +1,291 @@
// (C) Copyright 2015 Martin Dougiamas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, Output, OnInit, OnDestroy, EventEmitter } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '../../providers/app';
import { CoreEventsProvider } from '../../providers/events';
import { CoreFileProvider } from '../../providers/file';
import { CoreFilepoolProvider } from '../../providers/filepool';
import { CoreSitesProvider } from '../../providers/sites';
import { CoreDomUtilsProvider } from '../../providers/utils/dom';
import { CoreMimetypeUtilsProvider } from '../../providers/utils/mimetype';
import { CoreUtilsProvider } from '../../providers/utils/utils';
import { CoreConstants } from '../../core/constants';
/**
* Component to handle a remote file. Shows the file name, icon (depending on mimetype) and a button
* to download/refresh it.
*/
@Component({
selector: 'core-file',
templateUrl: 'file.html'
})
export class CoreFileComponent implements OnInit, OnDestroy {
@Input() file: any; // The file. Must have a property 'filename' and a 'fileurl' or 'url'
@Input() component?: string; // Component the file belongs to.
@Input() componentId?: string|number; // Component ID.
@Input() timemodified?: number; // If set, the value will be used to check if the file is outdated.
@Input() canDelete?: boolean|string; // Whether file can be deleted.
@Input() alwaysDownload?: boolean|string; // Whether it should always display the refresh button when the file is downloaded.
// Use it for files that you cannot determine if they're outdated or not.
@Input() canDownload?: boolean|string = true; // Whether file can be downloaded.
@Output() onDelete?: EventEmitter<string>; // Will notify when the delete button is clicked.
isDownloaded: boolean;
isDownloading: boolean;
showDownload: boolean;
fileIcon: string;
fileName: string;
protected fileUrl: string;
protected siteId: string;
protected fileSize: number;
protected observer;
constructor(private translate: TranslateService, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
private domUtils: CoreDomUtilsProvider, private filepoolProvider: CoreFilepoolProvider,
private fileProvider: CoreFileProvider, private appProvider: CoreAppProvider,
private mimeUtils: CoreMimetypeUtilsProvider, private eventsProvider: CoreEventsProvider) {
this.onDelete = new EventEmitter();
}
/**
* Component being initialized.
*/
ngOnInit() {
this.canDelete = this.utils.isTrueOrOne(this.canDelete);
this.alwaysDownload = this.utils.isTrueOrOne(this.alwaysDownload);
this.canDownload = this.utils.isTrueOrOne(this.canDownload);
this.timemodified = this.timemodified || 0;
this.fileUrl = this.file.fileurl || this.file.url;
this.siteId = this.sitesProvider.getCurrentSiteId();
this.fileSize = this.file.filesize;
this.fileName = this.file.filename;
if (this.file.isexternalfile) {
this.alwaysDownload = true; // Always show the download button in external files.
}
this.fileIcon = this.mimeUtils.getFileIcon(this.file.filename);
if (this.canDownload) {
this.calculateState();
// Update state when receiving events about this file.
this.filepoolProvider.getFileEventNameByUrl(this.siteId, this.fileUrl).then((eventName) => {
this.observer = this.eventsProvider.on(eventName, () => {
this.calculateState();
});
});
}
}
/**
* Convenience function to get the file state and set variables based on it.
*
* @return {Promise<void>} Promise resolved when state has been calculated.
*/
protected calculateState() : Promise<void> {
return this.filepoolProvider.getFileStateByUrl(this.siteId, this.fileUrl, this.timemodified).then((state) => {
let canDownload = this.sitesProvider.getCurrentSite().canDownloadFiles();
this.isDownloaded = state === CoreConstants.downloaded || state === CoreConstants.outdated;
this.isDownloading = canDownload && state === CoreConstants.downloading;
this.showDownload = canDownload && (state === CoreConstants.notDownloaded || state === CoreConstants.outdated ||
(this.alwaysDownload && state === CoreConstants.downloaded));
});
}
/**
* Download the file.
*
* @return {Promise<string>} Promise resolved when file is downloaded.
*/
protected downloadFile() : Promise<string> {
if (!this.sitesProvider.getCurrentSite().canDownloadFiles()) {
this.domUtils.showErrorModal('core.cannotdownloadfiles', true);
return Promise.reject(null);
}
this.isDownloading = true;
return this.filepoolProvider.downloadUrl(this.siteId, this.fileUrl, false, this.component, this.componentId,
this.timemodified, undefined, undefined, this.file).catch(() => {
// Call calculateState to make sure we have the right state.
return this.calculateState().then(() => {
if (this.isDownloaded) {
return this.filepoolProvider.getInternalUrlByUrl(this.siteId, this.fileUrl);
} else {
return Promise.reject(null);
}
});
});
}
/**
* Convenience function to open a file, downloading it if needed.
*
* @return {Promise<string>} Promise resolved when file is opened.
*/
protected openFile() : Promise<any> {
let fixedUrl = this.sitesProvider.getCurrentSite().fixPluginfileURL(this.fileUrl),
promise;
if (this.fileProvider.isAvailable()) {
promise = Promise.resolve().then(() => {
// The file system is available.
let isWifi = !this.appProvider.isNetworkAccessLimited(),
isOnline = this.appProvider.isOnline();
if (this.isDownloaded && !this.showDownload) {
// File is downloaded, get the local file URL.
return this.filepoolProvider.getUrlByUrl(this.siteId, this.fileUrl,
this.component, this.componentId, this.timemodified, false, false, this.file);
} else {
if (!isOnline && !this.isDownloaded) {
// Not downloaded and user is offline, reject.
return Promise.reject(this.translate.instant('core.networkerrormsg'));
}
let isDownloading = this.isDownloading;
this.isDownloading = true; // This check could take a while, show spinner.
return this.filepoolProvider.shouldDownloadBeforeOpen(fixedUrl, this.fileSize).then(() => {
if (isDownloading) {
// It's already downloading, stop.
return;
}
// Download and then return the local URL.
return this.downloadFile();
}, () => {
// Start the download if in wifi, but return the URL right away so the file is opened.
if (isWifi && isOnline) {
this.downloadFile();
}
if (isDownloading || !this.isDownloaded || isOnline) {
// Not downloaded or outdated and online, return the online URL.
return fixedUrl;
} else {
// Outdated but offline, so we return the local URL.
return this.filepoolProvider.getUrlByUrl(this.siteId, this.fileUrl,
this.component, this.componentId, this.timemodified, false, false, this.file);
}
});
}
});
} else {
// Use the online URL.
promise = Promise.resolve(fixedUrl);
}
return promise.then((url) => {
if (!url) {
return;
}
if (url.indexOf('http') === 0) {
return this.utils.openOnlineFile(url).catch((error) => {
// Error opening the file, some apps don't allow opening online files.
if (!this.fileProvider.isAvailable()) {
return Promise.reject(error);
} else if (this.isDownloading) {
return Promise.reject(this.translate.instant('core.erroropenfiledownloading'));
}
let subPromise;
if (status === CoreConstants.notDownloaded) {
// File is not downloaded, download and then return the local URL.
subPromise = this.downloadFile();
} else {
// File is outdated and can't be opened in online, return the local URL.
subPromise = this.filepoolProvider.getInternalUrlByUrl(this.siteId, this.fileUrl);
}
return subPromise.then((url) => {
return this.utils.openFile(url);
});
});
} else {
return this.utils.openFile(url);
}
});
}
/**
* Download a file and, optionally, open it afterwards.
*
* @param {Event} e Click event.
* @param {boolean} openAfterDownload Whether the file should be opened after download.
*/
download(e: Event, openAfterDownload: boolean) : void {
e.preventDefault();
e.stopPropagation();
let promise;
if (this.isDownloading && !openAfterDownload) {
return;
}
if (!this.appProvider.isOnline() && (!openAfterDownload || (openAfterDownload && !this.isDownloaded))) {
this.domUtils.showErrorModal('core.networkerrormsg', true);
return;
}
if (openAfterDownload) {
// File needs to be opened now.
this.openFile().catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true);
});
} else {
// File doesn't need to be opened (it's a prefetch). Show confirm modal if file size is defined and it's big.
promise = this.fileSize ? this.domUtils.confirmDownloadSize({size: this.fileSize, total: true}) : Promise.resolve();
promise.then(() => {
// User confirmed, add the file to queue.
this.filepoolProvider.invalidateFileByUrl(this.siteId, this.fileUrl).finally(() => {
this.isDownloading = true;
this.filepoolProvider.addToQueueByUrl(this.siteId, this.fileUrl, this.component,
this.componentId, this.timemodified, undefined, undefined, 0, this.file).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true);
this.calculateState();
});
});
});
}
};
/**
* Delete the file.
*
* @param {Event} e Click event.
*/
deleteFile(e: Event) : void {
e.preventDefault();
e.stopPropagation();
if (this.canDelete) {
this.onDelete.emit();
}
}
/**
* Component destroyed.
*/
ngOnDestroy() {
this.observer && this.observer.off();
}
}

View File

@ -25,7 +25,7 @@
<p class="item-heading">{{ 'core.teachers' | translate }}</p>
<p *ngFor="let contact of course.contacts">{{contact.fullname}}</p>
</a>
<!-- <mm-file ng-repeat="file in course.overviewfiles" file="file" component="{{component}}" component-id="{{course.id}}"></mm-file> -->
<core-file *ngFor="let file of course.overviewfiles" [file]="file" [component]="component" [componentId]="course.id"></core-file>
<div *ngIf="!isEnrolled">
<ion-item text-wrap *ngFor="let instance of selfEnrolInstances">
<p class="item-heading">{{ instance.name }}</p>

View File

@ -350,7 +350,6 @@ export class FileMock extends File {
(<any>navigator).webkitPersistentStorage.requestQuota(500 * 1024 * 1024, (granted) => {
window.requestFileSystem(LocalFileSystem.PERSISTENT, granted, (entry) => {
basePath = entry.root.toURL();
// this.fileProvider.setHTMLBasePath(basePath);
resolve(basePath);
}, reject);
}, reject);

View File

@ -98,7 +98,7 @@ export class CoreFileProvider {
* @return {boolean} Whether the plugin is available.
*/
isAvailable() : boolean {
return typeof window.resolveLocalFileSystemURL !== 'undefined' && typeof FileTransfer !== 'undefined';
return typeof window.resolveLocalFileSystemURL !== 'undefined';
}
/**

View File

@ -327,7 +327,7 @@ export class CoreFilepoolProvider {
component: component,
componentId: componentId || ''
};
return db.insertOrUpdateRecord(this.LINKS_TABLE, newEntry, null);
return db.insertOrUpdateRecord(this.LINKS_TABLE, newEntry, undefined);
});
}
@ -410,7 +410,7 @@ export class CoreFilepoolProvider {
* @return {Promise<any>} Promise resolved when the file is downloaded.
*/
protected addToQueue(siteId: string, fileId: string, url: string, priority: number, revision: number, timemodified: number,
filePath: string, options: any = {}, link?: any) : Promise<any> {
filePath: string, onProgress?: (event: any) => any, options: any = {}, link?: any) : Promise<any> {
this.logger.debug(`Adding ${fileId} to the queue`);
return this.appDB.insertRecord(this.QUEUE_TABLE, {
@ -429,7 +429,7 @@ export class CoreFilepoolProvider {
// Check if the queue is running.
this.checkQueueProcessing();
this.notifyFileDownloading(siteId, fileId);
return this.getQueuePromise(siteId, fileId);
return this.getQueuePromise(siteId, fileId, true, onProgress);
});
}
@ -479,8 +479,7 @@ export class CoreFilepoolProvider {
// Retrieve the queue deferred now if it exists to prevent errors if file is removed from queue
// while we're checking if the file is in queue.
queueDeferred = this.getQueueDeferred(siteId, fileId, false);
queueDeferred.onProgress = onProgress;
queueDeferred = this.getQueueDeferred(siteId, fileId, false, onProgress);
return this.hasFileInQueue(siteId, fileId).then((entry: CoreFilepoolQueueEntry) => {
let foundLink = false,
@ -530,7 +529,7 @@ export class CoreFilepoolProvider {
// Update only when required.
this.logger.debug(`Updating file ${fileId} which is already in queue`);
return this.appDB.updateRecords(this.QUEUE_TABLE, newData, primaryKey).then(() => {
return this.getQueuePromise(siteId, fileId);
return this.getQueuePromise(siteId, fileId, true, onProgress);
});
}
@ -540,14 +539,17 @@ export class CoreFilepoolProvider {
// might have finished now and the deferred wouldn't be in the array anymore.
return queueDeferred.promise;
} else {
return this.getQueuePromise(siteId, fileId);
// Create a new deferred and return its promise.
return this.getQueuePromise(siteId, fileId, true, onProgress);
}
} else {
return this.addToQueue(siteId, fileId, fileUrl, priority, revision, timemodified, filePath, options, link);
return this.addToQueue(
siteId, fileId, fileUrl, priority, revision, timemodified, filePath, onProgress, options, link);
}
}, () => {
// Unsure why we could not get the record, let's add to the queue anyway.
return this.addToQueue(siteId, fileId, fileUrl, priority, revision, timemodified, filePath, options, link);
return this.addToQueue(
siteId, fileId, fileUrl, priority, revision, timemodified, filePath, onProgress, options, link);
});
});
});
@ -596,15 +598,17 @@ export class CoreFilepoolProvider {
// Check if the file should be downloaded.
if (sizeUnknown) {
if (downloadUnknown && isWifi) {
return this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, null, null, 0, options);
return this.addToQueueByUrl(
siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options);
}
} else if (size <= this.DOWNLOAD_THRESHOLD || (isWifi && size <= this.WIFI_DOWNLOAD_THRESHOLD)) {
return this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, null, null, 0, options);
return this.addToQueueByUrl(
siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options);
}
});
} else {
// No need to check size, just add it to the queue.
return this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, null, null, 0, options);
return this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options);
}
}
@ -817,9 +821,11 @@ export class CoreFilepoolProvider {
}
if (prefetch) {
promises.push(this.addToQueueByUrl(siteId, url, component, componentId, timemodified, null, null, 0, options));
promises.push(this.addToQueueByUrl(
siteId, url, component, componentId, timemodified, undefined, undefined, 0, options));
} else {
promises.push(this.downloadUrl(siteId, url, ignoreStale, component, componentId, timemodified, null, null, options));
promises.push(this.downloadUrl(
siteId, url, ignoreStale, component, componentId, timemodified, undefined, undefined, options));
}
});
@ -901,7 +907,7 @@ export class CoreFilepoolProvider {
if (prefetch) {
promise = this.addToQueueByUrl(
siteId, fileUrl, component, componentId, file.timemodified, path, null, 0, options);
siteId, fileUrl, component, componentId, file.timemodified, path, undefined, 0, options);
} else {
promise = this.downloadUrl(
siteId, fileUrl, false, component, componentId, file.timemodified, onFileProgress, path, options);
@ -1816,9 +1822,10 @@ export class CoreFilepoolProvider {
* @param {string} siteId The site ID.
* @param {string} fileId The file ID.
* @param {boolean} [create=true] True if it should create a new deferred if it doesn't exist.
* @param {Function} [onProgress] Function to call on progress.
* @return {any} Deferred.
*/
protected getQueueDeferred(siteId: string, fileId: string, create = true): any {
protected getQueueDeferred(siteId: string, fileId: string, create = true, onProgress?: (event: any) => any): any {
if (!this.queueDeferreds[siteId]) {
if (!create) {
return;
@ -1831,6 +1838,11 @@ export class CoreFilepoolProvider {
}
this.queueDeferreds[siteId][fileId] = this.utils.promiseDefer();
}
if (onProgress) {
this.queueDeferreds[siteId][fileId].onProgress = onProgress;
}
return this.queueDeferreds[siteId][fileId];
}
@ -1854,10 +1866,11 @@ export class CoreFilepoolProvider {
* @param {string} siteId The site ID.
* @param {string} fileId The file ID.
* @param {boolean} [create=true] True if it should create a new promise if it doesn't exist.
* @param {Function} [onProgress] Function to call on progress.
* @return {Promise<any>} Promise.
*/
protected getQueuePromise(siteId: string, fileId: string, create = true) : Promise<any> {
return this.getQueueDeferred(siteId, fileId, create).promise;
protected getQueuePromise(siteId: string, fileId: string, create = true, onProgress?: (event: any) => any) : Promise<any> {
return this.getQueueDeferred(siteId, fileId, create, onProgress).promise;
}
/**
@ -2248,7 +2261,9 @@ export class CoreFilepoolProvider {
promise.then(() => {
// All good, we schedule next execution.
setTimeout(this.processQueue, this.QUEUE_PROCESS_INTERVAL);
setTimeout(() => {
this.processQueue();
}, this.QUEUE_PROCESS_INTERVAL);
}, (error) => {
@ -2270,7 +2285,7 @@ export class CoreFilepoolProvider {
* @return {Promise} Resolved on success. Rejected on failure.
*/
protected processImportantQueueItem() : Promise<any> {
return this.appDB.getRecords(this.QUEUE_TABLE, null, 'priority DESC, added ASC', null, 0, 1).then((items) => {
return this.appDB.getRecords(this.QUEUE_TABLE, undefined, 'priority DESC, added ASC', undefined, 0, 1).then((items) => {
let item = items.pop();
if (!item) {
return Promise.reject(this.ERR_QUEUE_IS_EMPTY);
@ -2290,16 +2305,17 @@ export class CoreFilepoolProvider {
* @return {Promise<any>} Resolved on success. Rejected on failure.
*/
protected processQueueItem(item: CoreFilepoolQueueEntry) : Promise<any> {
// Cast optional fields to undefined instead of null.
let siteId = item.siteId,
fileId = item.fileId,
fileUrl = item.url,
options = {
revision: item.revision,
timemodified: item.timemodified,
isexternalfile: item.isexternalfile,
repositorytype: item.repositorytype
revision: item.revision || undefined,
timemodified: item.timemodified || undefined,
isexternalfile: item.isexternalfile || undefined,
repositorytype: item.repositorytype || undefined
},
filePath = item.path,
filePath = item.path || undefined,
links = item.links || [];
this.logger.debug('Processing queue item: ' + siteId + ', ' + fileId);
@ -2335,7 +2351,7 @@ export class CoreFilepoolProvider {
// Whoops, we have an error...
let dropFromQueue = false;
if (typeof errorObject != 'undefined' && errorObject.source === fileUrl) {
if (errorObject && errorObject.source === fileUrl) {
// This is most likely a FileTransfer error.
if (errorObject.code === 1) { // FILE_NOT_FOUND_ERR.
// The file was not found, most likely a 404, we remove from queue.

View File

@ -185,7 +185,7 @@ export class CoreMimetypeUtilsProvider {
}
}
return 'img/files/' + icon + '-64.png';
return 'assets/img/files/' + icon + '-64.png';
}
/**
@ -194,7 +194,7 @@ export class CoreMimetypeUtilsProvider {
* @return {string} The path to a folder icon.
*/
getFolderIcon() : string {
return 'img/files/folder-64.png';
return 'assets/img/files/folder-64.png';
}
/**

View File

@ -171,3 +171,10 @@ $item-wp-avatar-size: 54px;
@import "roboto";
@import "noto-sans";
// Moodle Mobile variables
// --------------------------------------------------
// Small avatar ideal for icons.
$item-media-width: 32px !default;
$item-media-height: 32px !default;