MOBILE-3708 settings: Add split view in site preferences

main
Dani Palou 2021-02-23 12:09:51 +01:00
parent 54cf0c58a0
commit 9d3f4d5a29
10 changed files with 208 additions and 126 deletions

View File

@ -16,7 +16,6 @@ import { Injector, NgModule } from '@angular/core';
import { Route, RouterModule, ROUTES, Routes } from '@angular/router';
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
import { AddonMessagesSettingsHandlerService } from './services/handlers/settings';
export const AddonMessagesDiscussionRoute: Route = {
path: 'discussion',
@ -46,11 +45,6 @@ function buildRoutes(injector: Injector): Routes {
loadChildren: () => import('./pages/search/search.module')
.then(m => m.AddonMessagesSearchPageModule),
},
{
path: AddonMessagesSettingsHandlerService.PAGE_NAME,
loadChildren: () => import('./pages/settings/settings.module')
.then(m => m.AddonMessagesSettingsPageModule),
},
{
path: 'contacts', // 3.6 or greater.
loadChildren: () => import('./pages/contacts/contacts.module')

View File

@ -22,7 +22,7 @@ import { CoreMainMenuDelegate } from '@features/mainmenu/services/mainmenu-deleg
import { AddonMessagesMainMenuHandler, AddonMessagesMainMenuHandlerService } from './services/handlers/mainmenu';
import { CoreCronDelegate } from '@services/cron';
import { CoreSettingsDelegate } from '@features/settings/services/settings-delegate';
import { AddonMessagesSettingsHandler } from './services/handlers/settings';
import { AddonMessagesSettingsHandler, AddonMessagesSettingsHandlerService } from './services/handlers/settings';
import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module';
import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
import { AddonMessagesIndexLinkHandler } from './services/handlers/index-link';
@ -35,6 +35,7 @@ import { AddonMessagesSendMessageUserHandler } from './services/handlers/user-se
import { Network, NgZone } from '@singletons';
import { AddonMessagesSync } from './services/messages-sync';
import { AddonMessagesSyncCronHandler } from './services/handlers/sync-cron';
import { CoreSitePreferencesRoutingModule } from '@features/settings/pages/site/site-routing';
const mainMenuChildrenRoutes: Routes = [
{
@ -42,11 +43,18 @@ const mainMenuChildrenRoutes: Routes = [
loadChildren: () => import('./messages-lazy.module').then(m => m.AddonMessagesLazyModule),
},
];
const preferencesRoutes: Routes = [
{
path: AddonMessagesSettingsHandlerService.PAGE_NAME,
loadChildren: () => import('./pages/settings/settings.module').then(m => m.AddonMessagesSettingsPageModule),
},
];
@NgModule({
imports: [
CoreMainMenuRoutingModule.forChild({ children: mainMenuChildrenRoutes }),
CoreMainMenuTabRoutingModule.forChild( mainMenuChildrenRoutes),
CoreSitePreferencesRoutingModule.forChild(preferencesRoutes),
],
providers: [
{

View File

@ -16,7 +16,6 @@ import { Injectable } from '@angular/core';
import { CoreSettingsHandler, CoreSettingsHandlerData } from '@features/settings/services/settings-delegate';
import { makeSingleton } from '@singletons';
import { AddonMessages } from '../messages';
import { AddonMessagesMainMenuHandlerService } from './mainmenu';
/**
* Message settings handler.
@ -24,7 +23,7 @@ import { AddonMessagesMainMenuHandlerService } from './mainmenu';
@Injectable({ providedIn: 'root' })
export class AddonMessagesSettingsHandlerService implements CoreSettingsHandler {
static readonly PAGE_NAME = 'settings';
static readonly PAGE_NAME = 'messages';
name = 'AddonMessages';
priority = 600;
@ -49,7 +48,7 @@ export class AddonMessagesSettingsHandlerService implements CoreSettingsHandler
return {
icon: 'fas-comments',
title: 'addon.messages.messages',
page: AddonMessagesMainMenuHandlerService.PAGE_NAME + '/' + AddonMessagesSettingsHandlerService.PAGE_NAME,
page: AddonMessagesSettingsHandlerService.PAGE_NAME,
class: 'addon-messages-settings-handler',
};
}

View File

@ -16,7 +16,6 @@ import { Injector, NgModule } from '@angular/core';
import { RouterModule, ROUTES, Routes } from '@angular/router';
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
import { AddonNotificationsSettingsHandlerService } from './services/handlers/settings';
function buildRoutes(injector: Injector): Routes {
return [
@ -24,10 +23,6 @@ function buildRoutes(injector: Injector): Routes {
path: 'list',
loadChildren: () => import('./pages/list/list.module').then(m => m.AddonNotificationsListPageModule),
},
{
path: AddonNotificationsSettingsHandlerService.PAGE_NAME,
loadChildren: () => import('./pages/settings/settings.module').then(m => m.AddonNotificationsSettingsPageModule),
},
...buildTabMainRoutes(injector, {
redirectTo: 'list',
pathMatch: 'full',

View File

@ -24,7 +24,8 @@ import { CoreSettingsDelegate } from '@features/settings/services/settings-deleg
import { AddonNotificationsMainMenuHandler, AddonNotificationsMainMenuHandlerService } from './services/handlers/mainmenu';
import { AddonNotificationsCronHandler } from './services/handlers/cron';
import { AddonNotificationsPushClickHandler } from './services/handlers/push-click';
import { AddonNotificationsSettingsHandler } from './services/handlers/settings';
import { AddonNotificationsSettingsHandler, AddonNotificationsSettingsHandlerService } from './services/handlers/settings';
import { CoreSitePreferencesRoutingModule } from '@features/settings/pages/site/site-routing';
const routes: Routes = [
{
@ -32,11 +33,18 @@ const routes: Routes = [
loadChildren: () => import('@/addons/notifications/notifications-lazy.module').then(m => m.AddonNotificationsLazyModule),
},
];
const preferencesRoutes: Routes = [
{
path: AddonNotificationsSettingsHandlerService.PAGE_NAME,
loadChildren: () => import('./pages/settings/settings.module').then(m => m.AddonNotificationsSettingsPageModule),
},
];
@NgModule({
imports: [
CoreMainMenuRoutingModule.forChild({ children: routes }),
CoreMainMenuTabRoutingModule.forChild(routes),
CoreSitePreferencesRoutingModule.forChild(preferencesRoutes),
],
exports: [CoreMainMenuRoutingModule],
providers: [

View File

@ -18,7 +18,6 @@ import { CoreLocalNotifications } from '@services/local-notifications';
import { makeSingleton } from '@singletons';
import { CoreSettingsHandler, CoreSettingsHandlerData } from '@features/settings/services/settings-delegate';
import { AddonNotifications } from '../notifications';
import { AddonNotificationsMainMenuHandlerService } from './mainmenu';
/**
* Notifications settings handler.
@ -26,7 +25,7 @@ import { AddonNotificationsMainMenuHandlerService } from './mainmenu';
@Injectable({ providedIn: 'root' })
export class AddonNotificationsSettingsHandlerService implements CoreSettingsHandler {
static readonly PAGE_NAME = 'settings';
static readonly PAGE_NAME = 'notifications';
name = 'AddonNotifications';
priority = 500;
@ -50,7 +49,7 @@ export class AddonNotificationsSettingsHandlerService implements CoreSettingsHan
return {
icon: 'fas-bell',
title: 'addon.notifications.notifications',
page: AddonNotificationsMainMenuHandlerService.PAGE_NAME + '/' + AddonNotificationsSettingsHandlerService.PAGE_NAME,
page: AddonNotificationsSettingsHandlerService.PAGE_NAME,
class: 'addon-notifications-settings-handler',
};
}

View File

@ -0,0 +1,33 @@
// (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 { InjectionToken, ModuleWithProviders, NgModule } from '@angular/core';
import { ModuleRoutesConfig } from '@/app/app-routing.module';
export const SITE_PREFERENCES_ROUTES = new InjectionToken('SITE_PREFERENCES_ROUTES');
@NgModule()
export class CoreSitePreferencesRoutingModule {
static forChild(routes: ModuleRoutesConfig): ModuleWithProviders<CoreSitePreferencesRoutingModule> {
return {
ngModule: CoreSitePreferencesRoutingModule,
providers: [
{ provide: SITE_PREFERENCES_ROUTES, multi: true, useValue: routes },
],
};
}
}

View File

@ -9,10 +9,11 @@
</ion-toolbar>
</ion-header>
<ion-content>
<ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshData($event)">
<core-split-view>
<ion-refresher slot="fixed" [disabled]="!handlers.loaded" (ionRefresh)="refreshData($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="handlers.loaded">
<ion-list>
<ion-item *ngIf="siteInfo" class="ion-text-wrap">
<ion-label>
@ -25,7 +26,7 @@
</ion-label>
</ion-item>
<ion-item-divider><ion-label></ion-label></ion-item-divider>
<ion-item *ngIf="isIOS"
<!-- <ion-item *ngIf="isIOS"
(click)="openHandler('CoreSharedFilesListPage', {manage: true, siteId: siteId, hideSitePicker: true})"
[title]="'core.sharedfiles.sharedfiles' | translate"
[class.core-selected-item]="'CoreSharedFilesListPage' == selectedPage" detail>
@ -34,11 +35,11 @@
<h2>{{ 'core.sharedfiles.sharedfiles' | translate }}</h2>
</ion-label>
<ion-badge slot="end">{{ iosSharedFiles }}</ion-badge>
</ion-item>
</ion-item> -->
<ion-item *ngFor="let handler of handlers" [ngClass]="['core-settings-handler', handler.class]"
(click)="openHandler(handler.page, handler.params)" [title]="handler.title | translate" detail
[class.core-selected-item]="handler.page == selectedPage">
<ion-item *ngFor="let handler of handlers.items" [ngClass]="['core-settings-handler', handler.class]"
[title]="handler.title | translate" detail="true" (click)="handlers.select(handler)"
[class.core-selected-item]="handlers.isSelected(handler)">
<ion-icon [name]="handler.icon" slot="start" *ngIf="handler.icon">
</ion-icon>
<ion-label>
@ -77,4 +78,5 @@
</ion-card>
</ion-list>
</core-loading>
</core-split-view>
</ion-content>

View File

@ -12,26 +12,51 @@
// 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 { Injector, NgModule } from '@angular/core';
import { RouterModule, ROUTES, Routes } from '@angular/router';
import { CoreSharedModule } from '@/core/shared.module';
import { CoreSitePreferencesPage } from './site';
import { conditionalRoutes, resolveModuleRoutes } from '@/app/app-routing.module';
import { SITE_PREFERENCES_ROUTES } from './site-routing';
import { CoreScreen } from '@services/screen';
const routes: Routes = [
function buildRoutes(injector: Injector): Routes {
const routes = resolveModuleRoutes(injector, SITE_PREFERENCES_ROUTES);
const mobileRoutes: Routes = [
{
path: '',
component: CoreSitePreferencesPage,
},
...routes.siblings,
];
const tabletRoutes: Routes = [
{
path: '',
component: CoreSitePreferencesPage,
children: routes.siblings,
},
];
return [
...conditionalRoutes(mobileRoutes, () => CoreScreen.instance.isMobile),
...conditionalRoutes(tabletRoutes, () => CoreScreen.instance.isTablet),
];
}
@NgModule({
providers: [
{ provide: ROUTES, multi: true, useFactory: buildRoutes, deps: [Injector] },
],
declarations: [
CoreSitePreferencesPage,
],
imports: [
RouterModule.forChild(routes),
CoreSharedModule,
],
exports: [RouterModule],
})
export class CoreSitePreferencesPageModule {}

View File

@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Params } from '@angular/router';
import { AfterViewInit, Component, OnDestroy, ViewChild } from '@angular/core';
import { ActivatedRouteSnapshot, Params } from '@angular/router';
import { IonRefresher } from '@ionic/angular';
import { CoreSettingsDelegate, CoreSettingsHandlerData } from '../../services/settings-delegate';
import { CoreSettingsDelegate, CoreSettingsHandlerToDisplay } from '../../services/settings-delegate';
import { CoreEventObserver, CoreEvents, CoreEventSiteUpdatedData } from '@singletons/events';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
@ -26,7 +26,8 @@ import { CoreApp } from '@services/app';
import { CoreSiteInfo } from '@classes/site';
import { Translate } from '@singletons';
import { CoreNavigator } from '@services/navigator';
import { CoreScreen } from '@services/screen';
import { CorePageItemsListManager } from '@classes/page-items-list-manager';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
/**
* Page that displays the list of site settings pages.
@ -35,12 +36,13 @@ import { CoreScreen } from '@services/screen';
selector: 'page-core-site-preferences',
templateUrl: 'site.html',
})
export class CoreSitePreferencesPage implements OnInit, OnDestroy {
export class CoreSitePreferencesPage implements AfterViewInit, OnDestroy {
@ViewChild(CoreSplitViewComponent) splitView!: CoreSplitViewComponent;
handlers: CoreSettingsSitePreferencesManager;
isIOS: boolean;
selectedPage?: string;
handlers: CoreSettingsHandlerData[] = [];
siteId: string;
siteInfo?: CoreSiteInfo;
siteName?: string;
@ -50,7 +52,6 @@ export class CoreSitePreferencesPage implements OnInit, OnDestroy {
spaceUsage: 0,
};
loaded = false;
iosSharedFiles = 0;
protected sitesObserver: CoreEventObserver;
protected isDestroyed = false;
@ -59,6 +60,7 @@ export class CoreSitePreferencesPage implements OnInit, OnDestroy {
this.isIOS = CoreApp.isIOS();
this.siteId = CoreSites.getCurrentSiteId();
this.handlers = new CoreSettingsSitePreferencesManager(CoreSitePreferencesPage);
this.sitesObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, (data: CoreEventSiteUpdatedData) => {
if (data.siteId == this.siteId) {
@ -70,30 +72,29 @@ export class CoreSitePreferencesPage implements OnInit, OnDestroy {
/**
* View loaded.
*/
ngOnInit(): void {
// @todo this.selectedPage = route.snapshot.paramMap.get('page') || undefined;
async ngAfterViewInit(): Promise<void> {
const pageToOpen = CoreNavigator.getRouteParam('page');
this.fetchData().finally(() => {
this.loaded = true;
try {
await this.fetchData();
} finally {
if (this.selectedPage) {
this.openHandler(this.selectedPage);
} else if (CoreScreen.isTablet) {
if (this.isIOS) {
// @todo
// this.openHandler('CoreSharedFilesListPage', { manage: true, siteId: this.siteId, hideSitePicker: true });
} else if (this.handlers.length > 0) {
this.openHandler(this.handlers[0].page, this.handlers[0].params);
const handler = pageToOpen ? this.handlers.items.find(handler => handler.page == pageToOpen) : undefined;
if (handler) {
this.handlers.select(handler);
this.handlers.watchSplitViewOutlet(this.splitView);
} else {
this.handlers.start(this.splitView);
}
}
});
}
/**
* Fetch Data.
*/
protected async fetchData(): Promise<void> {
this.handlers = CoreSettingsDelegate.getHandlers();
this.handlers.setItems(CoreSettingsDelegate.getHandlers());
const currentSite = CoreSites.getCurrentSite();
this.siteInfo = currentSite!.getInfo();
@ -170,18 +171,6 @@ export class CoreSitePreferencesPage implements OnInit, OnDestroy {
}
}
/**
* Open a handler.
*
* @param page Page to open.
* @param params Params of the page to open.
*/
openHandler(page: string, params?: Params): void {
this.selectedPage = page;
// this.splitviewCtrl.push(page, params);
CoreNavigator.navigateToSitePath(page, { params });
}
/**
* Show information about space usage actions.
*/
@ -211,3 +200,33 @@ export class CoreSitePreferencesPage implements OnInit, OnDestroy {
}
}
/**
* Helper class to manage sections.
*/
class CoreSettingsSitePreferencesManager extends CorePageItemsListManager<CoreSettingsHandlerToDisplay> {
/**
* @inheritdoc
*/
protected getItemPath(handler: CoreSettingsHandlerToDisplay): string {
return handler.page;
}
/**
* @inheritdoc
*/
protected getItemQueryParams(handler: CoreSettingsHandlerToDisplay): Params {
return handler.params || {};
}
/**
* @inheritdoc
*/
protected getSelectedItemPath(route: ActivatedRouteSnapshot): string | null {
// @todo: routeConfig doesn't have a path after refreshing the app.
// route.component is null too, and route.parent.url is empty.
return route.parent?.routeConfig?.path ?? null;
}
}