MOBILE-3594 sitehome: Fix header buttons on sitehome

main
Pau Ferrer Ocaña 2020-11-20 17:05:30 +01:00
parent 2ce1950210
commit 55da132b9b
9 changed files with 230 additions and 65 deletions

View File

@ -33,6 +33,9 @@ import { CoreConstants } from '@/core/constants';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { NavigationOptions } from '@ionic/angular/providers/nav-controller'; import { NavigationOptions } from '@ionic/angular/providers/nav-controller';
import { Params } from '@angular/router'; import { Params } from '@angular/router';
import { CoreNavBarButtonsComponent } from '../navbar-buttons/navbar-buttons';
import { CoreDomUtils } from '@/core/services/utils/dom';
import { StackEvent } from '@ionic/angular/directives/navigation/stack-utils';
/** /**
* This component displays some top scrollable tabs that will autohide on vertical scroll. * This component displays some top scrollable tabs that will autohide on vertical scroll.
@ -105,6 +108,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges, OnDe
protected isInTransition = false; // Weather Slides is in transition. protected isInTransition = false; // Weather Slides is in transition.
protected slidesSwiper: any; protected slidesSwiper: any;
protected slidesSwiperLoaded = false; protected slidesSwiperLoaded = false;
protected stackEventsSubscription?: Subscription;
constructor( constructor(
protected element: ElementRef, protected element: ElementRef,
@ -151,6 +155,21 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges, OnDe
return; return;
} }
this.stackEventsSubscription = this.ionTabs!.outlet.stackEvents.subscribe(async (stackEvent: StackEvent) => {
if (this.isCurrentView) {
const content = stackEvent.enteringView.element.querySelector('ion-content');
this.showHideNavBarButtons(stackEvent.enteringView.element.tagName);
if (content) {
const scroll = await content.getScrollElement();
content.scrollEvents = true;
content.addEventListener('ionScroll', (e: CustomEvent): void => {
this.showHideTabs(e, scroll);
});
}
}
});
this.tabBarElement = this.element.nativeElement.querySelector('ion-tab-bar'); this.tabBarElement = this.element.nativeElement.querySelector('ion-tab-bar');
this.tabsElement = this.element.nativeElement.querySelector('ion-tabs'); this.tabsElement = this.element.nativeElement.querySelector('ion-tabs');
@ -576,18 +595,28 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges, OnDe
this.selectedIndex = index; this.selectedIndex = index;
this.ionChange.emit(selectedTab); this.ionChange.emit(selectedTab);
}
}
const content = this.ionTabs!.outlet.nativeEl.querySelector('ion-content'); /**
* Get all child core-navbar-buttons and show or hide depending on the page state.
* We need to use querySelectorAll because ContentChildren doesn't work with ng-template.
* https://github.com/angular/angular/issues/14842
*
* @param activatedPageName Activated page name.
*/
protected showHideNavBarButtons(activatedPageName: string): void {
const elements = this.ionTabs!.outlet.nativeEl.querySelectorAll('core-navbar-buttons');
const domUtils = CoreDomUtils.instance;
elements.forEach((element) => {
const instance: CoreNavBarButtonsComponent = domUtils.getInstanceByElement(element);
if (content) { if (instance) {
const scroll = await content.getScrollElement(); const pagetagName = element.closest('.ion-page')?.tagName;
content.scrollEvents = true; instance.forceHide(activatedPageName != pagetagName);
content.addEventListener('ionScroll', (e: CustomEvent): void => { }
this.showHideTabs(e, scroll);
}); });
} }
}
}
/** /**
* Adapt tabs to a window resize. * Adapt tabs to a window resize.
@ -607,6 +636,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges, OnDe
if (this.resizeFunction) { if (this.resizeFunction) {
window.removeEventListener('resize', this.resizeFunction); window.removeEventListener('resize', this.resizeFunction);
} }
this.stackEventsSubscription?.unsubscribe();
} }
} }

View File

@ -1,3 +1,16 @@
<core-navbar-buttons slot="end">
<ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
<ion-icon name="fas-search" slot="icon-only"></ion-icon>
</ion-button>
<core-context-menu>
<core-context-menu-item *ngIf="(downloadCourseEnabled || downloadCoursesEnabled)" [priority]="1000"
[content]="'core.settings.showdownloadoptions' | translate" (action)="toggleDownload()"
[iconAction]="downloadEnabledIcon"></core-context-menu-item>
<core-context-menu-item *ngIf="(downloadCourseEnabled || downloadCoursesEnabled)" [priority]="500"
[content]="'addon.storagemanager.managestorage' | translate"
(action)="manageCoursesStorage()" iconAction="fas-archive"></core-context-menu-item>
</core-context-menu>
</core-navbar-buttons>
<ion-content> <ion-content>
<!-- @todo --> <!-- @todo -->
<core-empty-box icon="fa-home" [message]="'core.courses.nocourses' | translate"> <core-empty-box icon="fa-home" [message]="'core.courses.nocourses' | translate">

View File

@ -12,25 +12,93 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { NavController } from '@ionic/angular';
import { CoreCourses, CoreCoursesProvider } from '../../services/courses';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreSites } from '@services/sites';
/** /**
* Page that displays the Home. * Page that displays the dashboard page.
*/ */
@Component({ @Component({
selector: 'page-core-courses-dashboard', selector: 'page-core-courses-dashboard',
templateUrl: 'dashboard.html', templateUrl: 'dashboard.html',
styleUrls: ['dashboard.scss'], styleUrls: ['dashboard.scss'],
}) })
export class CoreCoursesDashboardPage implements OnInit { export class CoreCoursesDashboardPage implements OnInit, OnDestroy {
searchEnabled = false;
downloadEnabled = false;
downloadCourseEnabled = false;
downloadCoursesEnabled = false;
downloadEnabledIcon = 'far-square';
protected updateSiteObserver?: CoreEventObserver;
siteName = 'Hello world'; siteName = 'Hello world';
constructor(
protected navCtrl: NavController,
) { }
/** /**
* Initialize the component. * Initialize the component.
*/ */
ngOnInit(): void { ngOnInit(): void {
// @todo this.searchEnabled = !CoreCourses.instance.isSearchCoursesDisabledInSite();
this.downloadCourseEnabled = !CoreCourses.instance.isDownloadCourseDisabledInSite();
this.downloadCoursesEnabled = !CoreCourses.instance.isDownloadCoursesDisabledInSite();
// Refresh the enabled flags if site is updated.
this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
this.searchEnabled = !CoreCourses.instance.isSearchCoursesDisabledInSite();
this.downloadCourseEnabled = !CoreCourses.instance.isDownloadCourseDisabledInSite();
this.downloadCoursesEnabled = !CoreCourses.instance.isDownloadCoursesDisabledInSite();
this.switchDownload(this.downloadEnabled && this.downloadCourseEnabled && this.downloadCoursesEnabled);
}, CoreSites.instance.getCurrentSiteId());
} }
/**
* Toggle download enabled.
*/
toggleDownload(): void {
this.switchDownload(!this.downloadEnabled);
}
/**
* Convenience function to switch download enabled.
*
* @param enable If enable or disable.
*/
protected switchDownload(enable: boolean): void {
this.downloadEnabled = (this.downloadCourseEnabled || this.downloadCoursesEnabled) && enable;
this.downloadEnabledIcon = this.downloadEnabled ? 'far-check-square' : 'far-square';
CoreEvents.trigger(CoreCoursesProvider.EVENT_DASHBOARD_DOWNLOAD_ENABLED_CHANGED, { enabled: this.downloadEnabled });
}
/**
* Open page to manage courses storage.
*/
manageCoursesStorage(): void {
// @todo this.navCtrl.navigateForward(['/courses/storage']);
}
/**
* Go to search courses.
*/
openSearch(): void {
this.navCtrl.navigateForward(['/courses/search']);
}
/**
* Component being destroyed.
*/
ngOnDestroy(): void {
this.updateSiteObserver?.off();
}
} }

