gestione comunità
This commit is contained in:
+229
-9
@@ -9,11 +9,12 @@ import { PlaylistService } from '../services/playlist.service';
|
||||
import { SettingsService } from '../services/settings.service';
|
||||
import { VERSION } from '../version';
|
||||
import { YoutubePlayerService } from '../services/youtube-player.service';
|
||||
import { ModalController, AlertController, ToastController } from '@ionic/angular';
|
||||
import { ModalController, AlertController, ToastController, LoadingController } from '@ionic/angular';
|
||||
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
import { MyCantiService } from '../services/my-canti.service';
|
||||
import { QrScannerComponent } from '../components/qr-scanner/qr-scanner.component';
|
||||
import { CantiLettureService } from '../services/canti-letture.service';
|
||||
import { ComunitaService } from '../services/comunita.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
@@ -38,6 +39,7 @@ export class HomePage implements OnDestroy {
|
||||
|
||||
public fontSize = signal<number>(1.0);
|
||||
public youtubePlayerService = inject(YoutubePlayerService);
|
||||
public comunitaService = inject(ComunitaService);
|
||||
public isSeeking = false;
|
||||
|
||||
private readonly MIN_FONT = 0.6;
|
||||
@@ -59,6 +61,7 @@ export class HomePage implements OnDestroy {
|
||||
private modalCtrl = inject(ModalController);
|
||||
private alertCtrl = inject(AlertController);
|
||||
private toastCtrl = inject(ToastController);
|
||||
private loadingCtrl = inject(LoadingController);
|
||||
|
||||
private firstInteraction = true;
|
||||
|
||||
@@ -70,7 +73,14 @@ export class HomePage implements OnDestroy {
|
||||
|
||||
private scrollEffect = effect(() => {
|
||||
const activeId = this.youtubePlayerService.currentCantoId();
|
||||
const list = this.filteredCanti();
|
||||
|
||||
if (activeId) {
|
||||
const index = list.findIndex(c => c.id === activeId);
|
||||
if (index !== -1 && index >= this.limit()) {
|
||||
this.limit.set(index + 15);
|
||||
}
|
||||
|
||||
// Delay slightly to ensure DOM is updated and classes are applied
|
||||
setTimeout(() => {
|
||||
const element = document.getElementById('canto-' + activeId);
|
||||
@@ -79,7 +89,7 @@ export class HomePage implements OnDestroy {
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}, { allowSignalWrites: true });
|
||||
|
||||
private normalize(str: string | undefined): string {
|
||||
if (!str) return '';
|
||||
@@ -103,6 +113,25 @@ export class HomePage implements OnDestroy {
|
||||
|
||||
let list = [...this.cantiService.canti(), ...this.myCantiService.myCanti()];
|
||||
|
||||
// Filter by Community if code is set and filter is active
|
||||
const comunitaCode = this.comunitaService.comunitaCode();
|
||||
const comunitaIds = this.comunitaService.comunitaCantiIds();
|
||||
if (comunitaCode && this.comunitaService.isFilterActive()) {
|
||||
list = list.filter(c => {
|
||||
return comunitaIds.includes(c.id_canti) || comunitaIds.includes(c.id);
|
||||
});
|
||||
|
||||
// Sort list by community song number (num_canto) ASC!
|
||||
const cantiInfo = this.comunitaService.comunitaCantiInfo();
|
||||
list.sort((a, b) => {
|
||||
const infoA = cantiInfo.find(x => x.id_canti === a.id_canti || x.id_canti === Number(a.id));
|
||||
const infoB = cantiInfo.find(x => x.id_canti === b.id_canti || x.id_canti === Number(b.id));
|
||||
const numA = infoA ? Number(infoA.num_canto) : 999999;
|
||||
const numB = infoB ? Number(infoB.num_canto) : 999999;
|
||||
return numA - numB;
|
||||
});
|
||||
}
|
||||
|
||||
if (onlyMine) {
|
||||
list = this.myCantiService.myCanti();
|
||||
}
|
||||
@@ -160,17 +189,21 @@ export class HomePage implements OnDestroy {
|
||||
// Converte "uno" in "1" per facilitare la ricerca vocale (es. "numero uno")
|
||||
const processedQuery = query.replace(/\buno\b/g, '1');
|
||||
|
||||
// Se la ricerca inizia con "numero" o "nr", filtra esattamente per id_canti
|
||||
// Se la ricerca inizia con "numero" o "nr", filtra esattamente per id_canti/comunita number
|
||||
const numberMatchPattern = processedQuery.match(/^(?:numero|nr\.?)\s*(\d+)$/);
|
||||
if (numberMatchPattern) {
|
||||
const targetId = numberMatchPattern[1];
|
||||
return list.filter(c => c.id_canti.toString() === targetId);
|
||||
return list.filter(c => {
|
||||
const commNum = this.getCommunitySongNumber(c);
|
||||
return commNum ? commNum === targetId : c.id_canti.toString() === targetId;
|
||||
});
|
||||
}
|
||||
|
||||
return list.filter(c => {
|
||||
const titleMatch = this.normalize(c.titolo).includes(query);
|
||||
const authorMatch = this.normalize(c.autore).includes(query);
|
||||
const numberMatch = c.id_canti.toString().includes(query);
|
||||
const commNum = this.getCommunitySongNumber(c);
|
||||
const numberMatch = commNum ? commNum.includes(query) : c.id_canti.toString().includes(query);
|
||||
|
||||
// Strip tags like {Chorus} and newlines from lyrics before searching
|
||||
const lyricsPlain = (c.testo || '')
|
||||
@@ -642,10 +675,6 @@ export class HomePage implements OnDestroy {
|
||||
setTimeout(() => {
|
||||
this.limit.update(l => l + 10);
|
||||
event.target.complete();
|
||||
|
||||
if (this.limit() >= this.filteredCanti().length) {
|
||||
event.target.disabled = true;
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
@@ -883,4 +912,195 @@ export class HomePage implements OnDestroy {
|
||||
this.limit.set(10);
|
||||
}
|
||||
|
||||
getCommunitySongNumber(canto: any): string | null {
|
||||
if (!this.comunitaService.comunitaCode() || !this.comunitaService.isFilterActive()) return null;
|
||||
const cantiInfo = this.comunitaService.comunitaCantiInfo();
|
||||
const info = cantiInfo.find(x => x.id_canti === canto.id_canti || x.id_canti === Number(canto.id));
|
||||
return info && info.num_canto ? info.num_canto.toString() : null;
|
||||
}
|
||||
|
||||
toggleComunitaFilter() {
|
||||
if (!this.comunitaService.comunitaCode()) {
|
||||
this.promptComunitaCode();
|
||||
} else {
|
||||
this.comunitaService.isFilterActive.update(v => !v);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
onMassCardTouchStart(event: TouchEvent) {
|
||||
if (event.touches.length === 1) {
|
||||
this.massCardStartX = event.touches[0].clientX;
|
||||
this.massCardStartY = event.touches[0].clientY;
|
||||
}
|
||||
}
|
||||
|
||||
onMassCardTouchEnd(event: TouchEvent) {
|
||||
if (event.changedTouches.length === 1) {
|
||||
const endX = event.changedTouches[0].clientX;
|
||||
const endY = event.changedTouches[0].clientY;
|
||||
const diffX = endX - this.massCardStartX;
|
||||
const diffY = endY - this.massCardStartY;
|
||||
|
||||
// Ensure it is a horizontal swipe (diffX is much larger than diffY)
|
||||
if (Math.abs(diffX) > 60 && Math.abs(diffY) < 40) {
|
||||
// Prevent triggering click expansion
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
if (diffX > 0) {
|
||||
// Swiped right -> go to PREVIOUS date
|
||||
this.navigateMassDate(-1);
|
||||
} else {
|
||||
// Swiped left -> go to NEXT date
|
||||
this.navigateMassDate(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async navigateMassDate(direction: number) {
|
||||
const list = this.cantiLettureService.availableMasses();
|
||||
if (list.length === 0) return;
|
||||
|
||||
const currentDate = this.cantiLettureService.selectedMassDate();
|
||||
if (!currentDate) {
|
||||
this.cantiLettureService.selectedMassDate.set(list[0].date);
|
||||
return;
|
||||
}
|
||||
|
||||
const currentIndex = list.findIndex(m => m.date === currentDate);
|
||||
if (currentIndex === -1) {
|
||||
this.cantiLettureService.selectedMassDate.set(list[0].date);
|
||||
return;
|
||||
}
|
||||
|
||||
const nextIndex = currentIndex + direction;
|
||||
if (nextIndex >= 0 && nextIndex < list.length) {
|
||||
// Set the next/prev date
|
||||
this.cantiLettureService.selectedMassDate.set(list[nextIndex].date);
|
||||
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: `Messa: ${list[nextIndex].day} ${this.formatCompactDate(list[nextIndex].date)}`,
|
||||
duration: 1500,
|
||||
color: 'secondary',
|
||||
position: 'bottom'
|
||||
});
|
||||
await toast.present();
|
||||
} else {
|
||||
// "quando le messe sono finite rimani sull'ultima valorizzata, non dare errore"
|
||||
const targetIndex = direction > 0 ? list.length - 1 : 0;
|
||||
this.cantiLettureService.selectedMassDate.set(list[targetIndex].date);
|
||||
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: direction > 0 ? 'Nessun\'altra messa futura disponibile.' : 'Nessun\'altra messa passata disponibile.',
|
||||
duration: 1500,
|
||||
color: 'medium',
|
||||
position: 'bottom'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
}
|
||||
|
||||
private formatCompactDate(dateStr: string): string {
|
||||
const parts = dateStr.split('-');
|
||||
if (parts.length === 3) {
|
||||
return `${parts[2]}/${parts[1]}`;
|
||||
}
|
||||
return dateStr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user