Ottimizzazione UI player, rotazione head tilt invertita, prefisso playlist in Home e implementazione Identity QR modal e interceptor API

This commit is contained in:
David Frassi
2026-06-12 17:13:46 +02:00
parent 4d1883a45d
commit d023bb7d3f
31 changed files with 1706 additions and 160 deletions
+43 -24
View File
@@ -7,7 +7,9 @@
<span class="app-name">{{ appName }}</span>
<span class="version-badge" (click)="checkForAppUpdate($event)" style="cursor: pointer; display: inline-flex; align-items: center; gap: 4px;">
v{{ version }}
<ion-icon name="refresh-outline" style="font-size: 0.9em;"></ion-icon>
<span *ngIf="hasUpdateAvailable()" style="display: inline-flex; align-items: center; justify-content: center; padding: 4px; margin-left: 2px; background: rgba(var(--ion-color-secondary-rgb), 0.25); border-radius: 50%; border: 1px solid var(--ion-color-secondary); width: 24px; height: 24px; box-shadow: 0 0 8px rgba(var(--ion-color-secondary-rgb), 0.3);">
<ion-icon name="refresh-outline" style="font-size: 1.15rem; color: var(--ion-color-secondary); font-weight: bold;"></ion-icon>
</span>
</span>
</div>
</div>
@@ -68,14 +70,13 @@
</div>
<ion-button
*ngIf="settingsService.showEditor()"
[fill]="showOnlyMine() ? 'solid' : 'outline'"
[fill]="activeFilterType() === 'lista_completa' || showValidati() || showNonValidati() ? 'solid' : 'outline'"
size="small"
(click)="toggleOnlyMine()"
color="secondary"
(click)="toggleFilterType('lista_completa')"
class="filter-chip">
Miei
<span class="close-icon-wrapper" *ngIf="showOnlyMine()" (click)="clearOnlyMine($event)">
{{ showValidati() ? 'Lista: Validati' : (showNonValidati() ? 'Lista: Non Validati' : 'Lista completa') }}
<ion-icon slot="end" name="chevron-down-outline" *ngIf="!showValidati() && !showNonValidati()"></ion-icon>
<span class="close-icon-wrapper" *ngIf="showValidati() || showNonValidati()" (click)="clearListaCompleta($event)">
<ion-icon slot="end" name="close-circle"></ion-icon>
</span>
</ion-button>
@@ -85,7 +86,7 @@
size="small"
(click)="toggleFilterType('liturgico')"
class="filter-chip">
{{ selectedLiturgico() !== null ? getSelectedLiturgicoLabel() : 'Liturgia' }}
{{ selectedLiturgico() !== null ? 'Liturgia: ' + getSelectedLiturgicoLabel() : 'Liturgia' }}
<ion-icon slot="end" name="chevron-down-outline" *ngIf="selectedLiturgico() === null"></ion-icon>
<span class="close-icon-wrapper" *ngIf="selectedLiturgico() !== null" (click)="clearLiturgico($event)">
<ion-icon slot="end" name="close-circle"></ion-icon>
@@ -97,7 +98,7 @@
size="small"
(click)="toggleFilterType('tematico')"
class="filter-chip">
{{ selectedTematico() !== null ? getSelectedTematicoLabel() : 'Periodo' }}
{{ selectedTematico() !== null ? 'Periodo: ' + getSelectedTematicoLabel() : 'Periodo' }}
<ion-icon slot="end" name="chevron-down-outline" *ngIf="selectedTematico() === null"></ion-icon>
<span class="close-icon-wrapper" *ngIf="selectedTematico() !== null" (click)="clearTematico($event)">
<ion-icon slot="end" name="close-circle"></ion-icon>
@@ -120,7 +121,7 @@
size="small"
(click)="playlistService.allPlaylists().length > 0 ? toggleFilterType('playlist') : playlistService.toggleSelectionMode()"
class="filter-chip">
{{ playlistService.activeListName() !== null ? playlistService.activeListName() : 'Playlist' }}
{{ playlistService.activeListName() !== null ? 'Playlist: ' + playlistService.activeListName() : 'Playlist' }}
<ion-icon slot="end" name="chevron-down-outline" *ngIf="playlistService.activeListName() === null && playlistService.allPlaylists().length > 0"></ion-icon>
<ion-icon slot="end" name="add-circle-outline" *ngIf="playlistService.activeListName() === null && playlistService.allPlaylists().length === 0"></ion-icon>
<span class="close-icon-wrapper" *ngIf="playlistService.activeListName() !== null" (click)="clearSpecialList($event)">
@@ -145,7 +146,7 @@
<!-- Category Scroll (Dropdown style) -->
<ion-toolbar class="bg-gradient momentos-toolbar" *ngIf="activeFilterType() || playlistService.selectionMode() || (playlistService.activeListName() && !playlistService.selectionMode())">
<ion-toolbar class="bg-gradient momentos-toolbar" *ngIf="activeFilterType() || playlistService.selectionMode()">
<div class="momento-scroll">
<!-- Selection Mode Actions -->
<div class="selection-pill glass" *ngIf="playlistService.selectionMode()">
@@ -162,7 +163,7 @@
</div>
<!-- Active Playlist Actions -->
<div class="selection-pill glass" *ngIf="playlistService.activeListName() && !playlistService.selectionMode()">
<div class="selection-pill glass" *ngIf="activeFilterType() === 'playlist' && playlistService.activePlaylistId() && !playlistService.selectionMode()">
<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>
@@ -170,20 +171,37 @@
<ion-icon slot="icon-only" name="share-social-outline"></ion-icon>
</ion-button>
<ion-button fill="clear" color="danger" (click)="deleteActivePlaylist()" class="mini-action-btn" *ngIf="playlistService.activePlaylistId() && !isComunitaPlaylist()">
<ion-icon slot="icon-only" name="trash-outline"></ion-icon>
<ion-icon name="trash-outline" slot="icon-only"></ion-icon>
</ion-button>
</div>
<!-- Filter chips -->
<div
*ngFor="let item of (activeFilterType() === 'playlist' ? playlistService.allPlaylists() : (activeFilterType() === 'liturgico' ? cantiService.indiceLiturgico() : (activeFilterType() === 'tematico' ? cantiService.indiceTematico() : [])))"
class="momento-chip glass"
[class.active]="activeFilterType() === 'playlist' ? playlistService.activePlaylistId() === item.id : isIndexSelected(item.id)"
[class.comunita-chip]="activeFilterType() === 'playlist' && item.isComunita"
(click)="activeFilterType() === 'playlist' ? selectPlaylist(item) : toggleIndex(item.id, activeFilterType()!)">
<ion-icon *ngIf="activeFilterType() === 'playlist' && item.isComunita" name="people-outline" style="font-size: 0.85rem; margin-right: 4px; vertical-align: middle;"></ion-icon>
{{ activeFilterType() === 'playlist' ? item.name : item.tag_name }}
</div>
<ng-container *ngIf="activeFilterType() === 'lista_completa'">
<div
class="momento-chip glass"
[class.active]="showValidati()"
(click)="toggleValidati()">
Validati
</div>
<div
class="momento-chip glass"
[class.active]="showNonValidati()"
(click)="toggleNonValidati()">
Non Validati
</div>
</ng-container>
<ng-container *ngIf="activeFilterType() !== 'lista_completa'">
<div
*ngFor="let item of (activeFilterType() === 'playlist' ? playlistService.allPlaylists() : (activeFilterType() === 'liturgico' ? cantiService.indiceLiturgico() : (activeFilterType() === 'tematico' ? cantiService.indiceTematico() : [])))"
class="momento-chip glass"
[class.active]="activeFilterType() === 'playlist' ? playlistService.activePlaylistId() === item.id : isIndexSelected(item.id)"
[class.comunita-chip]="activeFilterType() === 'playlist' && item.isComunita"
(click)="activeFilterType() === 'playlist' ? selectPlaylist(item) : toggleIndex(item.id, activeFilterType()!)">
<ion-icon *ngIf="activeFilterType() === 'playlist' && item.isComunita" name="people-outline" style="font-size: 0.85rem; margin-right: 4px; vertical-align: middle;"></ion-icon>
{{ activeFilterType() === 'playlist' ? item.name : item.tag_name }}
</div>
</ng-container>
</div>
</ion-toolbar>
</ion-header>
@@ -284,7 +302,7 @@
<div class="item-wrapper">
<!-- Selection Area -->
<div class="selection-column" (click)="playlistService.toggleSongSelection(canto.id); $event.stopPropagation()">
<div class="selection-column" (click)="toggleSongSelection(canto.id); $event.stopPropagation()">
<span class="canto-number" [class.selected-number]="playlistService.selectedIds().has(canto.id)">
{{ canto.id.startsWith('my_') ? getMySongNumber(canto) : canto.id_canti }}
</span>
@@ -297,7 +315,8 @@
<h2 class="outfit-font" style="font-weight: 500; color: var(--ion-color-secondary); display: flex; align-items: center; flex-wrap: wrap; gap: 4px;">
<span *ngIf="getCommunitySongNumber(canto)" style="color: var(--ion-color-secondary); font-weight: 600; margin-right: 8px; opacity: 0.9;">{{ getCommunitySongNumber(canto) }}</span>
<span>{{ canto.titolo }}</span>
<span *ngIf="canto.nonValidato" class="non-validato-badge">Non Validato</span>
<span *ngIf="canto.nonValidato && !canto.id.startsWith('my_')" class="non-validato-badge remote-badge">Remoto</span>
<span *ngIf="canto.id.startsWith('my_')" class="non-validato-badge mio-badge">Mio</span>
</h2>
<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>