View File

@ -10,16 +10,16 @@
<ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate"> <ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
<ion-icon name="fas-search" slot="icon-only"></ion-icon> <ion-icon name="fas-search" slot="icon-only"></ion-icon>
</ion-button> </ion-button>
<ng-container *ngIf="downloadAllCoursesEnabled && courses && courses.length >= 2"> <ion-button [hidden]="!downloadAllCoursesEnabled || !courses || courses.length < 2 || downloadAllCoursesLoading"
<ion-button *ngIf="!downloadAllCoursesLoading" (click)="prefetchCourses()" (click)="prefetchCourses()" [attr.aria-label]="'core.courses.downloadcourses' | translate">
[attr.aria-label]="'core.courses.downloadcourses' | translate">
<ion-icon [name]="downloadAllCoursesIcon" slot="icon-only"></ion-icon> <ion-icon [name]="downloadAllCoursesIcon" slot="icon-only"></ion-icon>
</ion-button> </ion-button>
<ion-spinner *ngIf="downloadAllCoursesBadge == '' && downloadAllCoursesLoading" <ion-spinner [hidden]="!downloadAllCoursesEnabled || !courses || courses.length < 2 ||
downloadAllCoursesBadge != '' || !downloadAllCoursesLoading"
[attr.aria-label]="'core.loading' | translate"></ion-spinner> [attr.aria-label]="'core.loading' | translate"></ion-spinner>
<ion-badge *ngIf="downloadAllCoursesBadge != '' && downloadAllCoursesLoading" <ion-badge [hidden]="!downloadAllCoursesEnabled || !courses || courses.length < 2 || !downloadAllCoursesLoading ||
downloadAllCoursesBadge == '' || !downloadAllCoursesLoading"
[attr.aria-label]="'core.downloading' | translate">{{downloadAllCoursesBadge}}</ion-badge> [attr.aria-label]="'core.downloading' | translate">{{downloadAllCoursesBadge}}</ion-badge>
</ng-container>
</core-navbar-buttons> </core-navbar-buttons>
</ion-buttons> </ion-buttons>
</ion-toolbar> </ion-toolbar>

