Refactor: Restringimento drag & drop, legenda impostazioni, modalità offline e rimozione sezione liturgia

This commit is contained in:
David Frassi
2026-05-18 01:36:18 +02:00
parent 9982441c3c
commit 961b7ba65c
22 changed files with 988 additions and 500 deletions
+74 -11
View File
@@ -10,10 +10,6 @@
</div>
</ion-title>
<ion-buttons slot="end">
<div class="offline-badge-header" *ngIf="!connectivityService.isOnline()">
<ion-icon name="cloud-offline-outline"></ion-icon>
</div>
<ion-button (click)="importPlaylist()" class="add-btn">
<ion-icon slot="icon-only" name="qr-code-outline"></ion-icon>
@@ -83,6 +79,17 @@
<ion-icon slot="end" name="close-circle"></ion-icon>
</span>
</ion-button>
<ion-button
[fill]="showSuggeriti() ? 'solid' : 'outline'"
size="small"
(click)="toggleSuggeriti()"
class="filter-chip">
Suggeriti
<span class="close-icon-wrapper" *ngIf="showSuggeriti()" (click)="clearSuggeriti($event)">
<ion-icon slot="end" name="close-circle"></ion-icon>
</span>
</ion-button>
<ion-button
[fill]="activeFilterType() === 'playlist' || playlistService.activeListName() !== null ? 'solid' : 'outline'"
@@ -96,6 +103,17 @@
<ion-icon slot="end" name="close-circle"></ion-icon>
</span>
</ion-button>
<ion-button
[fill]="showTopTen() ? 'solid' : 'outline'"
size="small"
(click)="toggleTopTen()"
class="filter-chip">
Top Ten
<span class="close-icon-wrapper" *ngIf="showTopTen()" (click)="clearTopTen($event)">
<ion-icon slot="end" name="close-circle"></ion-icon>
</span>
</ion-button>
</div>
</div>
</div>
@@ -108,6 +126,9 @@
<!-- Selection Mode Actions -->
<div class="selection-pill glass" *ngIf="playlistService.selectionMode()">
<span class="selection-count">{{ playlistService.selectedIds().size }}</span>
<ion-button fill="clear" color="secondary" (click)="toggleAddingSongs()" class="mini-action-btn">
<ion-icon slot="icon-only" [name]="isAddingSongs() ? 'list-outline' : 'add-circle-outline'"></ion-icon>
</ion-button>
<ion-button fill="clear" color="secondary" (click)="finishSelection()" [disabled]="playlistService.selectedIds().size === 0" class="mini-action-btn">
<ion-icon slot="icon-only" name="save-outline"></ion-icon>
</ion-button>
@@ -162,6 +183,32 @@
(cdkDropListDropped)="drop($event)"
class="transparent-list">
<!-- Premium Suggested Mass Card (Collapsible) -->
<div class="suggeriti-header-card glass ion-margin-bottom"
*ngIf="showSuggeriti() && cantiLettureService.data()"
(click)="isMassCardExpanded.set(!isMassCardExpanded())"
[class.expanded]="isMassCardExpanded()">
<div class="card-inner ion-padding">
<div class="card-header-row">
<div class="card-header-left">
<span class="card-label">SINTESI MESSA</span>
<span class="card-date-compact" *ngIf="!isMassCardExpanded()">{{ getSelectedMassFormattedDate() }}</span>
</div>
<ion-icon [name]="isMassCardExpanded() ? 'chevron-up-outline' : 'chevron-down-outline'" class="expand-icon"></ion-icon>
</div>
<div class="expandable-content" [class.show]="isMassCardExpanded()">
<div class="card-date-row" *ngIf="isMassCardExpanded()">
<span class="card-date">{{ getSelectedMassFormattedDate() }}</span>
</div>
<h1 class="card-title outfit-font">{{ getSelectedMassTitle() }}</h1>
<p class="card-summary outfit-font" *ngIf="getSelectedMassSummary()">
{{ getSelectedMassSummary() }}
</p>
</div>
</div>
</div>
<ion-item *ngFor="let canto of visibleCanti()"
[id]="'canto-' + canto.id"
class="glass ion-margin-bottom custom-item"
@@ -189,13 +236,23 @@
<h2 class="outfit-font" style="font-weight: 500; color: var(--ion-color-secondary)">
{{ canto.titolo }}
</h2>
<p style="color: rgba(255,255,255,0.6); margin-bottom: 2px;">{{ canto.autore || 'Autore sconosciuto' }}</p>
<p style="color: rgba(255,255,255,0.6); margin-bottom: 2px; display: flex; align-items: center; flex-wrap: wrap; gap: 8px;">
<span>{{ canto.autore || 'Autore sconosciuto' }}</span>
<span *ngIf="showTopTen() && getEsecuzioniCount(canto.id) !== null" class="esecuzioni-badge" style="color: var(--ion-color-secondary); font-size: 0.75rem; background: rgba(var(--ion-color-secondary-rgb), 0.12); padding: 2px 6px; border-radius: 6px; display: inline-flex; align-items: center; gap: 4px; border: 1px solid rgba(var(--ion-color-secondary-rgb), 0.2);">
<ion-icon name="stats-chart-outline" style="font-size: 0.75rem; color: var(--ion-color-secondary);"></ion-icon>
{{ getEsecuzioniCount(canto.id) }} esecuzioni
</span>
<span *ngIf="showSuggeriti() && getMassSuggestionWeight(canto.id_canti) !== null" class="suggerito-badge" style="color: var(--ion-color-secondary); font-size: 0.75rem; background: rgba(var(--ion-color-secondary-rgb), 0.12); padding: 2px 6px; border-radius: 6px; display: inline-flex; align-items: center; gap: 4px; border: 1px solid rgba(var(--ion-color-secondary-rgb), 0.3);">
<ion-icon name="sparkles-outline" style="font-size: 0.75rem; color: var(--ion-color-secondary);"></ion-icon>
Attinenza {{ getMassSuggestionWeight(canto.id_canti) }}%
</span>
</p>
</ion-label>
<!-- Video Thumbnail Section -->
<div *ngIf="canto.link_youtube && canto.link_youtube.length > 5" class="thumb-section" (click)="$event.stopPropagation()">
<div class="thumb-container compact">
<ng-container *ngIf="connectivityService.isOnline(); else offlineThumb">
<ng-container *ngIf="youtubePlayerService.isPlayerSupported(); else noPlayerThumb">
<div class="thumb-wrapper" (click)="playVideo($event, canto.id)">
<img [src]="cantiService.getYoutubeThumb(canto.link_youtube)"
class="thumb-img loaded"
@@ -205,11 +262,17 @@
</div>
</div>
</ng-container>
<ng-template #offlineThumb>
<ng-template #noPlayerThumb>
<div class="thumb-wrapper">
<div class="offline-thumb">
<ion-icon name="cloud-offline-outline"></ion-icon>
</div>
<img [src]="cantiService.getYoutubeThumb(canto.link_youtube)"
class="thumb-img loaded"
loading="lazy"
*ngIf="connectivityService.isOnline(); else offlineIcon">
<ng-template #offlineIcon>
<div class="offline-thumb">
<ion-icon name="cloud-offline-outline"></ion-icon>
</div>
</ng-template>
</div>
</ng-template>
</div>
@@ -249,7 +312,7 @@
</ion-content>
<ion-footer *ngIf="youtubePlayerService.currentCantoId()" class="ion-no-border">
<ion-footer *ngIf="youtubePlayerService.isPlayerSupported() && youtubePlayerService.currentCantoId()" class="ion-no-border">
<ion-toolbar class="global-player-toolbar glass">
<div class="player-content">
<div class="controls-row">