From 171780bf87a9ba020a2dc9f6f24126fcd0fce157 Mon Sep 17 00:00:00 2001 From: David Frassi Date: Sun, 9 Aug 2026 08:28:03 +0200 Subject: [PATCH] Spostato gruppo avanzamento karaoke accanto ai controlli testa nel dettaglio canto --- src/app/app.component.ts | 144 ++++++++---------- src/app/home/home.page.html | 14 +- src/app/home/home.page.ts | 2 +- src/app/pages/player/player.page.html | 34 +++-- src/app/pages/player/player.page.scss | 16 ++ src/app/pages/player/player.page.ts | 28 +++- .../propose-canto/propose-canto.page.scss | 1 + src/app/services/playlist.service.ts | 1 + src/app/version.ts | 2 +- 9 files changed, 130 insertions(+), 112 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 0bce36a..e384fd2 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,10 +1,11 @@ -import { Component, inject, OnInit, signal, effect } from '@angular/core'; +import { Component, inject, NgZone, OnInit, signal, effect } from '@angular/core'; import { ThemeService } from './services/theme.service'; import { CantiService } from './services/canti.service'; import { SettingsService } from './services/settings.service'; import { VERSION } from './version'; import { Router, ActivatedRoute, NavigationStart } from '@angular/router'; -import { ToastController, Platform } from '@ionic/angular'; +import { ToastController, Platform, AlertController, NavController } from '@ionic/angular'; +import { Location } from '@angular/common'; import { SwUpdate, VersionReadyEvent } from '@angular/service-worker'; import { filter, first } from 'rxjs/operators'; import { App } from '@capacitor/app'; @@ -96,8 +97,12 @@ export class AppComponent implements OnInit { private platform = inject(Platform); private router = inject(Router); private route = inject(ActivatedRoute); + private location = inject(Location); + private navCtrl = inject(NavController); private toastCtrl = inject(ToastController); + private alertCtrl = inject(AlertController); private swUpdate = inject(SwUpdate); + private ngZone = inject(NgZone); public showRedirectOverlay = signal(false); public showInstallOverlay = signal(false); @@ -107,6 +112,9 @@ export class AppComponent implements OnInit { public redirectFailed = signal(false); public protocolLink = ''; + + + constructor() { // Gli aggiornamenti automatici e periodici sono stati rimossi. // L'aggiornamento viene gestito esclusivamente in modo manuale @@ -208,24 +216,44 @@ export class AppComponent implements OnInit { } async ngOnInit() { - // Gestione tasto back per PWA/Browser (intercettando popstate di Angular Router) - this.router.events.subscribe(event => { - if (event instanceof NavigationStart && event.navigationTrigger === 'popstate') { - const targetUrl = event.url.split('?')[0]; - if (targetUrl !== '/home' && targetUrl !== '/') { - this.router.navigate(['/home'], { replaceUrl: true }); - } + // Gestione del tasto back (PWA/Browser e Nativo/Hardware) secondo le 3 specifiche: + // 1- Se siamo su un canto (/player o /display), premendo back andiamo sempre sulla home. + // 2- Se siamo sulla home (/home o /), premendo back l'app deve uscire. + // 3- Per tutto il resto, segue la logica standard andando alla pagina precedente nello storico. + + // Gestione popstate (tasto indietro browser / gesture PWA) + this.router.events.pipe( + filter((e): e is NavigationStart => e instanceof NavigationStart), + filter(e => e.navigationTrigger === 'popstate') + ).subscribe(() => { + const currentPath = this.router.url.split('?')[0]; + if (currentPath === '/home' || currentPath === '/') { + // Spec 2: Sulla home, usciamo dall'app + this.router.navigate(['/home'], { replaceUrl: true }); + this.exitApp(); + } else if (currentPath === '/player' || currentPath === '/display') { + // Spec 1: Su un canto, andiamo alla home azzerando lo stack + this.navCtrl.navigateRoot('/home', { animationDirection: 'back' }); } + // Spec 3: Per il resto (es. /settings), popstate prosegue normalmente verso la pagina precedente }); - // Gestione tasto back hardware per nativo (Capacitor/Cordova) - this.platform.backButton.subscribeWithPriority(9999, () => { - const currentUrl = this.router.url; - const path = currentUrl.split('?')[0]; - if (path !== '/home' && path !== '/') { - this.router.navigate(['/home']); + // Gestione tasto indietro hardware (es. Android / Capacitor / PWA) + this.platform.backButton.subscribeWithPriority(10, async () => { + const currentPath = this.router.url.split('?')[0]; + if (currentPath === '/home' || currentPath === '/') { + // Spec 2: Sulla home, usciamo dall'app + this.exitApp(); + } else if (currentPath === '/player' || currentPath === '/display') { + // Spec 1: Su un canto, andiamo alla home azzerando lo stack + this.navCtrl.navigateRoot('/home', { animationDirection: 'back' }); } else { - App.exitApp(); + // Spec 3: Per il resto, logica standard (pagina precedente) + if (window.history.length > 1) { + this.location.back(); + } else { + this.navCtrl.navigateRoot('/home', { animationDirection: 'back' }); + } } }); @@ -480,79 +508,13 @@ export class AppComponent implements OnInit { return true; } else { console.log('[PWA-Update] Versione allineata, nessun aggiornamento necessario.'); + return false; } } } catch (e) { console.warn('[PWA-Update] version.json check fallito:', e); } - // Fallback: Controlla direttamente tramite SwUpdate se non intercettato da version.json - if (this.swUpdate.isEnabled) { - try { - console.log('[PWA-Update] Verifica aggiornamenti via SwUpdate all\'avvio...'); - - let activated = false; - - const activateAndReload = async () => { - if (activated) return; - activated = true; - try { - await this.swUpdate.activateUpdate(); - } catch (e) { - console.warn('[PWA-Update] activateUpdate fallito all\'avvio:', e); - } - - if ('serviceWorker' in navigator) { - const registrations = await navigator.serviceWorker.getRegistrations(); - for (const reg of registrations) { - await reg.unregister(); - } - } - if ('caches' in window) { - const keys = await caches.keys(); - for (const key of keys) { - await caches.delete(key); - } - } - - const url = new URL(window.location.href); - url.searchParams.set('update_cb', Date.now().toString()); - window.location.replace(url.toString()); - }; - - const sub = this.swUpdate.versionUpdates - .pipe( - filter((evt): evt is VersionReadyEvent => evt.type === 'VERSION_READY'), - first() - ) - .subscribe(() => { - console.log('[PWA-Update] VERSION_READY ricevuto all\'avvio, ricaricamento automatico...'); - activateAndReload(); - }); - - const hasUpdate = await Promise.race([ - this.swUpdate.checkForUpdate(), - new Promise((resolve) => setTimeout(() => resolve(false), 8000)) - ]); - - if (hasUpdate) { - console.log('[PWA-Update] Aggiornamento rilevato via SwUpdate. Applicazione automatica...'); - - setTimeout(() => { - console.log('[PWA-Update] Safety timeout raggiunto all\'avvio, procedo...'); - sub.unsubscribe(); - activateAndReload(); - }, 15000); - - return true; - } else { - sub.unsubscribe(); - } - } catch (err) { - console.warn('[PWA-Update] Controllo SwUpdate fallito all\'avvio:', err); - } - } - return false; } @@ -566,6 +528,7 @@ export class AppComponent implements OnInit { const isStandalone = window.matchMedia('(display-mode: standalone)').matches || (navigator as any).standalone; if (isStandalone) { localStorage.setItem('pwa-installed', 'true'); + this.checkLoaderDismissal(); return; } @@ -728,6 +691,20 @@ export class AppComponent implements OnInit { this.checkLoaderDismissal(); } } + + private exitApp() { + try { + App.exitApp(); + } catch (e) {} + try { + if ((navigator as any)?.app?.exitApp) { + (navigator as any).app.exitApp(); + } + } catch (e) {} + try { + window.close(); + } catch (e) {} + } } export function showFullscreenUpdateOverlay() { @@ -776,3 +753,4 @@ export function showFullscreenUpdateOverlay() { } }; } + diff --git a/src/app/home/home.page.html b/src/app/home/home.page.html index 5f332cc..4c67aad 100644 --- a/src/app/home/home.page.html +++ b/src/app/home/home.page.html @@ -12,7 +12,7 @@ - + @@ -201,13 +201,7 @@ - + @@ -545,8 +539,8 @@ - -
+ +
diff --git a/src/app/home/home.page.ts b/src/app/home/home.page.ts index a008e89..323e00a 100644 --- a/src/app/home/home.page.ts +++ b/src/app/home/home.page.ts @@ -423,7 +423,7 @@ export class HomePage implements OnDestroy { // Filter by Validati (non personali e non contrassegnati come non validati) if (this.showValidati()) { - list = list.filter(c => !c.nonValidato && !c.id.startsWith('my_')); + list = list.filter(c => !c.nonValidato && (onlyMine || !c.id.startsWith('my_'))); } // Filter by Non-Validati (personali o esplicitamente non validati) diff --git a/src/app/pages/player/player.page.html b/src/app/pages/player/player.page.html index a96c718..c24124b 100644 --- a/src/app/pages/player/player.page.html +++ b/src/app/pages/player/player.page.html @@ -2,7 +2,7 @@
- +
{{ getCommunitySongNumber(canto()) }} {{ canto()?.titolo || 'Player' }} + + +
@@ -242,11 +245,27 @@
+ +
+ + + + + + + + + +
+
+ + + @@ -261,19 +280,6 @@
- -
- - - - - - - - - -
-
diff --git a/src/app/pages/player/player.page.scss b/src/app/pages/player/player.page.scss index 4b9d0df..b4fd117 100644 --- a/src/app/pages/player/player.page.scss +++ b/src/app/pages/player/player.page.scss @@ -59,6 +59,21 @@ } } + .settings-btn { + --color: var(--ion-color-secondary); + --padding-start: 0; + --padding-end: 0; + margin-left: 0; + margin-right: 0; + width: 38px; + min-width: 38px; + height: 38px; + + ion-icon { + font-size: 1.6rem; + } + } + .title-main { display: flex; align-items: center; @@ -283,6 +298,7 @@ white-space: normal; overflow-wrap: break-word; word-break: break-word; + letter-spacing: 3px; &.active { color: var(--ion-color-secondary); diff --git a/src/app/pages/player/player.page.ts b/src/app/pages/player/player.page.ts index 2ffaf15..168b60f 100644 --- a/src/app/pages/player/player.page.ts +++ b/src/app/pages/player/player.page.ts @@ -1015,7 +1015,7 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy { if (this.isLandscapeActive()) { this.isBlackScreen.set(true); } - this.router.navigate(['/player'], { queryParams: { id: nextId } }); + this.router.navigate(['/player'], { queryParams: { id: nextId }, replaceUrl: true }); } else { this.playlistService.autoPlayPlaylist.set(false); } @@ -1033,7 +1033,7 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy { if (this.isLandscapeActive()) { this.isBlackScreen.set(true); } - this.router.navigate(['/player'], { queryParams: { id: prevId } }); + this.router.navigate(['/player'], { queryParams: { id: prevId }, replaceUrl: true }); } } @@ -1041,7 +1041,8 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy { this.router.navigate([], { relativeTo: this.route, queryParams: { id }, - queryParamsHandling: 'merge' + queryParamsHandling: 'merge', + replaceUrl: true }); this.restart(); } @@ -1132,6 +1133,27 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy { } } + async deleteMyCanto() { + const c = this.canto(); + if (!c || !c.id.startsWith('my_')) return; + const alert = await this.alertCtrl.create({ + header: 'Elimina Canto', + message: 'Sei sicuro di voler eliminare questo canto dai tuoi brani personali?', + buttons: [ + { text: 'Annulla', role: 'cancel' }, + { + text: 'Elimina', + role: 'destructive', + handler: () => { + this.myCantiService.deleteCanto(c.id); + this.router.navigate(['/home']); + } + } + ] + }); + await alert.present(); + } + async shareCanto() { const c = this.canto(); if (!c) return; diff --git a/src/app/pages/propose-canto/propose-canto.page.scss b/src/app/pages/propose-canto/propose-canto.page.scss index 928a680..09ccf10 100644 --- a/src/app/pages/propose-canto/propose-canto.page.scss +++ b/src/app/pages/propose-canto/propose-canto.page.scss @@ -629,6 +629,7 @@ body.high-contrast :host ::ng-deep { white-space: normal; overflow-wrap: break-word; word-break: break-word; + letter-spacing: 3px; } .chord-segment { diff --git a/src/app/services/playlist.service.ts b/src/app/services/playlist.service.ts index ed2b2dc..9be3971 100644 --- a/src/app/services/playlist.service.ts +++ b/src/app/services/playlist.service.ts @@ -983,6 +983,7 @@ export class PlaylistService { display: block; margin-bottom: 7px; min-height: 1.2em; + letter-spacing: 3px; } .chord-segment { display: inline-flex; diff --git a/src/app/version.ts b/src/app/version.ts index 429d91c..22fdb00 100644 --- a/src/app/version.ts +++ b/src/app/version.ts @@ -1 +1 @@ -export const VERSION = '2026.08.08.1614'; +export const VERSION = '2026.08.09.0826';