import { Injectable, OnDestroy } from '@angular/core'; import { SettingsService } from './settings.service'; import { SelfUpdaterService } from './self-updater.service'; import { Subject, timer, Subscription } from 'rxjs'; import { ActivationStart, Router } from '@angular/router'; import { SlideShowService } from '../../display/slide-show.service'; import { filter, switchMap } from 'rxjs/operators'; import * as isWithinRange from 'date-fns/is_within_range'; import * as min from 'date-fns/min'; import * as max from 'date-fns/max'; const TIMER_UPDATE_POLL_INTERVAL = 30000; const TIME_SEPARATOR = ':'; @Injectable() export class TimerService implements OnDestroy { public paused = false; public autoSwitch = false; private slideShowTimer: Subscription; private selfUpdateCheckerTimer: Subscription; private slideTimerSubject: Subject = new Subject(); private slideIntervalSubscription: Subscription; constructor(private settings: SettingsService, private selfUpdaterService: SelfUpdaterService, private router: Router, private slideShowService: SlideShowService) { const timerSUC = timer(TIMER_UPDATE_POLL_INTERVAL, TIMER_UPDATE_POLL_INTERVAL); this.selfUpdateCheckerTimer = timerSUC.subscribe(() => { this.selfUpdaterService.checkAndReloadIfNecessary(); }); this.slideShowTimer = this.slideTimerSubject .pipe(switchMap((period: number) => timer(period))) .subscribe(() => this.changeSlide()); this.setSlideTimer(this.settings.slideInterval); this.autoSwitch = false; this.router.events .pipe(filter(event => event instanceof ActivationStart)) .subscribe((event: ActivationStart) => this.autoSwitch = !!event.snapshot.data.autoSwitchable); this.slideIntervalSubscription = this.settings.slideIntervalChanged.subscribe( interval => this.setSlideTimer(interval) ); } public ngOnDestroy() { this.slideShowTimer.unsubscribe(); this.selfUpdateCheckerTimer.unsubscribe(); this.slideIntervalSubscription.unsubscribe(); } private changeSlide() { if (!this.paused) { if (this.autoSwitch && this.isDuringDailyStandup()) { this.router.navigate(['/kanban']); } if (this.autoSwitch && !this.isDuringDailyStandup()) { this.slideShowService.nextSlide(); } this.setSlideTimer(this.settings.slideInterval); } } public setSlideTimer(delay: number) { this.slideTimerSubject.next(delay); } public togglePause() { this.paused = !this.paused; if (!this.paused) { this.setSlideTimer(this.settings.slideInterval); } } public pause() { this.paused = true; } private isDuringDailyStandup(): boolean { if (this.settings.team.dailyLockEnabled) { const now = new Date(); const startsParts = this.settings.team.dailyStartTime.split(TIME_SEPARATOR).map(part => +part); const endsParts = this.settings.team.dailyEndTime.split(TIME_SEPARATOR).map(part => +part); const times = [ new Date(now.getFullYear(), now.getMonth(), now.getDate(), startsParts[0], startsParts[1]), new Date(now.getFullYear(), now.getMonth(), now.getDate(), endsParts[0], endsParts[1]) ]; const startsAt = min(...times); const endsAt = max(...times); return isWithinRange(now, startsAt, endsAt); } return false; } }