feat: actualización a v1.1.9 con Agenda interactiva y correcciones visuales

This commit is contained in:
Carlos Tello
2026-03-27 07:43:41 -03:00
parent d3243c0166
commit f1da6175ae
20 changed files with 1525 additions and 404 deletions
+51 -12
View File
@@ -1,6 +1,8 @@
import { Injectable } from '@angular/core';
import { Filesystem, Directory, Encoding } from '@capacitor/filesystem';
import { FilePicker } from '@capawesome/capacitor-file-picker';
import { EventoAcademico } from './data';
@Injectable({
providedIn: 'root'
@@ -23,7 +25,7 @@ export class CsvStorageService {
}
}
async saveFavoritesToCsv(favoritos: string[]) {
async saveUserDataToCsv(favoritos: string[], eventos: EventoAcademico[]) {
try {
const hasPermission = await this.ensurePermissions();
if (!hasPermission) {
@@ -31,12 +33,22 @@ export class CsvStorageService {
return;
}
let csvContent = 'tipo,valor\n';
let csvContent = 'tipo,materia,id_o_valor,extra1,extra2,extra3,extra4\n';
// Filas de favoritos
favoritos.forEach(codigo => {
csvContent += `favorito,${codigo}\n`;
csvContent += `favorito,${codigo},,,,\n`;
});
// Intentamos borrar si existe para forzar la actualización transparente en Scoped Storage
// Filas de eventos
eventos.forEach(ev => {
// Formato: evento,CODIGO,ID,TIPO,FECHA,AULA,LINK,NOTAS
// Para simplificar el CSV sin escapar comas en notas, reemplazamos comas por punto y coma
const notasEscaped = (ev.notas || '').replace(/,/g, ';');
csvContent += `evento,${ev.materiaCodigo},${ev.id},${ev.tipo},${ev.fecha},${ev.aula || ''},${ev.link || ''},${notasEscaped}\n`;
});
// Intentamos borrar si existe
try {
await Filesystem.deleteFile({
path: this.FILE_NAME,
@@ -50,13 +62,14 @@ export class CsvStorageService {
directory: Directory.Documents,
encoding: Encoding.UTF8
});
console.log('CSV guardado exitosamente en Documents');
console.log('CSV con datos de usuario guardado en Documents');
} catch (e) {
console.error('Error al guardar el CSV:', e);
}
}
async loadFavoritesFromCsv(): Promise<string[] | null> {
async loadUserDataFromCsv(): Promise<{ favoritos: string[], eventos: EventoAcademico[] } | null> {
try {
const hasPermission = await this.ensurePermissions();
if (!hasPermission) return null;
@@ -71,23 +84,42 @@ export class CsvStorageService {
const lines = contents.data.toString().split('\n');
const favs: string[] = [];
const evs: EventoAcademico[] = [];
for (let i = 1; i < lines.length; i++) {
const line = lines[i].trim();
if (line.startsWith('favorito,')) {
const parts = line.split(',');
if (!line) continue;
const parts = line.split(',');
const tipo = parts[0];
if (tipo === 'favorito') {
if (parts.length > 1 && parts[1]) {
favs.push(parts[1]);
}
} else if (tipo === 'evento') {
// evento,materia,id,tipo_ev,fecha,aula,link,notas
if (parts.length >= 5) {
evs.push({
materiaCodigo: parts[1],
id: parts[2],
tipo: parts[3] as any,
fecha: parts[4],
aula: parts[5] || '',
link: parts[6] || '',
notas: (parts[7] || '').replace(/;/g, ',')
});
}
}
}
return favs.length > 0 ? favs : null;
return { favoritos: favs, eventos: evs };
} catch (e) {
return null;
}
}
async importFavoritesFromFilePicker(): Promise<string[] | null> {
try {
const result = await FilePicker.pickFiles({
@@ -105,18 +137,25 @@ export class CsvStorageService {
for (let i = 1; i < lines.length; i++) {
const line = lines[i].trim();
if (line.startsWith('favorito,')) {
const parts = line.split(',');
if (!line) continue;
const parts = line.split(',');
const tipo = parts[0];
if (tipo === 'favorito') {
if (parts.length > 1 && parts[1]) {
favs.push(parts[1]);
}
}
// Nota: para el Picker manual solo recuperamos favoritos por ahora para simplicidad,
// o podríamos reusar la lógica de loadUserDataFromCsv si el CSV es idéntico.
}
if (favs.length > 0) {
await this.saveFavoritesToCsv(favs);
await this.saveUserDataToCsv(favs, []);
return favs;
}
return null;
} catch(e) {
console.warn('File picker cancelado o falló', e);