feat: condivisione e importazione automatica del codice comunità nelle playlist con priorità tonalità e autoscroll e rifinitura UI

This commit is contained in:
David Frassi
2026-05-23 16:53:09 +02:00
parent b220167794
commit 960c73fbd0
20 changed files with 680 additions and 122 deletions
+1 -1
View File
@@ -160,7 +160,7 @@
<!-- Active Playlist Actions -->
<div class="selection-pill glass" *ngIf="playlistService.activeListName() && !playlistService.selectionMode()">
<ion-button fill="clear" color="secondary" (click)="editPlaylist()" class="mini-action-btn" *ngIf="!isComunitaPlaylist()">
<ion-button fill="clear" color="secondary" (click)="editPlaylist()" class="mini-action-btn" *ngIf="!isComunitaPlaylist() && isActivePlaylistSaved()">
<ion-icon slot="icon-only" name="create-outline"></ion-icon>
</ion-button>
<ion-button fill="clear" color="secondary" (click)="shareActivePlaylist()" class="mini-action-btn">
+2 -2
View File
@@ -174,7 +174,7 @@ ion-title {
align-items: center;
justify-content: flex-start;
gap: 12px;
padding: 16px 0 4px 24px; // Reduced padding to bring search bar closer
padding: 16px 0 16px 24px; // Spacing adjusted for search bar breathing room
}
.header-logo {
@@ -318,7 +318,7 @@ ion-title {
.search-wrapper-group {
display: flex;
flex-direction: column;
padding: 0 16px 8px 16px;
padding: 6px 16px 8px 16px; // Added slight top padding for search bar breathing room
gap: 8px;
}
+80 -7
View File
@@ -131,9 +131,9 @@ export class HomePage implements OnDestroy {
...this.comunitaService.comunitaCantiPersonali()
];
// Filter to only community canti
// Filter to only community canti, but preserve canti that are in the active playlist
list = list.filter(c => {
return comunitaIds.includes(c.id_canti) || comunitaIds.includes(c.id);
return comunitaIds.includes(c.id_canti) || comunitaIds.includes(c.id) || activeIds.includes(c.id);
});
// Deduplicate: parish-customized versions take precedence
@@ -144,7 +144,7 @@ export class HomePage implements OnDestroy {
if (!existing) {
seen.set(key, canto);
} else {
if (!existing.nonValidato && canto.nonValidato) {
if (!existing.isPersonal && canto.isPersonal) {
seen.set(key, canto);
}
}
@@ -253,6 +253,9 @@ export class HomePage implements OnDestroy {
});
public visibleCanti = computed(() => {
if (this.playlistService.selectionMode() && !this.isAddingSongs()) {
return this.filteredCanti();
}
return this.filteredCanti().slice(0, this.limit());
});
@@ -393,15 +396,70 @@ export class HomePage implements OnDestroy {
}
}
handleImport(base64: string) {
async handleImport(base64: string) {
try {
const decoded = decodeURIComponent(escape(atob(base64)));
const json = JSON.parse(decoded);
if (json && json.comunitaCode) {
// 1. Abilita la funzionalità comunità nelle impostazioni
this.settingsService.comunitaEnabled.set(true);
localStorage.setItem('comunita-enabled', 'true');
// 2. Mostra un overlay di caricamento premium con indicatore di progresso
const loading = await this.loadingCtrl.create({
message: 'Attivazione comunità: Caricamento 0%',
cssClass: 'premium-loading',
spinner: 'crescent'
});
await loading.present();
// Iscrizione agli aggiornamenti di progresso
let progressInterval: any = null;
progressInterval = setInterval(() => {
const pct = this.comunitaService.loadingProgress();
loading.message = `Attivazione comunità: Caricamento ${pct}%`;
if (pct >= 100) {
clearInterval(progressInterval);
}
}, 100);
const success = await this.comunitaService.setComunitaCode(json.comunitaCode);
clearInterval(progressInterval);
await loading.dismiss();
if (success) {
const toast = await this.toastCtrl.create({
message: `Comunità attivata: ${this.comunitaService.comunitaNome()}`,
duration: 2500,
color: 'success',
position: 'bottom'
});
await toast.present();
} else {
const toast = await this.toastCtrl.create({
message: 'Codice comunità non trovato o errore di connessione.',
duration: 3000,
color: 'danger',
position: 'bottom'
});
await toast.present();
}
}
if (this.playlistService.processImportJson(json)) {
this.limit.set(50); // Mostra più canti inizialmente per le playlist speciali
this.router.navigate([], { queryParams: { import: null }, queryParamsHandling: 'merge' });
}
} catch (e) {
console.error('Failed to import playlist', e);
const toast = await this.toastCtrl.create({
message: 'Errore durante l\'importazione della playlist.',
duration: 3000,
color: 'danger',
position: 'bottom'
});
await toast.present();
}
}
@@ -847,21 +905,25 @@ export class HomePage implements OnDestroy {
if (data.startsWith('canti:')) {
const parts = data.replace('canti:', '').split(':');
let idsStr = '';
let playlistName = 'Lista Parrocchiale';
if (parts.length > 1) {
this.playlistService.activeListName.set(parts[0]);
playlistName = parts[0];
idsStr = parts[1];
} else {
this.playlistService.activeListName.set('Lista Parrocchiale');
idsStr = parts[0];
}
const ids = idsStr.split(',').map(id => id.trim());
this.playlistService.activeListIds.set(ids);
this.playlistService.activeListName.set(playlistName);
this.limit.set(50); // Show more initially for special lists
// Clear other filters to avoid confusion
this.selectedLiturgico.set(null);
this.selectedTematico.set(null);
// Automatically save to the device!
this.playlistService.savePlaylist(playlistName, ids);
}
}
@@ -936,6 +998,12 @@ export class HomePage implements OnDestroy {
return !!id && id.startsWith('comunita_');
}
isActivePlaylistSaved(): boolean {
const id = this.playlistService.activePlaylistId();
if (!id) return false;
return this.playlistService.playlists().some(p => p.id === id);
}
clearSpecialList(event?: Event) {
if (event) event.stopPropagation();
this.playlistService.activeListIds.set([]);
@@ -955,7 +1023,12 @@ export class HomePage implements OnDestroy {
shareActivePlaylist() {
const ids = this.playlistService.activeListIds();
const name = this.playlistService.activeListName() || 'Playlist';
this.playlistService.sharePlaylistQR(ids, name);
const id = this.playlistService.activePlaylistId();
const pl = this.playlistService.playlists().find(p => p.id === id);
const songSettings = pl ? pl.songSettings : undefined;
this.playlistService.sharePlaylistQR(ids, name, songSettings);
}
async importPlaylist() {