View File

@ -9,14 +9,6 @@
<img src="assets/img/login_logo.png" class="core-header-logo" [alt]="siteName"> <img src="assets/img/login_logo.png" class="core-header-logo" [alt]="siteName">
</ion-title> </ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
<ion-icon name="fas-search" slot="icon-only"></ion-icon>
</ion-button>
<core-context-menu>
<core-context-menu-item *ngIf="(downloadCourseEnabled || downloadCoursesEnabled)" [priority]="500"
[content]="'addon.storagemanager.managestorage' | translate"
(action)="manageCoursesStorage()" iconAction="fas-archive"></core-context-menu-item>
</core-context-menu>
</ion-buttons> </ion-buttons>
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>

View File

@ -12,14 +12,13 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, ViewChild } from '@angular/core';
import { NavController } from '@ionic/angular';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreHomeDelegate, CoreHomeHandlerToDisplay } from '../../services/home.delegate'; import { CoreHomeDelegate, CoreHomeHandlerToDisplay } from '../../services/home.delegate';
import { CoreCourses } from '@features/courses/services/courses';
import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreTabsComponent } from '@components/tabs/tabs';
/** /**
* Page that displays the Home. * Page that displays the Home.
@ -31,20 +30,19 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events';
}) })
export class CoreHomePage implements OnInit { export class CoreHomePage implements OnInit {
@ViewChild(CoreTabsComponent) tabsComponent?: CoreTabsComponent;
siteName!: string; siteName!: string;
tabs: CoreHomeHandlerToDisplay[] = []; tabs: CoreHomeHandlerToDisplay[] = [];
loaded = false; loaded = false;
selectedTab?: number; selectedTab?: number;
searchEnabled = false;
downloadCourseEnabled = false;
downloadCoursesEnabled = false;
protected subscription?: Subscription; protected subscription?: Subscription;
protected updateSiteObserver?: CoreEventObserver; protected updateSiteObserver?: CoreEventObserver;
constructor( constructor(
protected homeDelegate: CoreHomeDelegate, protected homeDelegate: CoreHomeDelegate,
protected navCtrl: NavController,
) { ) {
this.loadSiteName(); this.loadSiteName();
} }
@ -53,20 +51,12 @@ export class CoreHomePage implements OnInit {
* Initialize the component. * Initialize the component.
*/ */
ngOnInit(): void { ngOnInit(): void {
this.searchEnabled = !CoreCourses.instance.isSearchCoursesDisabledInSite();
this.downloadCourseEnabled = !CoreCourses.instance.isDownloadCourseDisabledInSite();
this.downloadCoursesEnabled = !CoreCourses.instance.isDownloadCoursesDisabledInSite();
this.subscription = this.homeDelegate.getHandlersObservable().subscribe((handlers) => { this.subscription = this.homeDelegate.getHandlersObservable().subscribe((handlers) => {
handlers && this.initHandlers(handlers); handlers && this.initHandlers(handlers);
}); });
// Refresh the enabled flags if site is updated. // Refresh the enabled flags if site is updated.
this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => { this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
this.searchEnabled = !CoreCourses.instance.isSearchCoursesDisabledInSite();
this.downloadCourseEnabled = !CoreCourses.instance.isDownloadCourseDisabledInSite();
this.downloadCoursesEnabled = !CoreCourses.instance.isDownloadCoursesDisabledInSite();
this.loadSiteName(); this.loadSiteName();
}, CoreSites.instance.getCurrentSiteId()); }, CoreSites.instance.getCurrentSiteId());
} }
@ -114,17 +104,17 @@ export class CoreHomePage implements OnInit {
} }
/** /**
* Open page to manage courses storage. * User entered the page.
*/ */
manageCoursesStorage(): void { ionViewDidEnter(): void {
// @todo this.navCtrl.navigateForward(['/courses/storage']); this.tabsComponent?.ionViewDidEnter();
} }
/** /**
* Go to search courses. * User left the page.
*/ */
openSearch(): void { ionViewDidLeave(): void {
this.navCtrl.navigateForward(['/courses/search']); this.tabsComponent?.ionViewDidLeave();
} }
} }

