Files
pluriwave/lib/servicios/servicio_favoritos.dart
T
FreeTLab c707fc9911
Build & Deploy Pluriwave / Análisis de código (push) Failing after 21s
Build & Deploy Pluriwave / Build APK + AAB release (push) Has been skipped
feat(ui): add premium PluriWave redesign
2026-05-20 18:42:22 +02:00

143 lines
4.3 KiB
Dart

import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import '../modelos/emisora.dart';
/// Servicio de persistencia de emisoras favoritas con SQLite.
///
/// - Inicialización lazy: la BD se abre en el primer acceso.
/// - Migration-ready: versión 2 añade campos de la Radio Browser API.
class ServicioFavoritos {
static const _dbName = 'pluriwave.db';
static const _dbVersion = 2;
Database? _db;
Future<Database> get _database async {
_db ??= await _initDb();
return _db!;
}
Future<Database> _initDb() async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, _dbName);
return openDatabase(
path,
version: _dbVersion,
onCreate: _onCreate,
onUpgrade: _onUpgrade,
);
}
Future<void> _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE favoritos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uuid TEXT NOT NULL UNIQUE,
nombre TEXT NOT NULL,
url TEXT NOT NULL,
favicon TEXT,
pais TEXT,
codigo_pais TEXT,
idioma TEXT,
tags TEXT,
codec TEXT,
bitrate INTEGER,
votes INTEGER NOT NULL DEFAULT 0,
clickcount INTEGER NOT NULL DEFAULT 0,
orden INTEGER NOT NULL DEFAULT 0
)
''');
}
Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
if (oldVersion < 2) {
// v1→v2: añadir columnas de la Radio Browser API
await db.execute('ALTER TABLE favoritos ADD COLUMN codigo_pais TEXT');
await db.execute('ALTER TABLE favoritos ADD COLUMN codec TEXT');
await db.execute('ALTER TABLE favoritos ADD COLUMN bitrate INTEGER');
await db.execute('ALTER TABLE favoritos ADD COLUMN votes INTEGER NOT NULL DEFAULT 0');
await db.execute('ALTER TABLE favoritos ADD COLUMN clickcount INTEGER NOT NULL DEFAULT 0');
}
}
/// Devuelve todas las emisoras favoritas ordenadas por [orden].
Future<List<Emisora>> obtenerTodos() async {
final db = await _database;
final rows = await db.query('favoritos', orderBy: 'orden ASC');
return rows.map(Emisora.fromMap).toList();
}
/// Añade una emisora a favoritos. Si ya existe (mismo uuid), la actualiza.
Future<void> agregar(Emisora emisora) async {
final db = await _database;
// Calcular el siguiente orden
final maxOrden = Sqflite.firstIntValue(
await db.rawQuery('SELECT MAX(orden) FROM favoritos'),
) ??
-1;
final nuevaEmisora = emisora.copyWith(orden: maxOrden + 1);
await db.insert(
'favoritos',
nuevaEmisora.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
/// Elimina una emisora de favoritos por [uuid].
Future<void> eliminar(String uuid) async {
final db = await _database;
await db.delete('favoritos', where: 'uuid = ?', whereArgs: [uuid]);
}
/// Devuelve true si la emisora con [uuid] está en favoritos.
Future<bool> esFavorito(String uuid) async {
final db = await _database;
final count = Sqflite.firstIntValue(
await db.rawQuery(
'SELECT COUNT(*) FROM favoritos WHERE uuid = ?',
[uuid],
),
);
return (count ?? 0) > 0;
}
/// Alterna el estado de favorito de una emisora.
Future<bool> toggleFavorito(Emisora emisora) async {
if (await esFavorito(emisora.uuid)) {
await eliminar(emisora.uuid);
return false;
} else {
await agregar(emisora);
return true;
}
}
/// Actualiza el orden de un favorito.
Future<void> reordenar(String uuid, int nuevoOrden) async {
final db = await _database;
await db.transaction((txn) async {
final rows = await txn.query(
'favoritos',
columns: ['uuid'],
orderBy: 'orden ASC, id ASC',
);
final uuids = rows.map((r) => r['uuid'] as String).toList();
final oldIndex = uuids.indexOf(uuid);
if (oldIndex == -1 || uuids.isEmpty) return;
final targetIndex = nuevoOrden.clamp(0, uuids.length - 1);
final moved = uuids.removeAt(oldIndex);
uuids.insert(targetIndex, moved);
for (var i = 0; i < uuids.length; i++) {
await txn.update(
'favoritos',
{'orden': i},
where: 'uuid = ?',
whereArgs: [uuids[i]],
);
}
});
}
}