feat: show instructions when playlist is empty & fix high contrast contrast
This commit is contained in:
+18
-20
@@ -6,7 +6,7 @@
|
||||
<div class="header-text-group">
|
||||
<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 }}
|
||||
v{{ version }}<span *ngIf="settingsService.userName()"> - {{ settingsService.userName() }}</span>
|
||||
<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>
|
||||
@@ -48,11 +48,10 @@
|
||||
<ion-button
|
||||
[fill]="activeFilterType() === 'playlist' || playlistService.activeListName() !== null ? 'solid' : 'outline'"
|
||||
size="small"
|
||||
(click)="playlistService.allPlaylists().length > 0 ? toggleFilterType('playlist') : playlistService.toggleSelectionMode()"
|
||||
(click)="toggleFilterType('playlist')"
|
||||
class="filter-chip">
|
||||
{{ 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>
|
||||
<ion-icon slot="end" name="chevron-down-outline" *ngIf="playlistService.activeListName() === null"></ion-icon>
|
||||
<span class="close-icon-wrapper" *ngIf="playlistService.activeListName() !== null" (click)="clearSpecialList($event)">
|
||||
<ion-icon slot="end" name="close-circle"></ion-icon>
|
||||
</span>
|
||||
@@ -69,14 +68,6 @@
|
||||
<ion-icon slot="start" name="people-outline" style="font-size: 1.1rem; margin-right: 4px;"></ion-icon>
|
||||
{{ comunitaService.comunitaCode() ? comunitaService.comunitaNome() : 'Comunità' }}
|
||||
</ion-button>
|
||||
|
||||
<div
|
||||
*ngIf="comunitaService.comunitaCode()"
|
||||
(click)="editComunitaCode($event)"
|
||||
style="position: absolute; top: -6px; right: -6px; z-index: 99999; background: var(--ion-color-secondary); color: white; border-radius: 50%; width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; border: 1.5px solid #1a1a1a; cursor: pointer; box-shadow: 0 2px 4px rgba(0,0,0,0.3);"
|
||||
class="floating-edit-badge">
|
||||
<ion-icon name="create-outline" style="font-size: 0.85rem; pointer-events: none;"></ion-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ion-button
|
||||
@@ -143,18 +134,18 @@
|
||||
|
||||
|
||||
<!-- Category Scroll (Dropdown style) -->
|
||||
<ion-toolbar class="bg-gradient momentos-toolbar" *ngIf="activeFilterType() || playlistService.selectionMode()">
|
||||
<div class="momento-scroll">
|
||||
<ion-toolbar class="bg-gradient momentos-toolbar" *ngIf="shouldShowSubSectionToolbar()">
|
||||
<div class="momento-scroll" *ngIf="activeFilterType() !== 'playlist' || playlistService.allPlaylists().length > 0 || playlistService.selectionMode()">
|
||||
<!-- 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">
|
||||
<div class="selection-pill glass" *ngIf="playlistService.selectionMode() && reorderList().length > 0">
|
||||
<span class="selection-count">{{ reorderList().length }}</span>
|
||||
<ion-button fill="clear" color="secondary" (click)="toggleAddingSongs()" class="mini-action-btn" *ngIf="reorderList().length > 0">
|
||||
<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-button fill="clear" color="secondary" (click)="finishSelection()" [disabled]="reorderList().length === 0" class="mini-action-btn" *ngIf="reorderList().length > 0">
|
||||
<ion-icon slot="icon-only" name="save-outline"></ion-icon>
|
||||
</ion-button>
|
||||
<ion-button fill="clear" color="danger" (click)="cancelSelection()" class="mini-action-btn">
|
||||
<ion-button fill="clear" color="danger" (click)="cancelSelection()" class="mini-action-btn" *ngIf="reorderList().length > 0">
|
||||
<ion-icon slot="icon-only" name="close-circle-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</div>
|
||||
@@ -191,7 +182,7 @@
|
||||
name="add-outline"
|
||||
(click)="$event.stopPropagation()"
|
||||
routerLink="/propose-canto"
|
||||
style="font-size: 1.1rem; color: #000; font-weight: bold; background: rgba(0,0,0,0.1); border-radius: 50%; padding: 2px;">
|
||||
class="non-validati-add-icon">
|
||||
</ion-icon>
|
||||
</div>
|
||||
</ng-container>
|
||||
@@ -208,6 +199,13 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<!-- Instructions when playlist is empty -->
|
||||
<div class="empty-playlist-container" *ngIf="activeFilterType() === 'playlist' && playlistService.allPlaylists().length === 0 && !playlistService.selectionMode()">
|
||||
<p class="empty-playlist-instruction outfit-font">
|
||||
Per creare una playlist, seleziona il nr dei canti che vuoi inserire nella playlist, riordinali e salvala con nome
|
||||
</p>
|
||||
</div>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
|
||||
@@ -368,6 +368,24 @@ ion-title {
|
||||
}
|
||||
}
|
||||
|
||||
.non-validati-add-icon {
|
||||
font-size: 1.1rem;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 50%;
|
||||
padding: 2px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
:host-context(body.high-contrast) {
|
||||
.non-validati-add-icon {
|
||||
color: #ffffff !important;
|
||||
background: rgba(255, 255, 255, 0.2) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Custom Item Layout
|
||||
.custom-item {
|
||||
--padding-start: 16px;
|
||||
@@ -1285,3 +1303,38 @@ ion-title {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-playlist-container {
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.empty-playlist-instruction {
|
||||
margin: 0;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.4;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
text-align: center;
|
||||
background: rgba(var(--ion-color-secondary-rgb), 0.08);
|
||||
border: 1px dashed rgba(var(--ion-color-secondary-rgb), 0.35);
|
||||
padding: 12px 16px;
|
||||
border-radius: 12px;
|
||||
max-width: 480px;
|
||||
width: 100%;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
:host-context(body.high-contrast) {
|
||||
.empty-playlist-instruction {
|
||||
color: #000000 !important;
|
||||
background: rgba(var(--ion-color-secondary-rgb), 0.12) !important;
|
||||
border-color: var(--ion-color-secondary) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+19
-95
@@ -773,9 +773,15 @@ export class HomePage implements OnDestroy {
|
||||
if (response.ok) {
|
||||
const remoteJson = await response.json();
|
||||
if (Array.isArray(remoteJson)) {
|
||||
// Reconstruct user name/metadata
|
||||
const userMetadata = remoteJson.find((item: any) => item.momenti && item.momenti.includes('UserMetadata'));
|
||||
if (userMetadata && userMetadata.titolo) {
|
||||
this.settingsService.setUserName(userMetadata.titolo);
|
||||
}
|
||||
|
||||
// Reconstruct custom songs
|
||||
const customSongs = remoteJson
|
||||
.filter((item: any) => !item.momenti || !item.momenti.includes('Playlist'))
|
||||
.filter((item: any) => (!item.momenti || !item.momenti.includes('Playlist')) && (!item.momenti || !item.momenti.includes('UserMetadata')))
|
||||
.map((item: any) => ({
|
||||
id: `my_${item.id_canti}`,
|
||||
id_canti: Number(item.id_canti),
|
||||
@@ -1025,6 +1031,17 @@ export class HomePage implements OnDestroy {
|
||||
this.searchQuery() !== '';
|
||||
}
|
||||
|
||||
shouldShowSubSectionToolbar(): boolean {
|
||||
if (this.playlistService.selectionMode() && this.reorderList().length > 0) {
|
||||
return true;
|
||||
}
|
||||
const filterType = this.activeFilterType();
|
||||
if (filterType) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
clearAllFilters() {
|
||||
this.selectedLiturgico.set(null);
|
||||
this.selectedTematico.set(null);
|
||||
@@ -1655,105 +1672,12 @@ export class HomePage implements OnDestroy {
|
||||
}
|
||||
|
||||
toggleComunitaFilter() {
|
||||
if (!this.comunitaService.comunitaCode()) {
|
||||
this.promptComunitaCode();
|
||||
} else {
|
||||
if (this.comunitaService.comunitaCode()) {
|
||||
this.comunitaService.isFilterActive.update(v => !v);
|
||||
}
|
||||
this.activeFilterType.set(null);
|
||||
}
|
||||
|
||||
editComunitaCode(event: Event) {
|
||||
event.stopPropagation();
|
||||
this.promptComunitaCode();
|
||||
}
|
||||
|
||||
async promptComunitaCode() {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Imposta Comunità',
|
||||
subHeader: 'Inserisci il codice parrocchiale/comunità per attivare il libretto dedicato:',
|
||||
cssClass: 'premium-alert',
|
||||
inputs: [
|
||||
{
|
||||
name: 'code',
|
||||
type: 'text',
|
||||
placeholder: 'Es: 123456',
|
||||
value: this.comunitaService.comunitaCode()
|
||||
}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
text: 'Annulla',
|
||||
role: 'cancel'
|
||||
},
|
||||
{
|
||||
text: 'Rimuovi',
|
||||
role: 'destructive',
|
||||
cssClass: 'alert-button-delete',
|
||||
handler: async () => {
|
||||
await this.comunitaService.setComunitaCode('');
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Comunità disattivata.',
|
||||
duration: 2000,
|
||||
color: 'secondary'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Salva',
|
||||
handler: async (data) => {
|
||||
const trimmed = (data.code || '').trim();
|
||||
if (!trimmed) {
|
||||
await this.comunitaService.setComunitaCode('');
|
||||
return;
|
||||
}
|
||||
|
||||
// Show loading overlay with progress
|
||||
const loading = await this.loadingCtrl.create({
|
||||
message: 'Caricamento 0%',
|
||||
cssClass: 'premium-loading',
|
||||
spinner: 'crescent'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
// Subscribe to progress updates
|
||||
let progressInterval: any = null;
|
||||
progressInterval = setInterval(() => {
|
||||
const pct = this.comunitaService.loadingProgress();
|
||||
loading.message = `Caricamento ${pct}%`;
|
||||
if (pct >= 100) {
|
||||
clearInterval(progressInterval);
|
||||
}
|
||||
}, 100);
|
||||
|
||||
const success = await this.comunitaService.setComunitaCode(trimmed);
|
||||
clearInterval(progressInterval);
|
||||
await loading.dismiss();
|
||||
|
||||
if (success) {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: `Comunità attivata: ${this.comunitaService.comunitaNome()}`,
|
||||
duration: 2000,
|
||||
color: 'success'
|
||||
});
|
||||
await toast.present();
|
||||
} else {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Codice non trovato o errore di connessione.',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
setTimeout(() => this.promptComunitaCode(), 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
await alert.present();
|
||||
}
|
||||
|
||||
private massCardStartX: number = 0;
|
||||
private massCardStartY: number = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user