View File

@ -1,3 +1,16 @@
<core-navbar-buttons slot="end">
<ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
<ion-icon name="fas-search" slot="icon-only"></ion-icon>
</ion-button>
<core-context-menu>
<core-context-menu-item *ngIf="(downloadCourseEnabled || downloadCoursesEnabled)" [priority]="1000"
[content]="'core.settings.showdownloadoptions' | translate" (action)="toggleDownload()"
[iconAction]="downloadEnabledIcon"></core-context-menu-item>
<core-context-menu-item *ngIf="(downloadCourseEnabled || downloadCoursesEnabled)" [priority]="500"
[content]="'addon.storagemanager.managestorage' | translate"
(action)="manageCoursesStorage()" iconAction="fas-archive"></core-context-menu-item>
</core-context-menu>
</core-navbar-buttons>
<ion-content> <ion-content>
<ion-refresher slot="fixed" [disabled]="!dataLoaded" <ion-refresher slot="fixed" [disabled]="!dataLoaded"
(ionRefresh)="doRefresh($event)"> (ionRefresh)="doRefresh($event)">

View File

@ -12,16 +12,18 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { IonRefresher } from '@ionic/angular'; import { IonRefresher, NavController } from '@ionic/angular';
import { CoreSite, CoreSiteConfig } from '@classes/site'; import { CoreSite, CoreSiteConfig } from '@classes/site';
import { CoreCourse, CoreCourseSection } from '@features/course/services/course'; import { CoreCourse, CoreCourseSection } from '@features/course/services/course';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreSiteHome } from '@features/sitehome/services/sitehome'; import { CoreSiteHome } from '@features/sitehome/services/sitehome';
// import { CoreCourseHelperProvider } from '@features/course/services/helper'; import { CoreCourses, CoreCoursesProvider } from '@features//courses/services/courses';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreCourseHelper } from '@features/course/services/course.helper';
/** /**
* Page that displays site home index. * Page that displays site home index.
@ -30,9 +32,8 @@ import { CoreSiteHome } from '@features/sitehome/services/sitehome';
selector: 'page-core-sitehome-index', selector: 'page-core-sitehome-index',
templateUrl: 'index.html', templateUrl: 'index.html',
}) })
export class CoreSiteHomeIndexPage implements OnInit { export class CoreSiteHomeIndexPage implements OnInit, OnDestroy {
// @todo @Input() downloadEnabled: boolean;
// @todo @ViewChild(CoreBlockCourseBlocksComponent) courseBlocksComponent: CoreBlockCourseBlocksComponent; // @todo @ViewChild(CoreBlockCourseBlocksComponent) courseBlocksComponent: CoreBlockCourseBlocksComponent;
dataLoaded = false; dataLoaded = false;
@ -44,13 +45,19 @@ export class CoreSiteHomeIndexPage implements OnInit {
items: string[] = []; items: string[] = [];
siteHomeId?: number; siteHomeId?: number;
currentSite?: CoreSite; currentSite?: CoreSite;
searchEnabled = false;
downloadEnabled = false;
downloadCourseEnabled = false;
downloadCoursesEnabled = false;
downloadEnabledIcon = 'far-square';
protected updateSiteObserver?: CoreEventObserver;
constructor( constructor(
protected route: ActivatedRoute, protected route: ActivatedRoute,
protected navCtrl: NavController,
// @todo private prefetchDelegate: CoreCourseModulePrefetchDelegate, // @todo private prefetchDelegate: CoreCourseModulePrefetchDelegate,
) { ) {}
}
/** /**
* Page being initialized. * Page being initialized.
@ -58,13 +65,26 @@ export class CoreSiteHomeIndexPage implements OnInit {
ngOnInit(): void { ngOnInit(): void {
const navParams = this.route.snapshot.queryParams; const navParams = this.route.snapshot.queryParams;
this.searchEnabled = !CoreCourses.instance.isSearchCoursesDisabledInSite();
this.downloadCourseEnabled = !CoreCourses.instance.isDownloadCourseDisabledInSite();
this.downloadCoursesEnabled = !CoreCourses.instance.isDownloadCoursesDisabledInSite();
// Refresh the enabled flags if site is updated.
this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
this.searchEnabled = !CoreCourses.instance.isSearchCoursesDisabledInSite();
this.downloadCourseEnabled = !CoreCourses.instance.isDownloadCourseDisabledInSite();
this.downloadCoursesEnabled = !CoreCourses.instance.isDownloadCoursesDisabledInSite();
this.switchDownload(this.downloadEnabled && this.downloadCourseEnabled && this.downloadCoursesEnabled);
}, CoreSites.instance.getCurrentSiteId());
this.currentSite = CoreSites.instance.getCurrentSite()!; this.currentSite = CoreSites.instance.getCurrentSite()!;
this.siteHomeId = this.currentSite.getSiteHomeId(); this.siteHomeId = this.currentSite.getSiteHomeId();
const module = navParams['module']; const module = navParams['module'];
if (module) { if (module) {
// @todo const modParams = navParams.get('modParams'); // @todo const modParams = navParams.get('modParams');
// courseHelper.openModule(module, this.siteHomeId, undefined, modParams); // CoreCourseHelper.instance.openModule(module, this.siteHomeId, undefined, modParams);
} }
this.loadContent().finally(() => { this.loadContent().finally(() => {
@ -92,8 +112,8 @@ export class CoreSiteHomeIndexPage implements OnInit {
this.section = config.numsections ? sections.find((section) => section.section == 1) : undefined; this.section = config.numsections ? sections.find((section) => section.section == 1) : undefined;
if (this.section) { if (this.section) {
this.section.hasContent = false; this.section.hasContent = false;
/* @todo this.section.hasContent = this.courseHelper.sectionHasContent(this.section); this.section.hasContent = CoreCourseHelper.instance.sectionHasContent(this.section);
this.hasContent = this.courseHelper.addHandlerDataForModules( /* @todo this.hasContent = CoreCourseHelper.instance.addHandlerDataForModules(
[this.section], [this.section],
this.siteHomeId, this.siteHomeId,
undefined, undefined,
@ -152,4 +172,43 @@ export class CoreSiteHomeIndexPage implements OnInit {
}); });
} }
/**
* Toggle download enabled.
*/
toggleDownload(): void {
this.switchDownload(!this.downloadEnabled);
}
/**
* Convenience function to switch download enabled.
*
* @param enable If enable or disable.
*/
protected switchDownload(enable: boolean): void {
this.downloadEnabled = (this.downloadCourseEnabled || this.downloadCoursesEnabled) && enable;
this.downloadEnabledIcon = this.downloadEnabled ? 'far-check-square' : 'far-square';
CoreEvents.trigger(CoreCoursesProvider.EVENT_DASHBOARD_DOWNLOAD_ENABLED_CHANGED, { enabled: this.downloadEnabled });
}
/**
* Open page to manage courses storage.
*/
manageCoursesStorage(): void {
// @todo this.navCtrl.navigateForward(['/courses/storage']);
}
/**
* Go to search courses.
*/
openSearch(): void {
this.navCtrl.navigateForward(['/courses/search']);
}
/**
* Component being destroyed.
*/
ngOnDestroy(): void {
this.updateSiteObserver?.off();
}
} }