feat(grabaciones): add recordings library screen
This commit is contained in:
@@ -3,10 +3,12 @@ import 'dart:io';
|
||||
import 'dart:ui' show Locale;
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../l10n/gen/app_localizations.dart';
|
||||
import '../modelos/archivo_grabacion.dart';
|
||||
import '../modelos/emisora.dart';
|
||||
|
||||
enum EstadoGrabacionRadioTipo {
|
||||
@@ -173,6 +175,66 @@ class ServicioGrabacionRadio {
|
||||
_emitir(_estado);
|
||||
}
|
||||
|
||||
/// Lists the recording files currently on disk in the effective
|
||||
/// directory (WU15, recordings-library spec "Browsable Recordings List").
|
||||
/// Pure filesystem read — no audio decoding, no duration. Never throws: a
|
||||
/// missing directory (never recorded yet) degrades to an empty list, not
|
||||
/// an error, matching the spec's "No recordings (edge case)" scenario.
|
||||
/// Sorted most-recent-first by last-modified time.
|
||||
///
|
||||
/// Uses the SYNC `listSync`/`statSync` filesystem calls deliberately, not
|
||||
/// `Directory.list()`'s async stream — the latter did not resolve inside
|
||||
/// `flutter_test`'s fake-async zone in this sandbox (confirmed: a widget
|
||||
/// test calling through to the stream-based version hung indefinitely,
|
||||
/// while the sync calls resolve immediately), mirroring this project's
|
||||
/// existing `Directory.systemTemp` async-hang precedent for a different
|
||||
/// dart:io API shape.
|
||||
Future<List<ArchivoGrabacion>> listarGrabaciones() async {
|
||||
final ruta = await directorioEfectivo();
|
||||
final directorio = Directory(ruta);
|
||||
if (!directorio.existsSync()) return const [];
|
||||
|
||||
final archivos = <ArchivoGrabacion>[];
|
||||
for (final entidad in directorio.listSync()) {
|
||||
if (entidad is! File) continue;
|
||||
final stat = entidad.statSync();
|
||||
archivos.add(
|
||||
ArchivoGrabacion(
|
||||
ruta: entidad.path,
|
||||
nombre: p.basenameWithoutExtension(entidad.path),
|
||||
fecha: stat.modified,
|
||||
tamanoBytes: stat.size,
|
||||
),
|
||||
);
|
||||
}
|
||||
archivos.sort((a, b) => b.fecha.compareTo(a.fecha));
|
||||
return archivos;
|
||||
}
|
||||
|
||||
/// Deletes the recording at [ruta] (WU15, "Delete removes the file and
|
||||
/// its row"). File-lifecycle management for a file this service already
|
||||
/// created — not a new capability. A missing file is treated as
|
||||
/// already-deleted, never an error.
|
||||
Future<void> eliminarGrabacion(String ruta) async {
|
||||
final archivo = File(ruta);
|
||||
if (await archivo.exists()) {
|
||||
await archivo.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/// Renames the recording at [ruta] to [nuevoNombre], preserving its
|
||||
/// original extension (WU15, "Rename updates the displayed name").
|
||||
/// Returns the new full path.
|
||||
Future<String> renombrarGrabacion(String ruta, String nuevoNombre) async {
|
||||
final original = File(ruta);
|
||||
final nuevaRuta = p.join(
|
||||
p.dirname(ruta),
|
||||
'$nuevoNombre${p.extension(ruta)}',
|
||||
);
|
||||
final renombrado = await original.rename(nuevaRuta);
|
||||
return renombrado.path;
|
||||
}
|
||||
|
||||
Future<void> guardarMaxBytes(int bytes) async {
|
||||
if (bytes <= 0) {
|
||||
throw ArgumentError(_textos.recordingMaxSizeInvalidError);
|
||||
|
||||
Reference in New Issue
Block a user