Files
canti/src/app/pages/display/display.page.ts
T
David Frassi d83a5db65a fix: risolto accesso diretto ai singoli canti tramite URL e queryParams
- Aggiunto il caricamento reattivo del canto tramite un 'effect' in PlayerPage e DisplayPage.
- Ora l'applicazione attende che la lista asincrona dei canti sia popolata per caricare la canzone richiesta da URL.
2026-05-20 11:28:22 +02:00

134 lines
4.2 KiB
TypeScript

import { Component, OnInit, OnDestroy, signal, computed, effect, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { CantiService, Canto } from '../../services/canti.service';
import { LyricsParserService, ParsedSection } from '../../services/lyrics-parser.service';
@Component({
selector: 'app-display',
templateUrl: './display.page.html',
styleUrls: ['./display.page.scss'],
standalone: false
})
export class DisplayPage implements OnInit, OnDestroy {
public canto = signal<Canto | null>(null);
public activeSongId = signal<string | null>(null);
public showChords = signal<boolean>(false);
public fontSize = signal<number>(1.0);
public currentLineIndex = signal<number>(0);
public parsedSections = computed<ParsedSection[]>(() => {
const c = this.canto();
if (!c) return [];
if (this.showChords() && c.accordi) {
return this.lyricsParser.parseAccordi(c.accordi);
}
return this.lyricsParser.parseText(c.testo);
});
/** Get the current line text and surrounding lines from flat index */
public displayLines = computed(() => {
const sections = this.parsedSections();
const idx = this.currentLineIndex();
const allLines: { text: string; segments: any[]; sectionType: string }[] = [];
for (const section of sections) {
for (const line of section.lines) {
allLines.push({ text: line.text, segments: line.segments, sectionType: section.type });
}
}
return {
prev: idx > 0 ? allLines[idx - 1] : null,
current: allLines[idx] || null,
next: idx < allLines.length - 1 ? allLines[idx + 1] : null
};
});
private channel = new BroadcastChannel('karaoke_sync');
private readonly MIN_FONT = 0.6;
private readonly MAX_FONT = 5.0;
private initialPinchDistance: number | null = null;
private initialFontSize: number = 1.0;
private route = inject(ActivatedRoute);
private cantiService = inject(CantiService);
private lyricsParser = inject(LyricsParserService);
constructor() {
effect(() => {
const id = this.activeSongId();
const allCanti = this.cantiService.canti();
if (id) {
const found = allCanti.find(c => c.id === id);
if (found) {
this.canto.set(found);
}
}
}, { allowSignalWrites: true });
}
ngOnInit() {
this.route.queryParams.subscribe(params => {
const id = params['id'];
if (id) {
this.activeSongId.set(id);
}
});
this.channel.onmessage = (event) => {
if (event.data.type === 'SYNC_INDEX') {
this.currentLineIndex.set(event.data.index);
}
if (event.data.type === 'SYNC_CANTO') {
this.activeSongId.set(event.data.id);
}
if (event.data.type === 'SYNC_CHORDS') {
this.showChords.set(event.data.showChords);
}
if (event.data.type === 'SYNC_FONT') {
this.fontSize.set(event.data.fontSize);
}
};
}
ngOnDestroy() {
this.channel.close();
}
// --- Touch Gestures for Pinch-to-Zoom ---
onTouchStart(event: TouchEvent) {
if (event.touches.length === 2) {
this.initialPinchDistance = this.getDistance(event.touches[0], event.touches[1]);
this.initialFontSize = this.fontSize();
}
}
onTouchMove(event: TouchEvent) {
if (event.touches.length === 2 && this.initialPinchDistance !== null) {
event.preventDefault(); // Prevent browser zoom/scroll
const currentDistance = this.getDistance(event.touches[0], event.touches[1]);
const ratio = currentDistance / this.initialPinchDistance;
let newSize = this.initialFontSize * ratio;
// Clamp values
newSize = Math.max(this.MIN_FONT, Math.min(this.MAX_FONT, newSize));
if (Math.abs(newSize - this.fontSize()) > 0.01) {
this.fontSize.set(newSize);
// Sync back to player if display is touched
this.channel.postMessage({ type: 'SYNC_FONT', fontSize: this.fontSize() });
}
}
}
onTouchEnd() {
this.initialPinchDistance = null;
}
private getDistance(t1: Touch, t2: Touch): number {
return Math.sqrt(Math.pow(t1.clientX - t2.clientX, 2) + Math.pow(t1.clientY - t2.clientY, 2));
}
// ----------------------------------------
}