Files
tusha/src/app/pages/modus/focus/focus.component.ts

181 lines
5.2 KiB
TypeScript

import {Component, OnDestroy, OnInit, Renderer2} from "@angular/core";
import {
IonBreadcrumb,
IonBreadcrumbs,
IonButton,
IonCard,
IonContent,
IonIcon, IonItem, IonLabel, IonList,
IonProgressBar
} from "@ionic/angular/standalone";
import {TushaPageComponent} from "../../../tusha/tusha-page/tusha-page.component";
import {FocusState} from "./focus-state";
import {FocusService} from "./focus.service";
import {Observable} from "rxjs";
import {FocusStats} from "./focus-stats";
import { CommonModule } from '@angular/common';
@Component({
templateUrl: 'focus.component.html',
styleUrls: ['focus.component.css'],
standalone: true,
imports: [IonBreadcrumbs, IonBreadcrumb, IonIcon, TushaPageComponent, IonProgressBar, IonContent, IonButton, IonCard, IonItem, IonLabel, IonList, CommonModule]
})
export class FocusPage implements OnInit, OnDestroy {
duration: number = 0; // default duration in minutes
minutesText: string = '';
secondsText: string = '';
private interval: number | undefined;
private timerStarted: number | null = null;
state: FocusState = FocusState.STOPPED;
private focusRuns = 0;
$stats: Observable<FocusStats> = this.focusService.$stats;
private endOfTimerChime: HTMLAudioElement;
private forcedEndOfTimerChime: HTMLAudioElement;
private windUpChime: HTMLAudioElement;
pathD: string = 'M100 10 A90 90 0 1 1 0 0';
dashOffset = 0;
constructor(private renderer: Renderer2, private focusService: FocusService) {
this.endOfTimerChime = new Audio('../../../assets/race-start-beeps-125125.mp3');
this.forcedEndOfTimerChime = new Audio('../../../assets/hardstop.mp3');
this.windUpChime = new Audio('../../../assets/wind-up.mp3');
}
ngOnInit() {
this.updateTimeDisplay(this.duration * 60, 0, 1);
}
ngOnDestroy() {
if (this.interval) {
clearInterval(this.interval);
}
}
startTimer(duration: number) {
this.duration = duration;
if (this.interval) {
clearInterval(this.interval);
}
this.timerStarted = Date.now();
this.update();
this.interval = setInterval(() => this.update(), 1000);
}
private update() {
const elapsed = this.timerStarted ? Math.round((Date.now() - (this.timerStarted)) / 1000) : 0; // in seconden
let progress = elapsed / (this.duration * 60); // from 0 to 1
if( progress === 0) {
progress = 0.0000001; // otherwise no graph
}
if (progress >= 1 || isNaN(progress)) {
progress = 1;
if (this.duration === 0) {
this.forcedEndOfTimerChime.play().catch(error => {
console.error('Error playing audio:', error);
});
clearInterval(this.interval);
this.timerStarted = null;
}
else if (progress === 1) {
this.endOfTimerChime.play().catch(error => {
console.error('Error playing audio:', error);
});
}
progress = 1;
}
this.renderer.setStyle(
document.documentElement,
'--progress',
progress.toString()
);
this.updateTimeDisplay(this.duration * 60 - elapsed, elapsed, 1 - progress);
}
private updateTimeDisplay(timeLeft: number, elapsed: number, percentage: number) {
const theta = 2 * Math.PI * (percentage - 0.25);
const circleEndX = 100 + 90 * Math.cos(theta);
const circleEndY = 100 + 90 * Math.sin(theta);
this.pathD = 'M100 10 A90 90 0 ' + (percentage > 0.5 ? '1' : '0') + ' 1 ' + circleEndX + ' ' + circleEndY;
const twoNumbers = (n: number) => n < 10 && n >= 0 ? '0' + n.toString() : n.toString();
const floorPositiveCeilNegative = (n: number): number => n > 0 ? Math.floor(n) : Math.ceil(n);
this.minutesText = twoNumbers(Math.abs(floorPositiveCeilNegative(timeLeft / 60)));
this.secondsText = twoNumbers(Math.abs(floorPositiveCeilNegative(timeLeft % 60)));
this.dashOffset = elapsed;
}
startWhereWeAre() {
switch (this.state) {
case FocusState.FOCUS:
this.focusRuns++;
if (this.focusRuns > 3) {
this.focusRuns = 0;
this.recharge();
} else {
this.reload();
}
break;
default:
this.focus();
break;
}
}
stopTimer() {
this.focusRuns = 0;
this.state = FocusState.STOPPED;
this.stopStatsCounter();
this.startTimer(0);
}
private stopStatsCounter() {
this.focusService.stopCurrent(this.timerStarted !== null);
}
focus() {
this.windUpChime.play().catch(error => {
console.error('Error playing audio:', error);
});
this.state = FocusState.FOCUS;
this.stopStatsCounter();
this.focusService.startFocus();
this.startTimer(1); // 25
}
reload() {
this.windUpChime.play().catch(error => {
console.error('Error playing audio:', error);
});
if (!!this.timerStarted) {
this.focusRuns = 0;
}
this.state = FocusState.SHORT_BREAK;
this.stopStatsCounter();
this.focusService.startShortBreak();
this.startTimer(0.1); // 5
}
recharge() {
this.windUpChime.play().catch(error => {
console.error('Error playing audio:', error);
});
if (!!this.timerStarted) {
this.focusRuns = 0;
}
this.state = FocusState.LONG_BREAK;
this.stopStatsCounter();
this.focusService.startLongBreak();
this.startTimer(0.3); // 15
}
}