Some checks failed
Flutter CI/CD — PluriWave / Test + Build (pull_request) Has been cancelled
- Modelo Emisora: campos completos Radio Browser API (fromApi + fromMap) - ServicioRadio: cliente Radio Browser API (populares, tendencias, buscar por nombre/país/idioma/tag) - ServicioAudio: just_audio + audio_service wrapper (play/pause/stop/toggle, fade, background handler) - ServicioTimer: countdown con fade out gradual (15/30/60/90 min) - ServicioFavoritos: actualizado a v2 con campos codec/bitrate/votes/clickcount - EstadoRadio: ChangeNotifier global con Provider - PantallaInicio: grid emisoras populares, chips género, shimmer loading, pull-to-refresh - PantallaBuscar: SearchBar + filtros país/idioma, lista resultados - PantallaFavoritos: ReorderableListView + swipe-to-delete (Dismissible) - TarjetaEmisora: card + modo compacto ListTile, cached_network_image, shimmer fallback - MiniReproductor: barra inferior persistente con stream de estado - app.dart: MaterialApp + Provider + NavigationBar + timer dialog - main.dart: punto de entrada limpio - AndroidManifest.xml: permisos INTERNET + FOREGROUND_SERVICE + audio_service receivers
126 lines
3.8 KiB
Dart
126 lines
3.8 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.update(
|
|
'favoritos',
|
|
{'orden': nuevoOrden},
|
|
where: 'uuid = ?',
|
|
whereArgs: [uuid],
|
|
);
|
|
}
|
|
}
|