MOBILE-3565 components: Create core-file component
| @ -17,6 +17,8 @@ import { CommonModule } from '@angular/common'; | |||||||
| import { IonicModule } from '@ionic/angular'; | import { IonicModule } from '@ionic/angular'; | ||||||
| import { TranslateModule } from '@ngx-translate/core'; | import { TranslateModule } from '@ngx-translate/core'; | ||||||
| 
 | 
 | ||||||
|  | import { CoreDownloadRefreshComponent } from './download-refresh/download-refresh'; | ||||||
|  | import { CoreFileComponent } from './file/file'; | ||||||
| import { CoreIconComponent } from './icon/icon'; | import { CoreIconComponent } from './icon/icon'; | ||||||
| import { CoreIframeComponent } from './iframe/iframe'; | import { CoreIframeComponent } from './iframe/iframe'; | ||||||
| import { CoreInputErrorsComponent } from './input-errors/input-errors'; | import { CoreInputErrorsComponent } from './input-errors/input-errors'; | ||||||
| @ -31,6 +33,8 @@ import { CorePipesModule } from '@app/pipes/pipes.module'; | |||||||
| 
 | 
 | ||||||
| @NgModule({ | @NgModule({ | ||||||
|     declarations: [ |     declarations: [ | ||||||
|  |         CoreDownloadRefreshComponent, | ||||||
|  |         CoreFileComponent, | ||||||
|         CoreIconComponent, |         CoreIconComponent, | ||||||
|         CoreIframeComponent, |         CoreIframeComponent, | ||||||
|         CoreInputErrorsComponent, |         CoreInputErrorsComponent, | ||||||
| @ -49,6 +53,8 @@ import { CorePipesModule } from '@app/pipes/pipes.module'; | |||||||
|         CorePipesModule, |         CorePipesModule, | ||||||
|     ], |     ], | ||||||
|     exports: [ |     exports: [ | ||||||
|  |         CoreDownloadRefreshComponent, | ||||||
|  |         CoreFileComponent, | ||||||
|         CoreIconComponent, |         CoreIconComponent, | ||||||
|         CoreIframeComponent, |         CoreIframeComponent, | ||||||
|         CoreInputErrorsComponent, |         CoreInputErrorsComponent, | ||||||
|  | |||||||
| @ -0,0 +1,20 @@ | |||||||
|  | <ng-container *ngIf="enabled && !(loading || status === statusDownloading)"> | ||||||
|  |     <!-- Download button. --> | ||||||
|  |     <ion-button *ngIf="status == statusNotDownloaded" fill="clear" (click)="download($event, false)" color="dark" | ||||||
|  |         class="core-animate-show-hide" [attr.aria-label]="'core.download' | translate"> | ||||||
|  |         <ion-icon slot="icon-only" name="cloud-download"></ion-icon> | ||||||
|  |     </ion-button> | ||||||
|  | 
 | ||||||
|  |     <!-- Refresh button. --> | ||||||
|  |     <ion-button *ngIf="status == statusOutdated || (status == statusDownloaded && !canTrustDownload)" fill="clear" | ||||||
|  |         (click)="download($event, true)" color="dark" class="core-animate-show-hide" [attr.aria-label]="'core.refresh' | translate"> | ||||||
|  |         <ion-icon slot="icon-only" name="fas-sync"></ion-icon> | ||||||
|  |     </ion-button> | ||||||
|  | 
 | ||||||
|  |     <!-- Downloaded status icon. --> | ||||||
|  |     <ion-icon *ngIf="status == statusDownloaded && canTrustDownload" class="core-icon-downloaded ion-padding-horizontal" color="success" | ||||||
|  |         name="cloud-done" [attr.aria-label]="'core.downloaded' | translate" role="status"></ion-icon> | ||||||
|  | </ng-container> | ||||||
|  | 
 | ||||||
|  | <!-- Spinner. --> | ||||||
|  | <ion-spinner *ngIf="loading || status === statusDownloading" class="core-animate-show-hide"></ion-spinner> | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | :host { | ||||||
|  |     font-size: 1.4rem; | ||||||
|  |     display: flex; | ||||||
|  |     flex-flow: row; | ||||||
|  |     align-items: center; | ||||||
|  |     justify-content: space-around; | ||||||
|  |     align-content: center; | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								src/app/components/download-refresh/download-refresh.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,59 @@ | |||||||
|  | // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||||
|  | //
 | ||||||
|  | // 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, EventEmitter } from '@angular/core'; | ||||||
|  | import { CoreConstants } from '@core/constants'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Component to show a download button with refresh option, the spinner and the status of it. | ||||||
|  |  * | ||||||
|  |  * Usage: | ||||||
|  |  * <core-download-refresh [status]="status" enabled="true" canCheckUpdates="true" action="download()"></core-download-refresh> | ||||||
|  |  */ | ||||||
|  | @Component({ | ||||||
|  |     selector: 'core-download-refresh', | ||||||
|  |     templateUrl: 'core-download-refresh.html', | ||||||
|  |     styleUrls: ['download-refresh.scss'], | ||||||
|  | }) | ||||||
|  | export class CoreDownloadRefreshComponent { | ||||||
|  | 
 | ||||||
|  |     @Input() status?: string; // Download status.
 | ||||||
|  |     @Input() enabled = false; // Whether the download is enabled.
 | ||||||
|  |     @Input() loading = true; // Force loading status when is not downloading.
 | ||||||
|  |     @Input() canTrustDownload = false; // If false, refresh will be shown if downloaded.
 | ||||||
|  |     @Output() action: EventEmitter<boolean>; // Will emit an event when the item clicked.
 | ||||||
|  | 
 | ||||||
|  |     statusDownloaded = CoreConstants.DOWNLOADED; | ||||||
|  |     statusNotDownloaded = CoreConstants.NOT_DOWNLOADED; | ||||||
|  |     statusOutdated = CoreConstants.OUTDATED; | ||||||
|  |     statusDownloading = CoreConstants.DOWNLOADING; | ||||||
|  | 
 | ||||||
|  |     constructor() { | ||||||
|  |         this.action = new EventEmitter(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Download clicked. | ||||||
|  |      * | ||||||
|  |      * @param e Click event. | ||||||
|  |      * @param refresh Whether it's refreshing. | ||||||
|  |      */ | ||||||
|  |     download(e: Event, refresh: boolean): void { | ||||||
|  |         e.preventDefault(); | ||||||
|  |         e.stopPropagation(); | ||||||
|  | 
 | ||||||
|  |         this.action.emit(refresh); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								src/app/components/file/core-file.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,20 @@ | |||||||
|  | <ion-item *ngIf="file" button class="ion-text-wrap item-media" (click)="download($event, true)" detail="false"> | ||||||
|  |     <ion-thumbnail slot="start"> | ||||||
|  |         <img [src]="fileIcon" alt="" role="presentation" /> | ||||||
|  |     </ion-thumbnail> | ||||||
|  |     <ion-label> | ||||||
|  |         <h2>{{fileName}}</h2> | ||||||
|  |         <p *ngIf="fileSizeReadable">{{ fileSizeReadable }}</p> | ||||||
|  |         <p *ngIf="showTime">{{ timemodified * 1000 | coreFormatDate }}</p> | ||||||
|  |     </ion-label> | ||||||
|  |     <div slot="end"> | ||||||
|  |         <core-download-refresh [status]="state" [enabled]="canDownload" [loading]="isDownloading" | ||||||
|  |             [canTrustDownload]="!alwaysDownload" (action)="download()"> | ||||||
|  |         </core-download-refresh> | ||||||
|  | 
 | ||||||
|  |         <ion-button fill="clear" *ngIf="!isDownloading && canDelete" (click)="delete($event)" | ||||||
|  |             [attr.aria-label]="'core.delete' | translate" color="danger"> | ||||||
|  |             <ion-icon slot="icon-only" name="fas-trash"></ion-icon> | ||||||
|  |         </ion-button> | ||||||
|  |     </div> | ||||||
|  | </ion-item> | ||||||
							
								
								
									
										31
									
								
								src/app/components/file/file.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,31 @@ | |||||||
|  | :host { | ||||||
|  |     // @todo | ||||||
|  |     // .card-md core-file + core-file > .item-md.item-block > .item-inner, | ||||||
|  |     // core-file + core-file > .item-md.item-block > .item-inner { | ||||||
|  |     //     border-top: 1px solid $list-md-border-color; | ||||||
|  |     // } | ||||||
|  | 
 | ||||||
|  |     // .card-ios core-file + core-file > .item-ios.item-block > .item-inner, | ||||||
|  |     // core-file + core-file > .item-ios.item-block > .item-inner { | ||||||
|  |     //     border-top: $hairlines-width solid $list-ios-border-color; | ||||||
|  |     //     .buttons { | ||||||
|  |     //         min-height: 53px; | ||||||
|  |     //         min-width: 58px; | ||||||
|  |     //     } | ||||||
|  |     // } | ||||||
|  | 
 | ||||||
|  |     // core-file > .item.item-block > .item-inner { | ||||||
|  |     //     border-bottom: 0; | ||||||
|  |     //     @include safe-area-padding(null, 0px, null, null); | ||||||
|  |     //     .buttons { | ||||||
|  |     //         display: flex; | ||||||
|  |     //         flex-flow: row; | ||||||
|  |     //         align-items: center; | ||||||
|  |     //         z-index: 1; | ||||||
|  |     //         justify-content: space-around; | ||||||
|  |     //         align-content: center; | ||||||
|  |     //         min-height: 52px; | ||||||
|  |     //         min-width: 53px; | ||||||
|  |     //     } | ||||||
|  |     // } | ||||||
|  | } | ||||||
							
								
								
									
										253
									
								
								src/app/components/file/file.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,253 @@ | |||||||
|  | // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||||
|  | //
 | ||||||
|  | // 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 { CoreApp } from '@services/app'; | ||||||
|  | import { CoreFilepool } from '@services/filepool'; | ||||||
|  | import { CoreFileHelper } from '@services/file-helper'; | ||||||
|  | import { CorePluginFileDelegate } from '@services/plugin-file-delegate'; | ||||||
|  | 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 { CoreTextUtils } from '@services/utils/text'; | ||||||
|  | import { CoreConstants } from '@core/constants'; | ||||||
|  | import { CoreEventObserver, CoreEvents } from '@singletons/events'; | ||||||
|  | import { CoreWSExternalFile } from '@/app/services/ws'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 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: 'core-file.html', | ||||||
|  |     styleUrls: ['file.scss'], | ||||||
|  | }) | ||||||
|  | export class CoreFileComponent implements OnInit, OnDestroy { | ||||||
|  | 
 | ||||||
|  |     @Input() file?: CoreWSExternalFile; // The file.
 | ||||||
|  |     @Input() component?: string; // Component the file belongs to.
 | ||||||
|  |     @Input() componentId?: string | number; // Component ID.
 | ||||||
|  |     @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.
 | ||||||
|  |     @Input() canDownload?: boolean | string = true; // Whether file can be downloaded.
 | ||||||
|  |     @Input() showSize?: boolean | string = true; // Whether show filesize.
 | ||||||
|  |     @Input() showTime?: boolean | string = true; // Whether show file time modified.
 | ||||||
|  |     @Output() onDelete: EventEmitter<void>; // Will notify when the delete button is clicked.
 | ||||||
|  | 
 | ||||||
|  |     isDownloading?: boolean; | ||||||
|  |     fileIcon?: string; | ||||||
|  |     fileName!: string; | ||||||
|  |     fileSizeReadable?: string; | ||||||
|  |     state?: string; | ||||||
|  |     timemodified!: number; | ||||||
|  | 
 | ||||||
|  |     protected fileUrl!: string; | ||||||
|  |     protected siteId?: string; | ||||||
|  |     protected fileSize?: number; | ||||||
|  |     protected observer?: CoreEventObserver; | ||||||
|  | 
 | ||||||
|  |     constructor( | ||||||
|  |         protected pluginFileDelegate: CorePluginFileDelegate, | ||||||
|  |     ) { | ||||||
|  |         this.onDelete = new EventEmitter<void>(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Component being initialized. | ||||||
|  |      */ | ||||||
|  |     async ngOnInit(): Promise<void> { | ||||||
|  |         if (!this.file) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.canDelete = CoreUtils.instance.isTrueOrOne(this.canDelete); | ||||||
|  |         this.alwaysDownload = CoreUtils.instance.isTrueOrOne(this.alwaysDownload); | ||||||
|  |         this.canDownload = CoreUtils.instance.isTrueOrOne(this.canDownload); | ||||||
|  | 
 | ||||||
|  |         this.fileUrl = this.file.fileurl; | ||||||
|  |         this.timemodified = this.file.timemodified || 0; | ||||||
|  |         this.siteId = CoreSites.instance.getCurrentSiteId(); | ||||||
|  |         this.fileSize = this.file.filesize; | ||||||
|  |         this.fileName = this.file.filename || ''; | ||||||
|  | 
 | ||||||
|  |         if (CoreUtils.instance.isTrueOrOne(this.showSize) && this.fileSize && this.fileSize >= 0) { | ||||||
|  |             this.fileSizeReadable = CoreTextUtils.instance.bytesToSize(this.fileSize, 2); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.showTime = CoreUtils.instance.isTrueOrOne(this.showTime) && this.timemodified > 0; | ||||||
|  | 
 | ||||||
|  |         if (this.file.isexternalfile) { | ||||||
|  |             this.alwaysDownload = true; // Always show the download button in external files.
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.fileIcon = this.file.mimetype ? CoreMimetypeUtils.instance.getMimetypeIcon(this.file.mimetype) : | ||||||
|  |             CoreMimetypeUtils.instance.getFileIcon(this.fileName); | ||||||
|  | 
 | ||||||
|  |         if (this.canDownload) { | ||||||
|  |             this.calculateState(); | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 // Update state when receiving events about this file.
 | ||||||
|  |                 const eventName = await CoreFilepool.instance.getFileEventNameByUrl(this.siteId, this.fileUrl); | ||||||
|  | 
 | ||||||
|  |                 this.observer = CoreEvents.on(eventName, () => { | ||||||
|  |                     this.calculateState(); | ||||||
|  |                 }); | ||||||
|  |             } catch (error) { | ||||||
|  |                 // File not downloadable.
 | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Convenience function to get the file state and set variables based on it. | ||||||
|  |      * | ||||||
|  |      * @return Promise resolved when state has been calculated. | ||||||
|  |      */ | ||||||
|  |     protected async calculateState(): Promise<void> { | ||||||
|  |         if (!this.siteId) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const state = await CoreFilepool.instance.getFileStateByUrl(this.siteId, this.fileUrl, this.timemodified); | ||||||
|  | 
 | ||||||
|  |         const site = await CoreSites.instance.getSite(this.siteId); | ||||||
|  | 
 | ||||||
|  |         this.canDownload = site.canDownloadFiles(); | ||||||
|  | 
 | ||||||
|  |         this.state = state; | ||||||
|  |         this.isDownloading = this.canDownload && state === CoreConstants.DOWNLOADING; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Convenience function to open a file, downloading it if needed. | ||||||
|  |      * | ||||||
|  |      * @return Promise resolved when file is opened. | ||||||
|  |      */ | ||||||
|  |     protected openFile(): Promise<void> { | ||||||
|  |         return CoreFileHelper.instance.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) => { | ||||||
|  |             CoreDomUtils.instance.showErrorModalDefault(error, 'core.errordownloading', true); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Download a file and, optionally, open it afterwards. | ||||||
|  |      * | ||||||
|  |      * @param e Click event. | ||||||
|  |      * @param openAfterDownload Whether the file should be opened after download. | ||||||
|  |      */ | ||||||
|  |     async download(e?: Event, openAfterDownload: boolean = false): Promise<void> { | ||||||
|  |         e && e.preventDefault(); | ||||||
|  |         e && e.stopPropagation(); | ||||||
|  | 
 | ||||||
|  |         if (!this.file || !this.siteId) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (this.isDownloading && !openAfterDownload) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (!this.canDownload || !this.state || this.state == CoreConstants.NOT_DOWNLOADABLE) { | ||||||
|  |             // File cannot be downloaded, just open it.
 | ||||||
|  |             if (CoreUrlUtils.instance.isLocalFileUrl(this.fileUrl)) { | ||||||
|  |                 CoreUtils.instance.openFile(this.fileUrl); | ||||||
|  |             } else { | ||||||
|  |                 CoreUtils.instance.openOnlineFile(CoreUrlUtils.instance.unfixPluginfileURL(this.fileUrl)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (!CoreApp.instance.isOnline() && (!openAfterDownload || (openAfterDownload && | ||||||
|  |                 !CoreFileHelper.instance.isStateDownloaded(this.state)))) { | ||||||
|  |             CoreDomUtils.instance.showErrorModal('core.networkerrormsg', true); | ||||||
|  | 
 | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (openAfterDownload) { | ||||||
|  |             // File needs to be opened now.
 | ||||||
|  |             try { | ||||||
|  |                 await this.openFile(); | ||||||
|  |             } catch (error) { | ||||||
|  |                 CoreDomUtils.instance.showErrorModalDefault(error, 'core.errordownloading', true); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             try { | ||||||
|  |                 // File doesn't need to be opened (it's a prefetch). Show confirm modal if file size is defined and it's big.
 | ||||||
|  |                 const size = await this.pluginFileDelegate.getFileSize(this.file, this.siteId); | ||||||
|  | 
 | ||||||
|  |                 if (size) { | ||||||
|  |                     await CoreDomUtils.instance.confirmDownloadSize({ size: size, total: true }); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // User confirmed, add the file to queue.
 | ||||||
|  |                 // @todo: Is the invalidate really needed?
 | ||||||
|  |                 await CoreUtils.instance.ignoreErrors(CoreFilepool.instance.invalidateFileByUrl(this.siteId, this.fileUrl)); | ||||||
|  | 
 | ||||||
|  |                 this.isDownloading = true; | ||||||
|  | 
 | ||||||
|  |                 try { | ||||||
|  |                     await CoreFilepool.instance.addToQueueByUrl( | ||||||
|  |                         this.siteId, | ||||||
|  |                         this.fileUrl, | ||||||
|  |                         this.component, | ||||||
|  |                         this.componentId, | ||||||
|  |                         this.timemodified, | ||||||
|  |                         undefined, | ||||||
|  |                         undefined, | ||||||
|  |                         0, | ||||||
|  |                         this.file, | ||||||
|  |                     ); | ||||||
|  |                 } catch (error) { | ||||||
|  |                     CoreDomUtils.instance.showErrorModalDefault(error, 'core.errordownloading', true); | ||||||
|  |                     this.calculateState(); | ||||||
|  |                 } | ||||||
|  |             } catch (error) { | ||||||
|  |                 CoreDomUtils.instance.showErrorModalDefault(error, 'core.errordownloading', true); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Delete the file. | ||||||
|  |      * | ||||||
|  |      * @param e Click event. | ||||||
|  |      */ | ||||||
|  |     delete(e: Event): void { | ||||||
|  |         e.preventDefault(); | ||||||
|  |         e.stopPropagation(); | ||||||
|  | 
 | ||||||
|  |         if (this.canDelete) { | ||||||
|  |             this.onDelete.emit(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Component destroyed. | ||||||
|  |      */ | ||||||
|  |     ngOnDestroy(): void { | ||||||
|  |         this.observer?.off(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -46,8 +46,8 @@ export class CoreFileHelperProvider { | |||||||
|      */ |      */ | ||||||
|     async downloadAndOpenFile( |     async downloadAndOpenFile( | ||||||
|         file: CoreWSExternalFile, |         file: CoreWSExternalFile, | ||||||
|         component: string, |         component?: string, | ||||||
|         componentId: string | number, |         componentId?: string | number, | ||||||
|         state?: string, |         state?: string, | ||||||
|         onProgress?: CoreFileHelperOnProgress, |         onProgress?: CoreFileHelperOnProgress, | ||||||
|         siteId?: string, |         siteId?: string, | ||||||
|  | |||||||
| @ -251,7 +251,7 @@ export class CoreFileProvider { | |||||||
|      * @return Promise to be resolved when the file is created. |      * @return Promise to be resolved when the file is created. | ||||||
|      */ |      */ | ||||||
|     async createFile(path: string, failIfExists?: boolean): Promise<FileEntry> { |     async createFile(path: string, failIfExists?: boolean): Promise<FileEntry> { | ||||||
|         const entry = <FileEntry> await this.create(true, path, failIfExists); |         const entry = <FileEntry> await this.create(false, path, failIfExists); | ||||||
| 
 | 
 | ||||||
|         return entry; |         return entry; | ||||||
|     } |     } | ||||||
| @ -568,8 +568,7 @@ export class CoreFileProvider { | |||||||
|         // Create file (and parent folders) to prevent errors.
 |         // Create file (and parent folders) to prevent errors.
 | ||||||
|         const fileEntry = await this.createFile(path); |         const fileEntry = await this.createFile(path); | ||||||
| 
 | 
 | ||||||
|         if (this.isHTMLAPI && |         if (this.isHTMLAPI && (typeof data == 'string' || data.toString() == '[object ArrayBuffer]')) { | ||||||
|                 (typeof data == 'string' || data.toString() == '[object ArrayBuffer]')) { |  | ||||||
|             // We need to write Blobs.
 |             // We need to write Blobs.
 | ||||||
|             const extension = CoreMimetypeUtils.instance.getFileExtension(path); |             const extension = CoreMimetypeUtils.instance.getFileExtension(path); | ||||||
|             const type = extension ? CoreMimetypeUtils.instance.getMimeType(extension) : ''; |             const type = extension ? CoreMimetypeUtils.instance.getMimeType(extension) : ''; | ||||||
|  | |||||||
| @ -17,11 +17,14 @@ import { FileEntry } from '@ionic-native/file'; | |||||||
| 
 | 
 | ||||||
| import { CoreFile } from '@services/file'; | import { CoreFile } from '@services/file'; | ||||||
| import { CoreTextUtils } from '@services/utils/text'; | import { CoreTextUtils } from '@services/utils/text'; | ||||||
| import { makeSingleton, Translate, Http } from '@singletons/core.singletons'; | import { makeSingleton, Translate } from '@singletons/core.singletons'; | ||||||
| import { CoreLogger } from '@singletons/logger'; | import { CoreLogger } from '@singletons/logger'; | ||||||
| import { CoreWSExternalFile } from '@services/ws'; | import { CoreWSExternalFile } from '@services/ws'; | ||||||
| import { CoreUtils } from '@services/utils/utils'; | import { CoreUtils } from '@services/utils/utils'; | ||||||
| 
 | 
 | ||||||
|  | import extToMime from '@/assets/exttomime.json'; | ||||||
|  | import mimeToExt from '@/assets/mimetoext.json'; | ||||||
|  | 
 | ||||||
| interface MimeTypeInfo { | interface MimeTypeInfo { | ||||||
|     type: string; |     type: string; | ||||||
|     icon?: string; |     icon?: string; | ||||||
| @ -52,17 +55,8 @@ export class CoreMimetypeUtilsProvider { | |||||||
|     constructor() { |     constructor() { | ||||||
|         this.logger = CoreLogger.getInstance('CoreMimetypeUtilsProvider'); |         this.logger = CoreLogger.getInstance('CoreMimetypeUtilsProvider'); | ||||||
| 
 | 
 | ||||||
|         Http.instance.get('assets/exttomime.json').subscribe((result: Record<string, MimeTypeInfo>) => { |         this.extToMime = extToMime; | ||||||
|             this.extToMime = result; |         this.mimeToExt = mimeToExt; | ||||||
|         }, () => { |  | ||||||
|             // Error, shouldn't happen.
 |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         Http.instance.get('assets/mimetoext.json').subscribe((result: Record<string, string[]>) => { |  | ||||||
|             this.mimeToExt = result; |  | ||||||
|         }, () => { |  | ||||||
|             // Error, shouldn't happen
 |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/archive-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/audio-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/avi-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/base-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/bmp-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/calc-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/chart-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/database-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/document-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/draw-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/eps-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/epub-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/flash-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/folder-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/folder-open-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/gif-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/h5p-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/html-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/image-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/impress-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/isf-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/jpeg-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/markup-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/math-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/moodle-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/mp3-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/mpeg-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/oth-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/pdf-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/png-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/powerpoint-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/psd-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/publisher-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/quicktime-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/sourcecode-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/spreadsheet-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/text-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/tiff-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/unknown-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/video-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/wav-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/wmv-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/files/writer-64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.8 KiB |