chore: save current changes

This commit is contained in:
David Frassi
2026-06-06 08:19:08 +02:00
parent e7e43468b3
commit 4d1883a45d
23 changed files with 1028 additions and 327 deletions
+87 -22
View File
@@ -412,18 +412,29 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
const container = document.querySelector('.lyrics-container') as HTMLElement;
if (!container) return 3; // Ritorno generico se il contenitore non è pronto
const containerHeight = container.clientHeight;
// Calcoliamo la reale altezza visibile sottraendo l'eventuale footer in sovraimpressione
let visibleHeight = containerHeight;
const containerRect = container.getBoundingClientRect();
const visibleTop = Math.max(containerRect.top, 0);
let visibleBottom = Math.min(containerRect.bottom, window.innerHeight || document.documentElement.clientHeight);
const footer = document.querySelector('ion-footer') as HTMLElement;
if (footer && footer.offsetHeight > 0) {
const computedStyle = window.getComputedStyle(footer);
if (computedStyle.display !== 'none') {
visibleHeight -= footer.offsetHeight;
if (footer) {
const footerRect = footer.getBoundingClientRect();
if (footerRect.height > 0 && window.getComputedStyle(footer).display !== 'none') {
visibleBottom = Math.min(visibleBottom, footerRect.top);
}
}
const floatingBar = document.querySelector('.floating-autoscroll-bar') as HTMLElement;
if (floatingBar) {
const barRect = floatingBar.getBoundingClientRect();
if (barRect.height > 0 && window.getComputedStyle(floatingBar).display !== 'none') {
visibleBottom = Math.min(visibleBottom, barRect.top);
}
}
// Calcoliamo la reale altezza visibile
const visibleHeight = Math.max(0, visibleBottom - visibleTop);
const lineElems = document.querySelectorAll('.lyric-line');
if (lineElems.length === 0) return 3;
@@ -443,7 +454,6 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
const pageStep = Math.max(1, linesPerPage);
console.log('[PageScroll] Calcolo dinamico dello scorrimento a pagina (Area visibile depurata):', {
containerHeight,
visibleHeight,
avgLineHeight,
linesPerPage,
@@ -463,10 +473,10 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
if (!container) return [];
const containerRect = container.getBoundingClientRect();
const visibleTop = containerRect.top;
let visibleBottom = containerRect.bottom;
const visibleTop = Math.max(containerRect.top, 0);
let visibleBottom = Math.min(containerRect.bottom, window.innerHeight || document.documentElement.clientHeight);
// Sottrai l'altezza dell'eventuale footer sovrapposto ad alto z-index
// Sottrai l'altezza dell'eventuale footer o barra sovrapposti ad alto z-index
const footer = document.querySelector('ion-footer') as HTMLElement;
if (footer) {
const footerRect = footer.getBoundingClientRect();
@@ -475,6 +485,14 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
}
}
const floatingBar = document.querySelector('.floating-autoscroll-bar') as HTMLElement;
if (floatingBar) {
const barRect = floatingBar.getBoundingClientRect();
if (barRect.height > 0 && window.getComputedStyle(floatingBar).display !== 'none') {
visibleBottom = Math.min(visibleBottom, barRect.top);
}
}
const lineElems = document.querySelectorAll('.lyric-line');
const visibleIndices: number[] = [];
@@ -501,7 +519,8 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
if (!container) return this.currentLineIndex() + 1;
const containerRect = container.getBoundingClientRect();
let visibleBottom = containerRect.bottom;
// Assicuriamoci che il limite inferiore non superi l'altezza reale della finestra
let visibleBottom = Math.min(containerRect.bottom, window.innerHeight || document.documentElement.clientHeight);
// Trova la posizione del footer o di qualunque elemento sovrapposto in fondo
const footer = document.querySelector('ion-footer') as HTMLElement;
@@ -512,8 +531,18 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
}
}
// Sottrai un piccolo margine di tolleranza di 8px
const visibleLimitY = visibleBottom - 8;
const floatingBar = document.querySelector('.floating-autoscroll-bar') as HTMLElement;
if (floatingBar) {
const barRect = floatingBar.getBoundingClientRect();
if (barRect.height > 0 && window.getComputedStyle(floatingBar).display !== 'none') {
visibleBottom = Math.min(visibleBottom, barRect.top);
}
}
// Aumentiamo il margine di tolleranza a 24px (o più) per essere sicuri
// di non perdere mai una riga parzialmente coperta. Meglio rileggere una riga
// in cima alla pagina successiva che perderla completamente a causa dello zoom.
const visibleLimitY = visibleBottom - 24;
const lineElems = document.querySelectorAll('.lyric-line');
const totalLines = this.getTotalLines();
@@ -546,7 +575,7 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
}
}
next(isAutomatic: boolean = false) {
next(isAutomatic: boolean = false, isVisual: boolean = false) {
this.lastAdvanceTimestamp = Date.now();
const totalLines = this.getTotalLines();
@@ -571,8 +600,8 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
nextIdx = this.calculateNextPageStartIndex();
}
this.lastScrollBlock.set('center');
} else if (this.settingsService.karaokePageScrollMode()) {
// Modalità manuale a pagine: calcolo analitico preciso per non perdere righe coperte
} else if (this.settingsService.karaokePageScrollMode() || isVisual) {
// Modalità manuale a pagine (o trigger visuale): calcolo analitico preciso per non perdere righe coperte
nextIdx = this.calculateNextPageStartIndex();
this.lastScrollBlock.set('start');
} else {
@@ -588,12 +617,12 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
// Metodi di validazione e freeze rimossi per migliorare affidabilità e prevenire blocchi permanenti
prev() {
prev(isVisual: boolean = false) {
this.lastAdvanceTimestamp = Date.now();
const prevIdx = this.currentLineIndex();
if (prevIdx > 0) {
const isPageMode = this.settingsService.karaokePageScrollMode();
const isPageMode = this.settingsService.karaokePageScrollMode() || isVisual;
const stepSize = isPageMode ? this.calculatePageStepSize() : 1;
const nextIdx = Math.max(0, prevIdx - stepSize);
@@ -710,6 +739,36 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
}
}
async editOrCloneCanto() {
const c = this.canto();
if (!c) return;
if (
this.settingsService.comunitaEnabled() &&
this.settingsService.showEditor() &&
this.comunitaService.comunitaCode() &&
!c.id.startsWith('my_')
) {
// Clone the song: Title: <original title>
const clonedTitle = c.titolo;
const clonedCanto = await this.myCantiService.saveCanto({
titolo: clonedTitle,
autore: c.autore,
link_youtube: c.link_youtube,
testo: c.testo || c.accordi || '',
accordi: c.accordi || c.testo || '',
id_momenti: c.id_momenti || []
});
// Redirect to the edit page for the newly cloned song
this.router.navigate(['/propose-canto'], { queryParams: { editId: clonedCanto.id } });
} else {
// Standard edit path
this.router.navigate(['/propose-canto'], { queryParams: { editId: c.id } });
}
}
private initPlayer(id: string) {
if (!this.youtubePlayerService.isPlayerSupported()) {
return;
@@ -757,6 +816,12 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
return info && info.num_canto ? info.num_canto.toString() : null;
}
getMySongNumber(canto: any): number {
if (!canto || !canto.id) return 0;
const index = this.myCantiService.myCanti().findIndex(c => c.id === canto.id);
return index !== -1 ? index + 1 : 0;
}
toggleAutoscroll() {
if (this.isAutoscrolling()) {
this.stopAutoscroll();
@@ -845,9 +910,9 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
await this.faceDetector.start(videoEl, (direction) => {
console.log(`[PlayerPage] Head tilt trigger received: ${direction}`);
if (direction === 'next') {
this.next(false);
this.next(false, true);
} else {
this.prev();
this.prev(true);
}
});
} catch (e) {