canti primo tag
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
import { Injectable, signal, inject } from '@angular/core';
|
||||
import { Storage } from '@ionic/storage-angular';
|
||||
import { Canto, CantiService } from './canti.service';
|
||||
import * as QRCode from 'qrcode';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class PlaylistService {
|
||||
private storage = inject(Storage);
|
||||
private cantiService = inject(CantiService);
|
||||
|
||||
public selectionMode = signal<boolean>(false);
|
||||
public selectedIds = signal<Set<string>>(new Set());
|
||||
public playlists = signal<any[]>([]);
|
||||
public lastPlaylist = signal<any | null>(null);
|
||||
public autoPlayPlaylist = signal<boolean>(false);
|
||||
|
||||
public activeListIds = signal<string[]>([]);
|
||||
public activeListName = signal<string | null>(null);
|
||||
public activePlaylistId = signal<string | null>(null);
|
||||
|
||||
private _storage: Storage | null = null;
|
||||
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
const storage = await this.storage.create();
|
||||
this._storage = storage;
|
||||
const saved = await this._storage.get('playlists');
|
||||
if (saved) {
|
||||
this.playlists.set(saved);
|
||||
}
|
||||
const last = await this._storage?.get('lastPlaylist');
|
||||
if (last) {
|
||||
this.lastPlaylist.set(last);
|
||||
}
|
||||
}
|
||||
|
||||
toggleSelectionMode() {
|
||||
this.selectionMode.update(v => !v);
|
||||
if (!this.selectionMode()) {
|
||||
this.selectedIds.set(new Set());
|
||||
}
|
||||
}
|
||||
|
||||
toggleSongSelection(id: string) {
|
||||
if (!this.selectionMode()) {
|
||||
const active = this.activeListIds();
|
||||
if (active.length > 0) {
|
||||
this.selectedIds.set(new Set(active));
|
||||
}
|
||||
this.selectionMode.set(true);
|
||||
}
|
||||
this.selectedIds.update(set => {
|
||||
const newSet = new Set(set);
|
||||
if (newSet.has(id)) {
|
||||
newSet.delete(id);
|
||||
} else {
|
||||
newSet.add(id);
|
||||
}
|
||||
return newSet;
|
||||
});
|
||||
}
|
||||
|
||||
async savePlaylist(name: string, ids: string[]) {
|
||||
const editId = this.activePlaylistId();
|
||||
let newPlaylist: any;
|
||||
|
||||
if (editId) {
|
||||
this.playlists.update(p => p.map(pl => {
|
||||
if (pl.id === editId) {
|
||||
return { ...pl, name, ids };
|
||||
}
|
||||
return pl;
|
||||
}));
|
||||
newPlaylist = this.playlists().find(pl => pl.id === editId);
|
||||
} else {
|
||||
newPlaylist = {
|
||||
id: Date.now().toString(),
|
||||
name,
|
||||
ids,
|
||||
createdAt: new Date()
|
||||
};
|
||||
this.playlists.update(p => [newPlaylist, ...p]);
|
||||
}
|
||||
|
||||
this.lastPlaylist.set(newPlaylist);
|
||||
this.activeListIds.set(ids);
|
||||
this.activeListName.set(name);
|
||||
await this._storage?.set('playlists', this.playlists());
|
||||
await this._storage?.set('lastPlaylist', newPlaylist);
|
||||
|
||||
// Reset selection mode, IDs and editing state after saving
|
||||
this.selectedIds.set(new Set());
|
||||
this.selectionMode.set(false);
|
||||
this.activePlaylistId.set(newPlaylist.id);
|
||||
}
|
||||
|
||||
async deletePlaylist(id: string) {
|
||||
this.playlists.update(p => p.filter(pl => pl.id !== id));
|
||||
await this._storage?.set('playlists', this.playlists());
|
||||
}
|
||||
|
||||
async generateQR(ids: string[], name: string): Promise<string> {
|
||||
const data = this.getShareLink(ids, name);
|
||||
return await QRCode.toDataURL(data, {
|
||||
width: 400,
|
||||
margin: 2,
|
||||
color: {
|
||||
dark: '#2d3436',
|
||||
light: '#ffffff'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getShareLink(ids: string[], name: string): string {
|
||||
const data = JSON.stringify({ name, ids });
|
||||
// Use btoa safely for UTF-8 strings
|
||||
const base64 = btoa(unescape(encodeURIComponent(data)));
|
||||
|
||||
// Always use the production URL for sharing links as requested
|
||||
const productionUrl = 'https://www.canticristiani.it/ionic';
|
||||
return `${productionUrl}/?import=${base64}`;
|
||||
}
|
||||
|
||||
processImportJson(json: any): boolean {
|
||||
if (json && json.name && json.ids) {
|
||||
this.activeListIds.set(json.ids);
|
||||
this.activeListName.set(json.name);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async sharePlaylistQR(ids: string[], name: string) {
|
||||
const qrImage = await this.generateQR(ids, name);
|
||||
const shareLink = this.getShareLink(ids, name);
|
||||
const fileName = `${name.toLowerCase().replace(/\s+/g, '_')}_qr.png`;
|
||||
|
||||
try {
|
||||
const res = await fetch(qrImage);
|
||||
const blob = await res.blob();
|
||||
const file = new File([blob], fileName, { type: 'image/png' });
|
||||
|
||||
if (navigator.share && navigator.canShare && navigator.canShare({ files: [file] })) {
|
||||
await navigator.share({
|
||||
files: [file],
|
||||
title: 'Playlist CantiCristiani',
|
||||
text: `Ecco la playlist: ${name}\n\nClicca qui per aprirla subito: ${shareLink}`
|
||||
});
|
||||
} else {
|
||||
// Fallback: download
|
||||
const link = document.createElement('a');
|
||||
link.href = qrImage;
|
||||
link.download = fileName;
|
||||
link.click();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Share failed', err);
|
||||
}
|
||||
}
|
||||
|
||||
async loadPlaylists() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user