diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 82f1667..3c2bfb0 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -3,10 +3,11 @@ 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 } from '@angular/router';
-import { ToastController } from '@ionic/angular';
+import { Router, ActivatedRoute, NavigationStart } from '@angular/router';
+import { ToastController, Platform } from '@ionic/angular';
import { SwUpdate, VersionReadyEvent } from '@angular/service-worker';
import { filter, first } from 'rxjs/operators';
+import { App } from '@capacitor/app';
@Component({
selector: 'app-root',
@@ -19,6 +20,7 @@ export class AppComponent implements OnInit {
public cantiService = inject(CantiService);
public settingsService = inject(SettingsService);
public version = VERSION;
+ private platform = inject(Platform);
private router = inject(Router);
private route = inject(ActivatedRoute);
private toastCtrl = inject(ToastController);
@@ -60,6 +62,27 @@ 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 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']);
+ } else {
+ App.exitApp();
+ }
+ });
+
// Add global horizontal scroll support for wheel on horizontal containers
window.addEventListener('wheel', (event: WheelEvent) => {
if (Math.abs(event.deltaY) > 0 && Math.abs(event.deltaX) === 0) {
diff --git a/src/app/home/home.page.html b/src/app/home/home.page.html
index d47c7a0..f7a1f21 100644
--- a/src/app/home/home.page.html
+++ b/src/app/home/home.page.html
@@ -139,6 +139,13 @@
0">
{{ reorderList().length }}
+
0">
@@ -155,6 +162,9 @@
+
+
+
diff --git a/src/app/home/home.page.scss b/src/app/home/home.page.scss
index 6578e83..1e1d471 100644
--- a/src/app/home/home.page.scss
+++ b/src/app/home/home.page.scss
@@ -383,6 +383,12 @@ ion-title {
color: #ffffff !important;
background: rgba(255, 255, 255, 0.2) !important;
}
+ .playlist-name-input {
+ color: #000000 !important;
+ &::placeholder {
+ color: rgba(0, 0, 0, 0.6) !important;
+ }
+ }
}
// Custom Item Layout
@@ -676,6 +682,30 @@ ion-title {
font-size: 1.2rem;
}
}
+
+ .playlist-name-input {
+ background: rgba(255, 255, 255, 0.08);
+ border: 1px solid rgba(255, 255, 255, 0.15);
+ border-radius: 10px;
+ color: white;
+ margin: 0 4px;
+ padding: 2px 8px;
+ font-size: 0.8rem;
+ width: 120px;
+ height: 24px;
+ outline: none;
+ transition: all 0.2s ease;
+
+ &:focus {
+ border-color: var(--ion-color-secondary);
+ background: rgba(255, 255, 255, 0.12);
+ box-shadow: 0 0 6px rgba(var(--ion-color-secondary-rgb), 0.2);
+ }
+
+ &::placeholder {
+ color: rgba(255, 255, 255, 0.4);
+ }
+ }
}
.small-action-btn {
diff --git a/src/app/home/home.page.ts b/src/app/home/home.page.ts
index 43a5040..bdfd962 100644
--- a/src/app/home/home.page.ts
+++ b/src/app/home/home.page.ts
@@ -1778,6 +1778,50 @@ export class HomePage implements OnDestroy {
this.playlistService.sharePlaylistQR(ids, name, songSettings);
}
+ async cloneActivePlaylist() {
+ const id = this.playlistService.activePlaylistId();
+ const currentName = this.playlistService.activeListName() || 'Playlist';
+ const activeIds = this.playlistService.activeListIds();
+
+ const allPls = this.playlistService.allPlaylists();
+ const activePl = allPls.find(p => p.id === id);
+ const songSettings = activePl ? activePl.songSettings : undefined;
+
+ const alert = await this.alertCtrl.create({
+ header: 'Clona Playlist',
+ inputs: [
+ {
+ name: 'name',
+ type: 'text',
+ placeholder: 'Nome della nuova playlist',
+ value: `${currentName} (Copia)`
+ }
+ ],
+ buttons: [
+ {
+ text: 'Annulla',
+ role: 'cancel'
+ },
+ {
+ text: 'Clona',
+ handler: async (data) => {
+ if (data.name) {
+ await this.playlistService.clonePlaylist(data.name, [...activeIds], songSettings);
+
+ const toast = await this.toastCtrl.create({
+ message: `Playlist clonata nel profilo: ${data.name}`,
+ duration: 2500,
+ color: 'success'
+ });
+ await toast.present();
+ }
+ }
+ }
+ ]
+ });
+ await alert.present();
+ }
+
async importPlaylist() {
const modal = await this.modalCtrl.create({
component: QrScannerComponent
diff --git a/src/app/pages/propose-canto/propose-canto.page.html b/src/app/pages/propose-canto/propose-canto.page.html
index a8747c4..6f4e1c4 100644
--- a/src/app/pages/propose-canto/propose-canto.page.html
+++ b/src/app/pages/propose-canto/propose-canto.page.html
@@ -31,9 +31,19 @@
+
+
+
+ Editor
+
+
+ Anteprima
+
+
+
-
+
Titolo del Canto
@@ -44,7 +54,7 @@
Momento Liturgico
-
+
{{ lit.tag_name }}
@@ -53,7 +63,7 @@
Periodo / Tema
-
+
{{ tem.tag_name }}
@@ -103,13 +113,16 @@
Editor Testo
-
+
-
+
+
+
+
-
+
@@ -142,7 +155,7 @@
-