/* * Copyright (C) 2023 StApps * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ import {AfterViewInit, Component, HostListener, Input, OnInit, ViewChild} from '@angular/core'; import {Location} from '@angular/common'; import {ActivatedRoute, Router} from '@angular/router'; import {AnimationController, IonRouterOutlet} from '@ionic/angular'; import {SharedAxisChoreographer} from '../../../animation/animation-choreographer'; import {materialSharedAxisX} from '../../../animation/material-motion'; import {ScheduleResponsiveBreakpoint} from './schema/schema'; import {CalendarService} from '../../calendar/calendar.service'; import moment from 'moment'; import {fabExpand} from '../../../animation/fab-expand'; /** * This needs to be sorted by break point low -> high * * Last entry must have `until: Infinity` */ const responsiveConfig: ScheduleResponsiveBreakpoint[] = [ { until: 768, days: 3, startOf: 'day', }, { until: 1700, days: 3, startOf: 'day', }, { until: Number.POSITIVE_INFINITY, days: 7, startOf: 'week', }, ]; /** * Component that displays the schedule */ @Component({ selector: 'stapps-schedule-page', templateUrl: 'schedule-page.html', styleUrls: ['schedule-page.scss'], animations: [materialSharedAxisX], }) export class SchedulePageComponent implements OnInit, AfterViewInit { /** * Current width of the window */ private currentWindowWidth: number = window.innerWidth; /** * Actual Segment Tab */ actualSegmentValue?: string | null; /** * Trigger event to go to today in calendar component */ /** * Layout */ layout: ScheduleResponsiveBreakpoint = SchedulePageComponent.getDaysToDisplay(this.currentWindowWidth); @ViewChild('segment') segmentView!: HTMLIonSegmentElement; /** * Show the navigation drawer */ @Input() showDrawer = true; /** * Search value from search bar */ queryText: string; /** * Choreographer for the tab switching */ tabChoreographer: SharedAxisChoreographer; isModalOpen = false; fabAnimation = fabExpand(this.animationController); /** * Amount of days that should be shown according to current display width */ static getDaysToDisplay(width: number): ScheduleResponsiveBreakpoint { // the search could be optimized, but probably would have little // actual effect with five entries. // we can be sure we get an hit when the last value.until is infinity // (unless someone has a display that reaches across the universe) return ( responsiveConfig.find(value => width < value.until) ?? responsiveConfig[responsiveConfig.length - 1] ); } constructor( private readonly activatedRoute: ActivatedRoute, private calendarService: CalendarService, readonly routerOutlet: IonRouterOutlet, private router: Router, private animationController: AnimationController, private location: Location, ) {} ngOnInit() { this.onInit(); } /** * ngOnInit is not reliably called after first navigation to app/schedule. This leads to URL and segmentView being out of sync. * ionViewWillEnter is called on second, third, ... navigation to app/schedule */ ionViewWillEnter() { this.onInit(); this.segmentView.value = this.tabChoreographer.currentValue; } ngAfterViewInit() { this.segmentView.value = this.tabChoreographer.currentValue; } onInit() { this.tabChoreographer = new SharedAxisChoreographer(this.activatedRoute.snapshot.paramMap.get('mode'), [ 'calendar', 'recurring', 'single', ]); } /** * Resize callback * * Note: this may not fire when the browser transfers from full screen to windowed * (Firefox & Chrome tested) */ @HostListener('window:resize', ['$event']) onResize(_: UIEvent) { const current = SchedulePageComponent.getDaysToDisplay(this.currentWindowWidth); const next = SchedulePageComponent.getDaysToDisplay(window.innerWidth); this.currentWindowWidth = window.innerWidth; if (current.days === next.days) { this.layout = next; } } /** * When the segment changes */ onSegmentChange() { const url = this.router.createUrlTree(['schedule', this.segmentView.value]).toString(); this.location.go(url); this.tabChoreographer.changeViewForState(this.segmentView.value); } onTodayClick() { this.calendarService.emitGoToDate(moment().startOf('day')); } }