From 2302638702c2b4f434524dc70999c5d9c146c7d6 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 11 Mar 2021 14:33:46 +0100 Subject: [PATCH] MOBILE-3630 sharedfiled: Implement components and pages --- src/core/classes/page-items-list-manager.ts | 2 +- src/core/components/components.module.ts | 3 + .../site-picker/core-site-picker.html | 6 + .../components/site-picker/site-picker.ts | 77 ++++++++ .../services/fileuploader-helper.ts | 24 +-- src/core/features/settings/constants.ts | 55 ------ .../features/settings/pages/index/index.html | 11 +- .../features/settings/pages/index/index.ts | 71 +++++++- .../features/settings/pages/site/site.html | 12 +- src/core/features/settings/pages/site/site.ts | 26 +-- .../settings/services/settings-helper.ts | 26 +++ .../features/settings/settings-lazy.module.ts | 6 +- .../components/components.module.ts | 34 ++++ .../components/list-modal/list-modal.html | 19 ++ .../components/list-modal/list-modal.ts | 75 ++++++++ .../sharedfiles/components/list/list.html | 32 ++++ .../sharedfiles/components/list/list.ts | 170 ++++++++++++++++++ .../pages/choose-site/choose-site.html | 32 ++++ .../pages/choose-site/choose-site.ts | 108 +++++++++++ .../features/sharedfiles/pages/list/list.html | 13 ++ .../features/sharedfiles/pages/list/list.ts | 63 +++++++ .../sharedfiles/sharedfiles-lazy.module.ts | 45 +++++ src/core/services/navigator.ts | 15 ++ src/core/singletons/events.ts | 2 +- 24 files changed, 811 insertions(+), 116 deletions(-) create mode 100644 src/core/components/site-picker/core-site-picker.html create mode 100644 src/core/components/site-picker/site-picker.ts delete mode 100644 src/core/features/settings/constants.ts create mode 100644 src/core/features/sharedfiles/components/components.module.ts create mode 100644 src/core/features/sharedfiles/components/list-modal/list-modal.html create mode 100644 src/core/features/sharedfiles/components/list-modal/list-modal.ts create mode 100644 src/core/features/sharedfiles/components/list/list.html create mode 100644 src/core/features/sharedfiles/components/list/list.ts create mode 100644 src/core/features/sharedfiles/pages/choose-site/choose-site.html create mode 100644 src/core/features/sharedfiles/pages/choose-site/choose-site.ts create mode 100644 src/core/features/sharedfiles/pages/list/list.html create mode 100644 src/core/features/sharedfiles/pages/list/list.ts create mode 100644 src/core/features/sharedfiles/sharedfiles-lazy.module.ts diff --git a/src/core/classes/page-items-list-manager.ts b/src/core/classes/page-items-list-manager.ts index defd9ca3d..ed43becdd 100644 --- a/src/core/classes/page-items-list-manager.ts +++ b/src/core/classes/page-items-list-manager.ts @@ -137,7 +137,7 @@ export abstract class CorePageItemsListManager { // If this item is already selected, do nothing. const itemRoute = this.getItemRoute(route); const itemPath = this.getItemPath(item); - const selectedItemPath = itemRoute ? this.getSelectedItemPath(itemRoute.snapshot) : null; + const selectedItemPath = itemRoute?.snapshot ? this.getSelectedItemPath(itemRoute.snapshot) : null; if (selectedItemPath === itemPath) { return; diff --git a/src/core/components/components.module.ts b/src/core/components/components.module.ts index 4e37a8a76..8e1f2bfe6 100644 --- a/src/core/components/components.module.ts +++ b/src/core/components/components.module.ts @@ -52,6 +52,7 @@ import { CoreAttachmentsComponent } from './attachments/attachments'; import { CoreFilesComponent } from './files/files'; import { CoreLocalFileComponent } from './local-file/local-file'; import { CoreBSTooltipComponent } from './bs-tooltip/bs-tooltip'; +import { CoreSitePickerComponent } from './site-picker/site-picker'; @NgModule({ declarations: [ @@ -86,6 +87,7 @@ import { CoreBSTooltipComponent } from './bs-tooltip/bs-tooltip'; CoreFilesComponent, CoreLocalFileComponent, CoreBSTooltipComponent, + CoreSitePickerComponent, ], imports: [ CommonModule, @@ -127,6 +129,7 @@ import { CoreBSTooltipComponent } from './bs-tooltip/bs-tooltip'; CoreFilesComponent, CoreLocalFileComponent, CoreBSTooltipComponent, + CoreSitePickerComponent, ], }) export class CoreComponentsModule {} diff --git a/src/core/components/site-picker/core-site-picker.html b/src/core/components/site-picker/core-site-picker.html new file mode 100644 index 000000000..ff07a6a1e --- /dev/null +++ b/src/core/components/site-picker/core-site-picker.html @@ -0,0 +1,6 @@ + + {{ 'core.site' | translate }} + + {{ site.fullNameAndSiteName }} + + diff --git a/src/core/components/site-picker/site-picker.ts b/src/core/components/site-picker/site-picker.ts new file mode 100644 index 000000000..8cdec8a16 --- /dev/null +++ b/src/core/components/site-picker/site-picker.ts @@ -0,0 +1,77 @@ +// (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, OnInit } from '@angular/core'; + +import { CoreFilter } from '@features/filter/services/filter'; +import { CoreSiteBasicInfo, CoreSites } from '@services/sites'; +import { CoreUtils } from '@services/utils/utils'; +import { Translate } from '@singletons'; + +/** + * Component to display a site selector. It will display a select with the list of sites. If the selected site changes, + * an output will be emitted with the site ID. + * + * Example usage: + * + */ +@Component({ + selector: 'core-site-picker', + templateUrl: 'core-site-picker.html', +}) +export class CoreSitePickerComponent implements OnInit { + + @Input() initialSite?: string; // Initial site. If not provided, current site. + @Output() siteSelected = new EventEmitter(); // Emit an event when a site is selected. Sends the siteId as parameter. + + selectedSite?: string; + sites?: SiteInfo[]; + + /** + * @inheritdoc + */ + async ngOnInit(): Promise { + this.selectedSite = this.initialSite || CoreSites.getCurrentSiteId(); + + // Load the sites. + const sites = await CoreSites.getSites(); + + if (!this.selectedSite && sites.length) { + // There is no current site, select the first one. + this.selectedSite = sites[0].id; + this.siteSelected.emit(this.selectedSite); + } + + await Promise.all(sites.map(async (site: SiteInfo) => { + // Format the site name. + const options = { clean: true, singleLine: true, filter: false }; + const siteName = await CoreUtils.ignoreErrors( + CoreFilter.formatText(site.siteName || '', options, [], site.id), + site.siteName || '', + ); + + site.fullNameAndSiteName = Translate.instant( + 'core.fullnameandsitename', + { fullname: site.fullName, sitename: siteName }, + ); + })); + + this.sites = sites; + } + +} + +type SiteInfo = CoreSiteBasicInfo & { + fullNameAndSiteName?: string; +}; diff --git a/src/core/features/fileuploader/services/fileuploader-helper.ts b/src/core/features/fileuploader/services/fileuploader-helper.ts index a42747761..e0e939f57 100644 --- a/src/core/features/fileuploader/services/fileuploader-helper.ts +++ b/src/core/features/fileuploader/services/fileuploader-helper.ts @@ -376,16 +376,14 @@ export class CoreFileUploaderHelperProvider { try { const data = await handler.action(maxSize, upload, allowOffline, handler.mimetypes); + let result: CoreWSUploadFileResult | FileEntry | undefined; + if (data.treated) { // The handler already treated the file. Return the result. - this.fileUploaded(data.result!); - - return true; + result = data.result; } else if (data.fileEntry) { // The handler provided us a fileEntry, use it. - await this.uploadFileEntry(data.fileEntry, !!data.delete, maxSize, upload, allowOffline); - - return true; + result = await this.uploadFileEntry(data.fileEntry, !!data.delete, maxSize, upload, allowOffline); } else if (data.path) { let fileEntry: FileEntry; @@ -398,13 +396,17 @@ export class CoreFileUploaderHelperProvider { } // File found, treat it. - await this.uploadFileEntry(fileEntry, !!data.delete, maxSize, upload, allowOffline); - - return true; + result = await this.uploadFileEntry(fileEntry, !!data.delete, maxSize, upload, allowOffline); } - // Nothing received, fail. - throw new CoreError('No file received'); + if (!result) { + // Nothing received, fail. + throw new CoreError('No file received'); + } + + this.fileUploaded(result); + + return true; } catch (error) { CoreDomUtils.showErrorModalDefault( error, diff --git a/src/core/features/settings/constants.ts b/src/core/features/settings/constants.ts deleted file mode 100644 index 67b3eda4e..000000000 --- a/src/core/features/settings/constants.ts +++ /dev/null @@ -1,55 +0,0 @@ -// (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 { CoreConstants } from '@/core/constants'; - -/** - * Settings section. - */ -export type CoreSettingsSection = { - name: string; - path: string; - icon: string; -}; - -/** - * Settings constants. - */ -export class CoreSettingsConstants { - - static readonly SECTIONS: CoreSettingsSection[] = [ - { - name: 'general', - path: 'general', - icon: 'fas-wrench', - }, - { - name: 'spaceusage', - path: 'spaceusage', - icon: 'fas-tasks', - }, - { - name: 'synchronization', - path: 'sync', - icon: CoreConstants.ICON_SYNC, - }, - // @TODO sharedfiles - { - name: 'about', - path: 'about', - icon: 'fas-id-card', - }, - ]; - -} diff --git a/src/core/features/settings/pages/index/index.html b/src/core/features/settings/pages/index/index.html index 2552bd392..5acca83d3 100644 --- a/src/core/features/settings/pages/index/index.html +++ b/src/core/features/settings/pages/index/index.html @@ -10,15 +10,10 @@ - + - {{ 'core.settings.' + section.name | translate }} + {{ section.name | translate }} diff --git a/src/core/features/settings/pages/index/index.ts b/src/core/features/settings/pages/index/index.ts index 00e452db5..14abe5b7a 100644 --- a/src/core/features/settings/pages/index/index.ts +++ b/src/core/features/settings/pages/index/index.ts @@ -13,10 +13,14 @@ // limitations under the License. import { AfterViewInit, Component, OnDestroy, ViewChild } from '@angular/core'; -import { CoreSettingsConstants, CoreSettingsSection } from '@features/settings/constants'; +import { ActivatedRouteSnapshot, Params } from '@angular/router'; + import { CorePageItemsListManager } from '@classes/page-items-list-manager'; -import { ActivatedRouteSnapshot } from '@angular/router'; import { CoreSplitViewComponent } from '@components/split-view/split-view'; +import { CoreSettingsHelper } from '@features/settings/services/settings-helper'; +import { CoreConstants } from '@/core/constants'; +import { SHAREDFILES_PAGE_NAME } from '@features/sharedfiles/sharedfiles.module'; +import { CoreApp } from '@services/app'; @Component({ selector: 'page-core-settings-index', @@ -32,7 +36,7 @@ export class CoreSettingsIndexPage implements AfterViewInit, OnDestroy { * @inheritdoc */ ngAfterViewInit(): void { - this.sections.setItems(CoreSettingsConstants.SECTIONS); + this.sections.setItems(this.getSections()); this.sections.start(this.splitView); } @@ -43,6 +47,48 @@ export class CoreSettingsIndexPage implements AfterViewInit, OnDestroy { this.sections.destroy(); } + /** + * Get the sections. + * + * @returns Sections. + */ + protected getSections(): CoreSettingsSection[] { + const sections: CoreSettingsSection[] = [ + { + name: 'core.settings.general', + path: 'general', + icon: 'fas-wrench', + }, + { + name: 'core.settings.spaceusage', + path: 'spaceusage', + icon: 'fas-tasks', + }, + { + name: 'core.settings.synchronization', + path: 'sync', + icon: CoreConstants.ICON_SYNC, + }, + ]; + + if (CoreApp.isIOS()) { + sections.push({ + name: 'core.sharedfiles.sharedfiles', + path: SHAREDFILES_PAGE_NAME + '/list/root', + icon: 'fas-folder', + params: { manage: true }, + }); + } + + sections.push({ + name: 'core.settings.about', + path: 'about', + icon: 'fas-id-card', + }); + + return sections; + } + } /** @@ -57,11 +103,28 @@ class CoreSettingsSectionsManager extends CorePageItemsListManager - diff --git a/src/core/features/settings/pages/site/site.ts b/src/core/features/settings/pages/site/site.ts index 6fabd9e42..ec5ccc7c6 100644 --- a/src/core/features/settings/pages/site/site.ts +++ b/src/core/features/settings/pages/site/site.ts @@ -20,7 +20,6 @@ import { CoreSettingsDelegate, CoreSettingsHandlerToDisplay } from '../../servic import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; -// import { CoreSharedFiles } from '@features/sharedfiles/services/sharedfiles'; import { CoreSettingsHelper, CoreSiteSpaceUsage } from '../../services/settings-helper'; import { CoreApp } from '@services/app'; import { CoreSiteInfo } from '@classes/site'; @@ -52,7 +51,6 @@ export class CoreSitePreferencesPage implements AfterViewInit, OnDestroy { spaceUsage: 0, }; - iosSharedFiles = 0; protected sitesObserver: CoreEventObserver; protected isDestroyed = false; @@ -101,25 +99,7 @@ export class CoreSitePreferencesPage implements AfterViewInit, OnDestroy { this.siteName = currentSite!.getSiteName(); this.siteUrl = currentSite!.getURL(); - const promises: Promise[] = []; - - promises.push(CoreSettingsHelper.getSiteSpaceUsage(this.siteId) - .then((spaceUsage) => { - this.spaceUsage = spaceUsage; - - return; - })); - - /* if (this.isIOS) { - promises.push(CoreSharedFiles.getSiteSharedFiles(this.siteId) - .then((files) => { - this.iosSharedFiles = files.length; - - return; - })); - }*/ - - await Promise.all(promises); + this.spaceUsage = await CoreSettingsHelper.getSiteSpaceUsage(this.siteId); } /** @@ -224,9 +204,7 @@ class CoreSettingsSitePreferencesManager extends CorePageItemsListManager m.CoreSettingsSynchronizationPageModule), }, - // @todo sharedfiles + { + path: SHAREDFILES_PAGE_NAME, + loadChildren: () => import('@features/sharedfiles/sharedfiles-lazy.module').then(m => m.CoreSharedFilesLazyModule), + }, { path: 'about', loadChildren: () => import('./pages/about/about.module').then(m => m.CoreSettingsAboutPageModule), diff --git a/src/core/features/sharedfiles/components/components.module.ts b/src/core/features/sharedfiles/components/components.module.ts new file mode 100644 index 000000000..32b1a9f30 --- /dev/null +++ b/src/core/features/sharedfiles/components/components.module.ts @@ -0,0 +1,34 @@ +// (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 { NgModule } from '@angular/core'; + +import { CoreSharedModule } from '@/core/shared.module'; +import { CoreSharedFilesListComponent } from './list/list'; +import { CoreSharedFilesListModalComponent } from './list-modal/list-modal'; + +@NgModule({ + declarations: [ + CoreSharedFilesListComponent, + CoreSharedFilesListModalComponent, + ], + imports: [ + CoreSharedModule, + ], + exports: [ + CoreSharedFilesListComponent, + CoreSharedFilesListModalComponent, + ], +}) +export class CoreSharedFilesComponentsModule {} diff --git a/src/core/features/sharedfiles/components/list-modal/list-modal.html b/src/core/features/sharedfiles/components/list-modal/list-modal.html new file mode 100644 index 000000000..2d6998369 --- /dev/null +++ b/src/core/features/sharedfiles/components/list-modal/list-modal.html @@ -0,0 +1,19 @@ + + + + + + {{ title }} + + + + + + + + + + + + diff --git a/src/core/features/sharedfiles/components/list-modal/list-modal.ts b/src/core/features/sharedfiles/components/list-modal/list-modal.ts new file mode 100644 index 000000000..c06f27796 --- /dev/null +++ b/src/core/features/sharedfiles/components/list-modal/list-modal.ts @@ -0,0 +1,75 @@ +// (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, OnInit, Input } from '@angular/core'; +import { FileEntry } from '@ionic-native/file'; + +import { CoreFile } from '@services/file'; +import { ModalController, Translate } from '@singletons'; + +/** + * Modal to display the list of shared files. + */ +@Component({ + selector: 'core-shared-files-list-modal', + templateUrl: 'list-modal.html', +}) +export class CoreSharedFilesListModalComponent implements OnInit { + + @Input() siteId?: string; + @Input() mimetypes?: string[]; + @Input() manage?: boolean; + @Input() pick?: boolean; // To pick a file you MUST use a modal. + @Input() path?: string; + @Input() showSitePicker?: boolean; + + title?: string; + + /** + * Component being initialized. + */ + ngOnInit(): void { + this.calculateTitle(this.path); + } + + /** + * Calculate the title. + * + * @param path Path to use. + */ + calculateTitle(path?: string): void { + if (path) { + this.title = CoreFile.getFileAndDirectoryFromPath(path).name; + } else { + this.title = Translate.instant('core.sharedfiles.sharedfiles'); + } + } + + /** + * Close modal. + */ + closeModal(): void { + ModalController.dismiss(); + } + + /** + * A file was picked. + * + * @param file Picked file. + */ + filePicked(file: FileEntry): void { + ModalController.dismiss(file); + } + +} diff --git a/src/core/features/sharedfiles/components/list/list.html b/src/core/features/sharedfiles/components/list/list.html new file mode 100644 index 000000000..558525bdb --- /dev/null +++ b/src/core/features/sharedfiles/components/list/list.html @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + {{ file.name }} + + + + + + + + + + diff --git a/src/core/features/sharedfiles/components/list/list.ts b/src/core/features/sharedfiles/components/list/list.ts new file mode 100644 index 000000000..d915ba50f --- /dev/null +++ b/src/core/features/sharedfiles/components/list/list.ts @@ -0,0 +1,170 @@ +// (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, OnInit, OnDestroy, Input, Output, EventEmitter } from '@angular/core'; +import { FileEntry, DirectoryEntry } from '@ionic-native/file'; +import { IonRefresher } from '@ionic/angular'; +import { Md5 } from 'ts-md5'; + +import { CoreSharedFiles } from '@features/sharedfiles/services/sharedfiles'; +import { CoreNavigator } from '@services/navigator'; +import { CoreSites } from '@services/sites'; +import { CoreTextUtils } from '@services/utils/text'; +import { CoreEventObserver, CoreEvents } from '@singletons/events'; + +/** + * Component to display the list of shared files, either as a modal or inside a page. + */ +@Component({ + selector: 'core-shared-files-list', + templateUrl: 'list.html', +}) +export class CoreSharedFilesListComponent implements OnInit, OnDestroy { + + @Input() siteId?: string; + @Input() mimetypes?: string[]; + @Input() isModal?: boolean; // Whether the component is loaded in a modal. + @Input() manage?: boolean; + @Input() pick?: boolean; // To pick a file you MUST use a modal. + @Input() path?: string; + @Input() showSitePicker?: boolean; + @Output() onPathChanged = new EventEmitter(); + @Output() onFilePicked = new EventEmitter(); + + filesLoaded = false; + files?: (FileEntry | DirectoryEntry)[]; + + protected shareObserver?: CoreEventObserver; + + /** + * Component being initialized. + */ + ngOnInit(): void { + this.siteId = this.siteId || CoreSites.getCurrentSiteId(); + + this.loadFiles(); + + // Listen for new files shared with the app. + this.shareObserver = CoreEvents.on(CoreEvents.FILE_SHARED, (data) => { + if (data.siteId == this.siteId) { + // File was stored in current site, refresh the list. + this.filesLoaded = false; + this.loadFiles().finally(() => { + this.filesLoaded = true; + }); + } + }); + } + + /** + * Load the files. + * + * @return Promise resolved when done. + */ + protected async loadFiles(): Promise { + this.files = await CoreSharedFiles.getSiteSharedFiles(this.siteId, this.path, this.mimetypes); + this.filesLoaded = true; + } + + /** + * Refresh the list of files. + * + * @param refresher Refresher. + */ + refreshFiles(refresher: IonRefresher): void { + this.loadFiles().finally(() => { + refresher.complete(); + }); + } + + /** + * Called when a file is deleted. Remove the file from the list. + * + * @param index Position of the file. + */ + fileDeleted(index: number): void { + this.files!.splice(index, 1); + } + + /** + * Called when a file is renamed. Update the list. + * + * @param index Position of the file. + * @param data Data containing the new FileEntry. + */ + fileRenamed(index: number, data: { file: FileEntry }): void { + this.files![index] = data.file; + } + + /** + * Open a subfolder. + * + * @param folder The folder to open. + */ + openFolder(folder: DirectoryEntry): void { + const path = CoreTextUtils.concatenatePaths(this.path || '', folder.name); + + if (this.isModal) { + this.path = path; + this.filesLoaded = false; + this.loadFiles(); + this.onPathChanged.emit(path); + + return; + } + + const hash = Md5.hashAsciiStr(path); + + CoreNavigator.navigate(`../${hash}`, { + params: { + path, + manage: this.manage, + pick: this.pick, + siteId: this.siteId, + mimetypes: this.mimetypes, + isModal: false, + }, + }); + } + + /** + * Change site loaded. + * + * @param id Site to load. + */ + changeSite(id: string): void { + this.siteId = id; + this.path = ''; + this.filesLoaded = false; + this.loadFiles(); + this.onPathChanged.emit(''); + } + + /** + * A file was picked. + * + * @param file Picked file. + */ + filePicked(file: FileEntry): void { + this.onFilePicked.emit(file); + } + + /** + * Component destroyed. + */ + ngOnDestroy(): void { + this.shareObserver?.off(); + } + +} diff --git a/src/core/features/sharedfiles/pages/choose-site/choose-site.html b/src/core/features/sharedfiles/pages/choose-site/choose-site.html new file mode 100644 index 000000000..a37711cad --- /dev/null +++ b/src/core/features/sharedfiles/pages/choose-site/choose-site.html @@ -0,0 +1,32 @@ + + + + + + {{ 'core.sharedfiles.sharedfiles' | translate }} + + + + + + + +

{{ 'core.sharedfiles.chooseaccountstorefile' | translate }}

+

{{fileName}}

+
+
+ + + +

{{site.fullName}}

+

+

{{site.siteUrl}}

+
+
+
+
+
diff --git a/src/core/features/sharedfiles/pages/choose-site/choose-site.ts b/src/core/features/sharedfiles/pages/choose-site/choose-site.ts new file mode 100644 index 000000000..a802e1efa --- /dev/null +++ b/src/core/features/sharedfiles/pages/choose-site/choose-site.ts @@ -0,0 +1,108 @@ +// (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, OnInit } from '@angular/core'; +import { CoreSharedFilesHelper } from '@features/sharedfiles/services/sharedfiles-helper'; +import { FileEntry } from '@ionic-native/file'; +import { CoreFile } from '@services/file'; +import { CoreNavigator } from '@services/navigator'; +import { CoreSiteBasicInfo, CoreSites } from '@services/sites'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreUtils } from '@services/utils/utils'; + +/** + * Page to display the list of sites to choose one to store a shared file. + */ +@Component({ + selector: 'page-core-shared-files-choose-site', + templateUrl: 'choose-site.html', +}) +export class CoreSharedFilesChooseSitePage implements OnInit { + + fileName?: string; + sites?: CoreSiteBasicInfo[]; + loaded = false; + + protected filePath?: string; + protected fileEntry?: FileEntry; + protected isInbox = false; // Whether the file is in the Inbox folder. + + /** + * @inheritdoc + */ + async ngOnInit(): Promise { + this.filePath = CoreNavigator.getRouteParam('filePath'); + this.isInbox = !!CoreNavigator.getRouteBooleanParam('isInbox'); + + if (!this.filePath) { + CoreDomUtils.showErrorModal('Error reading file.'); + await CoreUtils.nextTick(); + CoreNavigator.back(); + + return; + } + + const fileAndDir = CoreFile.getFileAndDirectoryFromPath(this.filePath); + this.fileName = fileAndDir.name; + + try { + await Promise.all([ + this.loadFile(), + this.loadSites(), + ]); + } catch { + CoreDomUtils.showErrorModal('Error reading file.'); + CoreNavigator.back(); + } finally { + this.loaded = true; + } + } + + /** + * Load the file data. + * + * @return Promise resolved when done. + */ + protected async loadFile(): Promise { + this.fileEntry = await CoreFile.getExternalFile(this.filePath!); + this.fileName = this.fileEntry.name; + } + + /** + * Load sites. + * + * @return Promise resolved when done. + */ + protected async loadSites(): Promise { + this.sites = await CoreSites.getSites(); + } + + /** + * Store the file in a certain site. + * + * @param siteId Site ID. + */ + async storeInSite(siteId: string): Promise { + this.loaded = false; + + try { + await CoreSharedFilesHelper.storeSharedFileInSite(this.fileEntry!, siteId, this.isInbox); + + CoreNavigator.back(); + } finally { + this.loaded = true; + } + } + +} diff --git a/src/core/features/sharedfiles/pages/list/list.html b/src/core/features/sharedfiles/pages/list/list.html new file mode 100644 index 000000000..386c0ad7d --- /dev/null +++ b/src/core/features/sharedfiles/pages/list/list.html @@ -0,0 +1,13 @@ + + + + + + {{ title }} + + + + + + diff --git a/src/core/features/sharedfiles/pages/list/list.ts b/src/core/features/sharedfiles/pages/list/list.ts new file mode 100644 index 000000000..2525cd2db --- /dev/null +++ b/src/core/features/sharedfiles/pages/list/list.ts @@ -0,0 +1,63 @@ +// (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, OnInit } from '@angular/core'; + +import { CoreFile } from '@services/file'; +import { CoreNavigator } from '@services/navigator'; +import { Translate } from '@singletons'; + +/** + * Page to display the list of shared files. + */ +@Component({ + selector: 'page-core-shared-files-list', + templateUrl: 'list.html', +}) +export class CoreSharedFilesListPage implements OnInit { + + siteId?: string; + mimetypes?: string[]; + manage = false; + showSitePicker = false; + path = ''; + title?: string; + + /** + * @inheritdoc + */ + ngOnInit(): void { + this.siteId = CoreNavigator.getRouteParam('siteId'); + this.mimetypes = CoreNavigator.getRouteParam('mimetypes'); + this.manage = !!CoreNavigator.getRouteBooleanParam('manage'); + this.path = CoreNavigator.getRouteParam('path') || ''; + this.showSitePicker = !CoreNavigator.getRouteParam('hideSitePicker'); + + this.calculateTitle(this.path); + } + + /** + * Calculate the title. + * + * @param path Path to use. + */ + calculateTitle(path?: string): void { + if (path) { + this.title = CoreFile.getFileAndDirectoryFromPath(path).name; + } else { + this.title = Translate.instant('core.sharedfiles.sharedfiles'); + } + } + +} diff --git a/src/core/features/sharedfiles/sharedfiles-lazy.module.ts b/src/core/features/sharedfiles/sharedfiles-lazy.module.ts new file mode 100644 index 000000000..878a53cf9 --- /dev/null +++ b/src/core/features/sharedfiles/sharedfiles-lazy.module.ts @@ -0,0 +1,45 @@ +// (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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { CoreSharedModule } from '@/core/shared.module'; +import { CoreSharedFilesComponentsModule } from './components/components.module'; +import { CoreSharedFilesListPage } from './pages/list/list'; +import { CoreSharedFilesChooseSitePage } from './pages/choose-site/choose-site'; + +const routes: Routes = [ + { + path: 'choosesite', + component: CoreSharedFilesChooseSitePage, + }, + { + path: 'list/:hash', + component: CoreSharedFilesListPage, + }, +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes), + CoreSharedModule, + CoreSharedFilesComponentsModule, + ], + declarations: [ + CoreSharedFilesListPage, + CoreSharedFilesChooseSitePage, + ], +}) +export class CoreSharedFilesLazyModule {} diff --git a/src/core/services/navigator.ts b/src/core/services/navigator.ts index bd223c89d..3df8f454b 100644 --- a/src/core/services/navigator.ts +++ b/src/core/services/navigator.ts @@ -465,6 +465,21 @@ export class CoreNavigatorService { return 'param-' + (++this.lastParamId); } + /** + * Replace the route params in a path with the params values. + * + * @param path Path. + * @param params Params. + * @returns Path with params replaced. + */ + replaceRoutePathParams(path: string, params?: Params): string { + for (const name in params) { + path = path.replace(`:${name}`, params[name]); + } + + return path; + } + } export const CoreNavigator = makeSingleton(CoreNavigatorService); diff --git a/src/core/singletons/events.ts b/src/core/singletons/events.ts index 8b433b74e..21c12f149 100644 --- a/src/core/singletons/events.ts +++ b/src/core/singletons/events.ts @@ -373,6 +373,6 @@ export type CoreEventFileSharedData = { /** * Data passed to APP_LAUNCHED_URL event. */ - export type CoreEventAppLaunchedData = { +export type CoreEventAppLaunchedData = { url: string; };