Functionnal UI with All Files
This commit is contained in:
132
src/app/view/components/cued-title/cued-title.component.ts
Normal file
132
src/app/view/components/cued-title/cued-title.component.ts
Normal file
@ -0,0 +1,132 @@
|
||||
// src/app/components/cued-title/cued-title.component.ts
|
||||
import { Component, input, computed, signal, effect } from '@angular/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { TitleCasePipe } from '@angular/common';
|
||||
import { TitleSheet, TitleSheetListStatus } from '../../../models/title-sheet.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-cued-title',
|
||||
standalone: true,
|
||||
imports: [TitleCasePipe],
|
||||
templateUrl: './cued-title.component.html',
|
||||
styleUrl: './cued-title.component.scss'
|
||||
})
|
||||
export class CuedTitleComponent {
|
||||
|
||||
// === INPUT SIGNALS (ANGULAR 19) ===
|
||||
unrealStatus = input<TitleSheetListStatus | null>(null);
|
||||
|
||||
// === INTERNAL SIGNALS ===
|
||||
private playStartTime = signal<Date | null>(null);
|
||||
private elapsedSeconds = signal<number>(0);
|
||||
private intervalId : any = signal<number | null>(null);
|
||||
|
||||
// Keep track of the last attempted title (even if it failed)
|
||||
private lastAttemptedTitle = signal<TitleSheet | null>(null);
|
||||
|
||||
// === COMPUTED SIGNALS ===
|
||||
statusClass = computed(() => {
|
||||
const status = this.unrealStatus();
|
||||
if (!status) return 'stopped';
|
||||
return status.isPlaying ? 'playing' : 'stopped';
|
||||
});
|
||||
|
||||
hasCurrentTitle = computed(() => {
|
||||
const status = this.unrealStatus();
|
||||
const lastAttempted = this.lastAttemptedTitle();
|
||||
|
||||
// Show title if:
|
||||
// 1. There's a current title, OR
|
||||
// 2. There's an error/stopped state but we have a last attempted title
|
||||
return status?.currentTitleSheet !== null ||
|
||||
(lastAttempted !== null && (status?.errorMessage));
|
||||
});
|
||||
|
||||
// Get the title to display (current or last attempted)
|
||||
displayedTitle = computed(() => {
|
||||
const status = this.unrealStatus();
|
||||
// Prefer current title, fallback to last attempted title
|
||||
return status?.currentTitleSheet || this.lastAttemptedTitle();
|
||||
});
|
||||
|
||||
isPlaying = computed(() => {
|
||||
const status = this.unrealStatus();
|
||||
return status?.isPlaying || false;
|
||||
});
|
||||
|
||||
// Format du timer : MM:SS
|
||||
formattedTimer = computed(() => {
|
||||
const seconds = this.elapsedSeconds();
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainingSeconds = seconds % 60;
|
||||
return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
|
||||
});
|
||||
|
||||
// Couleur du timer selon les règles
|
||||
timerColorClass = computed(() => {
|
||||
if (!this.isPlaying()) return 'timer-stopped';
|
||||
|
||||
const seconds = this.elapsedSeconds();
|
||||
if (seconds < 10) return 'timer-white';
|
||||
return 'timer-red';
|
||||
});
|
||||
|
||||
constructor() {
|
||||
// Track the last attempted title for error display
|
||||
effect(() => {
|
||||
const status = this.unrealStatus();
|
||||
|
||||
if (status?.currentTitleSheet) {
|
||||
// Update last attempted title when a new title is set
|
||||
this.lastAttemptedTitle.set(status.currentTitleSheet);
|
||||
} else if (!status?.isPlaying && !status?.errorMessage) {
|
||||
// Clear last attempted title when voluntarily stopped (no error)
|
||||
this.lastAttemptedTitle.set(null);
|
||||
}
|
||||
});
|
||||
|
||||
// Effect pour gérer le démarrage/arrêt du timer
|
||||
effect(() => {
|
||||
const isPlaying = this.isPlaying();
|
||||
|
||||
if (isPlaying) {
|
||||
this.startTimer();
|
||||
} else {
|
||||
this.stopTimer();
|
||||
this.resetTimer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.stopTimer();
|
||||
}
|
||||
|
||||
private startTimer(): void {
|
||||
this.stopTimer();
|
||||
|
||||
this.playStartTime.set(new Date());
|
||||
this.elapsedSeconds.set(0);
|
||||
|
||||
this.intervalId = setInterval(() => {
|
||||
const startTime = this.playStartTime();
|
||||
if (startTime) {
|
||||
const now = new Date();
|
||||
const elapsed = Math.floor((now.getTime() - startTime.getTime()) / 1000);
|
||||
this.elapsedSeconds.set(elapsed);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
private stopTimer(): void {
|
||||
if (this.intervalId) {
|
||||
clearInterval(this.intervalId);
|
||||
this.intervalId = null;
|
||||
}
|
||||
}
|
||||
|
||||
private resetTimer(): void {
|
||||
this.playStartTime.set(null);
|
||||
this.elapsedSeconds.set(0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user