Spostato gruppo avanzamento karaoke accanto ai controlli testa nel dettaglio canto
This commit is contained in:
+60
-82
@@ -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 { ThemeService } from './services/theme.service';
|
||||||
import { CantiService } from './services/canti.service';
|
import { CantiService } from './services/canti.service';
|
||||||
import { SettingsService } from './services/settings.service';
|
import { SettingsService } from './services/settings.service';
|
||||||
import { VERSION } from './version';
|
import { VERSION } from './version';
|
||||||
import { Router, ActivatedRoute, NavigationStart } from '@angular/router';
|
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 { SwUpdate, VersionReadyEvent } from '@angular/service-worker';
|
||||||
import { filter, first } from 'rxjs/operators';
|
import { filter, first } from 'rxjs/operators';
|
||||||
import { App } from '@capacitor/app';
|
import { App } from '@capacitor/app';
|
||||||
@@ -96,8 +97,12 @@ export class AppComponent implements OnInit {
|
|||||||
private platform = inject(Platform);
|
private platform = inject(Platform);
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private route = inject(ActivatedRoute);
|
private route = inject(ActivatedRoute);
|
||||||
|
private location = inject(Location);
|
||||||
|
private navCtrl = inject(NavController);
|
||||||
private toastCtrl = inject(ToastController);
|
private toastCtrl = inject(ToastController);
|
||||||
|
private alertCtrl = inject(AlertController);
|
||||||
private swUpdate = inject(SwUpdate);
|
private swUpdate = inject(SwUpdate);
|
||||||
|
private ngZone = inject(NgZone);
|
||||||
|
|
||||||
public showRedirectOverlay = signal<boolean>(false);
|
public showRedirectOverlay = signal<boolean>(false);
|
||||||
public showInstallOverlay = signal<boolean>(false);
|
public showInstallOverlay = signal<boolean>(false);
|
||||||
@@ -107,6 +112,9 @@ export class AppComponent implements OnInit {
|
|||||||
public redirectFailed = signal<boolean>(false);
|
public redirectFailed = signal<boolean>(false);
|
||||||
public protocolLink = '';
|
public protocolLink = '';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Gli aggiornamenti automatici e periodici sono stati rimossi.
|
// Gli aggiornamenti automatici e periodici sono stati rimossi.
|
||||||
// L'aggiornamento viene gestito esclusivamente in modo manuale
|
// L'aggiornamento viene gestito esclusivamente in modo manuale
|
||||||
@@ -208,24 +216,44 @@ export class AppComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
// Gestione tasto back per PWA/Browser (intercettando popstate di Angular Router)
|
// Gestione del tasto back (PWA/Browser e Nativo/Hardware) secondo le 3 specifiche:
|
||||||
this.router.events.subscribe(event => {
|
// 1- Se siamo su un canto (/player o /display), premendo back andiamo sempre sulla home.
|
||||||
if (event instanceof NavigationStart && event.navigationTrigger === 'popstate') {
|
// 2- Se siamo sulla home (/home o /), premendo back l'app deve uscire.
|
||||||
const targetUrl = event.url.split('?')[0];
|
// 3- Per tutto il resto, segue la logica standard andando alla pagina precedente nello storico.
|
||||||
if (targetUrl !== '/home' && targetUrl !== '/') {
|
|
||||||
|
// 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.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)
|
// Gestione tasto indietro hardware (es. Android / Capacitor / PWA)
|
||||||
this.platform.backButton.subscribeWithPriority(9999, () => {
|
this.platform.backButton.subscribeWithPriority(10, async () => {
|
||||||
const currentUrl = this.router.url;
|
const currentPath = this.router.url.split('?')[0];
|
||||||
const path = currentUrl.split('?')[0];
|
if (currentPath === '/home' || currentPath === '/') {
|
||||||
if (path !== '/home' && path !== '/') {
|
// Spec 2: Sulla home, usciamo dall'app
|
||||||
this.router.navigate(['/home']);
|
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 {
|
} 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;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
console.log('[PWA-Update] Versione allineata, nessun aggiornamento necessario.');
|
console.log('[PWA-Update] Versione allineata, nessun aggiornamento necessario.');
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('[PWA-Update] version.json check fallito:', 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<boolean>((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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -566,6 +528,7 @@ export class AppComponent implements OnInit {
|
|||||||
const isStandalone = window.matchMedia('(display-mode: standalone)').matches || (navigator as any).standalone;
|
const isStandalone = window.matchMedia('(display-mode: standalone)').matches || (navigator as any).standalone;
|
||||||
if (isStandalone) {
|
if (isStandalone) {
|
||||||
localStorage.setItem('pwa-installed', 'true');
|
localStorage.setItem('pwa-installed', 'true');
|
||||||
|
this.checkLoaderDismissal();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,6 +691,20 @@ export class AppComponent implements OnInit {
|
|||||||
this.checkLoaderDismissal();
|
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() {
|
export function showFullscreenUpdateOverlay() {
|
||||||
@@ -776,3 +753,4 @@ export function showFullscreenUpdateOverlay() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</ion-title>
|
</ion-title>
|
||||||
<ion-buttons slot="end">
|
<ion-buttons slot="end">
|
||||||
<ion-button routerLink="/propose-canto" class="add-btn" title="Crea un nuovo canto">
|
<ion-button routerLink="/propose-canto" class="add-btn" title="Crea un nuovo canto" *ngIf="settingsService.showEditor()">
|
||||||
<ion-icon slot="icon-only" name="add-outline"></ion-icon>
|
<ion-icon slot="icon-only" name="add-outline"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<ng-container *ngIf="hasUpdateAvailable(); else showQrBtn">
|
<ng-container *ngIf="hasUpdateAvailable(); else showQrBtn">
|
||||||
@@ -201,13 +201,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="filter-card-footer" *ngIf="hasPlaylistCardParams()">
|
|
||||||
<div></div>
|
|
||||||
<button type="button" class="clear-advanced-link outfit-font" (click)="clearPlaylistCard()">
|
|
||||||
<ion-icon name="close-circle-outline"></ion-icon>
|
|
||||||
<span>Reset liste</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Filter Card (default closed) -->
|
<!-- Filter Card (default closed) -->
|
||||||
@@ -545,8 +539,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Delete Button (only for local songs) -->
|
<!-- Delete Button (only for "mio" songs when "Miei" filter is active) -->
|
||||||
<div *ngIf="canto.id.startsWith('my_')" class="delete-section" (click)="$event.stopPropagation()">
|
<div *ngIf="settingsService.showEditor() && canto.id.startsWith('my_') && showOnlyMine()" class="delete-section" (click)="$event.stopPropagation()">
|
||||||
<ion-button fill="clear" color="danger" (click)="deleteMyCanto(canto.id, $event)">
|
<ion-button fill="clear" color="danger" (click)="deleteMyCanto(canto.id, $event)">
|
||||||
<ion-icon slot="icon-only" name="trash-outline"></ion-icon>
|
<ion-icon slot="icon-only" name="trash-outline"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|||||||
@@ -423,7 +423,7 @@ export class HomePage implements OnDestroy {
|
|||||||
|
|
||||||
// Filter by Validati (non personali e non contrassegnati come non validati)
|
// Filter by Validati (non personali e non contrassegnati come non validati)
|
||||||
if (this.showValidati()) {
|
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)
|
// Filter by Non-Validati (personali o esplicitamente non validati)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<ion-toolbar class="bg-gradient top-toolbar" style="--padding-top: 8px; --padding-bottom: 8px; --padding-start: 12px; --padding-end: 12px;">
|
<ion-toolbar class="bg-gradient top-toolbar" style="--padding-top: 8px; --padding-bottom: 8px; --padding-start: 12px; --padding-end: 12px;">
|
||||||
<div class="outfit-font" style="display: flex; flex-direction: column; width: 100%; gap: 2px;">
|
<div class="outfit-font" style="display: flex; flex-direction: column; width: 100%; gap: 2px;">
|
||||||
|
|
||||||
<!-- Row 1: Number + Title -->
|
<!-- Row 1: Number + Title + Settings -->
|
||||||
<div style="display: flex; align-items: center; gap: 8px; width: 100%; min-width: 0;">
|
<div style="display: flex; align-items: center; gap: 8px; width: 100%; min-width: 0;">
|
||||||
<span class="canto-number" *ngIf="canto()?.id_canti" style="flex-shrink: 0;"
|
<span class="canto-number" *ngIf="canto()?.id_canti" style="flex-shrink: 0;"
|
||||||
[style.fontSize.rem]="0.85 * fontSize()"
|
[style.fontSize.rem]="0.85 * fontSize()"
|
||||||
@@ -18,6 +18,9 @@
|
|||||||
<span *ngIf="getCommunitySongNumber(canto())" style="color: var(--ion-color-secondary); font-weight: 600; margin-right: 6px; opacity: 0.9;">{{ getCommunitySongNumber(canto()) }}</span>
|
<span *ngIf="getCommunitySongNumber(canto())" style="color: var(--ion-color-secondary); font-weight: 600; margin-right: 6px; opacity: 0.9;">{{ getCommunitySongNumber(canto()) }}</span>
|
||||||
<span>{{ canto()?.titolo || 'Player' }}</span>
|
<span>{{ canto()?.titolo || 'Player' }}</span>
|
||||||
</span>
|
</span>
|
||||||
|
<ion-button routerLink="/settings" class="settings-btn" fill="clear" style="flex-shrink: 0; margin: 0; --color: var(--ion-color-secondary);">
|
||||||
|
<ion-icon slot="icon-only" name="settings-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Row 2: Author -->
|
<!-- Row 2: Author -->
|
||||||
@@ -242,11 +245,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Navigation (Avanzamento Karaoke e Riparti da inizio) -->
|
||||||
|
<div class="group">
|
||||||
|
<ion-button fill="clear" size="small" (click)="restart()">
|
||||||
|
<ion-icon slot="icon-only" name="arrow-up-circle" color="secondary"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
<ion-button fill="clear" size="small" (click)="prev()" [disabled]="currentLineIndex() === 0">
|
||||||
|
<ion-icon slot="icon-only" name="chevron-back" color="secondary"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
<ion-button fill="clear" size="small" (click)="next()" [disabled]="currentLineIndex() === getTotalLines() - 1">
|
||||||
|
<ion-icon slot="icon-only" name="chevron-forward" color="secondary"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Action Buttons (edit, condividi, accordi) -->
|
<!-- Action Buttons (edit, condividi, accordi) -->
|
||||||
<div class="group">
|
<div class="group">
|
||||||
<ion-button fill="clear" size="small" (click)="editOrCloneCanto()" *ngIf="settingsService.showEditor()">
|
<ion-button fill="clear" size="small" (click)="editOrCloneCanto()" *ngIf="settingsService.showEditor()">
|
||||||
<ion-icon slot="icon-only" name="create-outline" color="secondary"></ion-icon>
|
<ion-icon slot="icon-only" name="create-outline" color="secondary"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
<ion-button fill="clear" size="small" (click)="deleteMyCanto()" *ngIf="settingsService.showEditor() && canto()?.id?.startsWith('my_')" color="danger">
|
||||||
|
<ion-icon slot="icon-only" name="trash-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
<ion-button fill="clear" size="small" (click)="shareCanto()">
|
<ion-button fill="clear" size="small" (click)="shareCanto()">
|
||||||
<ion-icon slot="icon-only" name="share-social-outline" color="secondary"></ion-icon>
|
<ion-icon slot="icon-only" name="share-social-outline" color="secondary"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
@@ -261,19 +280,6 @@
|
|||||||
</ion-button>
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Navigation -->
|
|
||||||
<div class="group">
|
|
||||||
<ion-button fill="clear" size="small" (click)="restart()">
|
|
||||||
<ion-icon slot="icon-only" name="arrow-up-circle" color="secondary"></ion-icon>
|
|
||||||
</ion-button>
|
|
||||||
<ion-button fill="clear" size="small" (click)="prev()" [disabled]="currentLineIndex() === 0">
|
|
||||||
<ion-icon slot="icon-only" name="chevron-back" color="secondary"></ion-icon>
|
|
||||||
</ion-button>
|
|
||||||
<ion-button fill="clear" size="small" (click)="next()" [disabled]="currentLineIndex() === getTotalLines() - 1">
|
|
||||||
<ion-icon slot="icon-only" name="chevron-forward" color="secondary"></ion-icon>
|
|
||||||
</ion-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Transposition (Only in chords mode) -->
|
<!-- Transposition (Only in chords mode) -->
|
||||||
<div class="group" *ngIf="showChords()">
|
<div class="group" *ngIf="showChords()">
|
||||||
<ion-button fill="clear" size="small" (click)="transposeDown()">
|
<ion-button fill="clear" size="small" (click)="transposeDown()">
|
||||||
|
|||||||
@@ -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 {
|
.title-main {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -283,6 +298,7 @@
|
|||||||
white-space: normal;
|
white-space: normal;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: var(--ion-color-secondary);
|
color: var(--ion-color-secondary);
|
||||||
|
|||||||
@@ -1015,7 +1015,7 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
if (this.isLandscapeActive()) {
|
if (this.isLandscapeActive()) {
|
||||||
this.isBlackScreen.set(true);
|
this.isBlackScreen.set(true);
|
||||||
}
|
}
|
||||||
this.router.navigate(['/player'], { queryParams: { id: nextId } });
|
this.router.navigate(['/player'], { queryParams: { id: nextId }, replaceUrl: true });
|
||||||
} else {
|
} else {
|
||||||
this.playlistService.autoPlayPlaylist.set(false);
|
this.playlistService.autoPlayPlaylist.set(false);
|
||||||
}
|
}
|
||||||
@@ -1033,7 +1033,7 @@ export class PlayerPage implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
if (this.isLandscapeActive()) {
|
if (this.isLandscapeActive()) {
|
||||||
this.isBlackScreen.set(true);
|
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([], {
|
this.router.navigate([], {
|
||||||
relativeTo: this.route,
|
relativeTo: this.route,
|
||||||
queryParams: { id },
|
queryParams: { id },
|
||||||
queryParamsHandling: 'merge'
|
queryParamsHandling: 'merge',
|
||||||
|
replaceUrl: true
|
||||||
});
|
});
|
||||||
this.restart();
|
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() {
|
async shareCanto() {
|
||||||
const c = this.canto();
|
const c = this.canto();
|
||||||
if (!c) return;
|
if (!c) return;
|
||||||
|
|||||||
@@ -629,6 +629,7 @@ body.high-contrast :host ::ng-deep {
|
|||||||
white-space: normal;
|
white-space: normal;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
|
letter-spacing: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chord-segment {
|
.chord-segment {
|
||||||
|
|||||||
@@ -983,6 +983,7 @@ export class PlaylistService {
|
|||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 7px;
|
margin-bottom: 7px;
|
||||||
min-height: 1.2em;
|
min-height: 1.2em;
|
||||||
|
letter-spacing: 3px;
|
||||||
}
|
}
|
||||||
.chord-segment {
|
.chord-segment {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
export const VERSION = '2026.08.08.1614';
|
export const VERSION = '2026.08.09.0826';
|
||||||
|
|||||||
Reference in New Issue
Block a user