Commit 9ad69105 by Diego Pérez Peña

Merge desde especificacionFormatos

parents 9e26fc90 07ea6d37
...@@ -4,20 +4,17 @@ import 'package:prueba_multimedia/modelo/conversor.dart'; ...@@ -4,20 +4,17 @@ import 'package:prueba_multimedia/modelo/conversor.dart';
import 'convertible.dart'; import 'convertible.dart';
import 'formato.dart'; import 'formato.dart';
// TODO: QUE PASA SI NO RECONOCEMOS EL FORMATO?
// TODO: MIRAR DE CREAR UN MIXIN TIPO ELEMENTOLOCAL O ALGO ASÍ (Archivo y Carpeta)
class Archivo extends Convertible { class Archivo extends Convertible {
final File file; final File file;
late final Future<List<Metadato>> metadatos; late final Future<List<Metadato>> metadatos;
Archivo({required super.id, required this.file}): Archivo({required super.id, required this.file}):
super( super(
nombre: file.path.split('/').last, nombre: file.path.split('/').last,
// TODO: POR AHORA USAMOS (!) PERO HAY QUE TENERLO EN CUENTA
formatoOriginal: Formato.fromExtension(file.path.split('.').last)!, formatoOriginal: Formato.fromExtension(file.path.split('.').last)!,
icon: Formato.fromExtension(file.path.split('.').last)!.tipoMultimedia.icono icon: Formato.fromExtension(file.path.split('.').last)!.tipoMultimedia.icono
) )
{ {
metadatos = Conversor.getMetadatos(this); metadatos = Conversor.getMetadatos(this);
} }
} }
\ No newline at end of file
...@@ -8,40 +8,46 @@ import 'formato.dart'; ...@@ -8,40 +8,46 @@ import 'formato.dart';
class Carpeta extends ElementoSeleccionable { class Carpeta extends ElementoSeleccionable {
final Directory _directory; final Directory _directory;
bool _incluirSubcarpetas = false; bool _incluirSubcarpetas = false;
// bool _open = false;
final List<InfoFormato> _formatos = <InfoFormato>[]; final List<InfoFormato> _formatos = <InfoFormato>[];
final _elementos = <FileSystemEntity>[]; final _elementos = <FileSystemEntity>[];
Directory get directory => _directory; Directory get directory => _directory;
List<InfoFormato> get formatos => List.unmodifiable(_formatos); List<InfoFormato> get formatos => List.unmodifiable(_formatos);
List<FileSystemEntity> get elementos => List.unmodifiable(_elementos); List<FileSystemEntity> get elementos => List.unmodifiable(_elementos);
// bool get isOpen => _open;
bool get incluyeSubcarpetas => _incluirSubcarpetas; bool get incluyeSubcarpetas => _incluirSubcarpetas;
Carpeta({required super.id, required Directory directory}): Carpeta({required super.id, required Directory directory}):
_directory = directory, _directory = directory,
super(nombre: directory.path.split('/').last, icon: const Icon(Icons.folder_outlined)) super(nombre: directory.path.split('/').last, icon: const Icon(Icons.folder_outlined))
{ {
final elementos = directory.listSync(recursive: _incluirSubcarpetas, followLinks: false); final archivos = directory.listSync(recursive: false, followLinks: false);
// Ahora mismo no funciona por tema permisos pero Diego está trabajando en ello for(var a in archivos) {
for(var fse in elementos) { Formato? f = Formato.fromExtension(a.path.split(".").last);
Formato? f = Formato.fromExtension(fse.path.split(".").last); if(f != null){
if (f != null) { final i = InfoFormato(
/* formato: f,
Creo que podríamos usar mejor _elementos que _formatos
para la construcción de las CarpetaWidget, pero no voy a
quitar _formatos para que la pagina de configuración de la
carpeta siga funcionando
*/
_formatos.add(
InfoFormato (
carpeta: this, carpeta: this,
subCarpeta: false);
if(!_formatos.contains(i)){
_formatos.add(i);
}
}
}
final subcarpeta = directory.listSync(recursive: true, followLinks: false);
for(var a in subcarpeta) {
Formato? f = Formato.fromExtension(a.path.split(".").last);
if(f != null){
final i = InfoFormato(
formato: f, formato: f,
) carpeta: this,
); subCarpeta: true);
_elementos.add(fse); if(!_formatos.contains(i)){
_formatos.add(i);
}
} }
} }
} }
/* /*
...@@ -59,25 +65,16 @@ class Carpeta extends ElementoSeleccionable { ...@@ -59,25 +65,16 @@ class Carpeta extends ElementoSeleccionable {
return null; return null;
} }
void setFormatoDestino(Formato original, Formato? destino){ void setFormatoDestino(Formato original, Formato? destino, Calidad? calidad){
final formatosAlt = formatos.toList(); final formatosAlt = formatos.toList();
for(InfoFormato i in formatosAlt){ for(InfoFormato i in formatosAlt){
if(i.formatoOriginal == original){ if(i.formatoOriginal == original){
i.formatoDestino = destino; i.formatoDestino = destino;
i.calidadSalida = calidad;
} }
} }
}
/*
Esto estaba siendo llamado para guardar que una carpeta había sido abierta
en la página principal para mostrar los archivos y subcarpetas y etc...
Aunque esto lo podriamos tener guerdado solo en el widget correspondiente
void pressOpenClose(){
_open = !_open;
} }
*/
void pressIncluirSubcarpetas(){ void pressIncluirSubcarpetas(){
_incluirSubcarpetas = !_incluirSubcarpetas; _incluirSubcarpetas = !_incluirSubcarpetas;
...@@ -93,11 +90,12 @@ class Carpeta extends ElementoSeleccionable { ...@@ -93,11 +90,12 @@ class Carpeta extends ElementoSeleccionable {
class InfoFormato extends Convertible { class InfoFormato extends Convertible {
final Carpeta _carpeta; final Carpeta _carpeta;
bool seleccionado; bool seleccionado;
bool subCarpeta;
Carpeta get carpeta => _carpeta; Carpeta get carpeta => _carpeta;
InfoFormato({required Formato formato, required Carpeta carpeta, InfoFormato({required Formato formato, required Carpeta carpeta,
bool? seleccionado}): bool? seleccionado, required bool this.subCarpeta}):
_carpeta = carpeta, _carpeta = carpeta,
seleccionado = seleccionado ?? false, seleccionado = seleccionado ?? false,
super( super(
......
import 'elemento_seleccionable.dart'; import 'elemento_seleccionable.dart';
import 'formato.dart'; import 'formato.dart';
// TODO: QUE PASA SI NO RECONOCEMOS EL FORMATO?
class Convertible extends ElementoSeleccionable{ class Convertible extends ElementoSeleccionable{
final Formato _formatoOriginal; final Formato _formatoOriginal;
Formato? formatoDestino; Formato? formatoDestino;
Calidad? calidadSalida;
Formato get formatoOriginal => _formatoOriginal; Formato get formatoOriginal => _formatoOriginal;
Convertible({required super.id, required super.nombre, required super.icon, Convertible({required super.id, required super.nombre, required super.icon,
required Formato formatoOriginal, this.formatoDestino}): required Formato formatoOriginal}):
_formatoOriginal = formatoOriginal; _formatoOriginal = formatoOriginal;
@override @override
......
...@@ -2,74 +2,75 @@ import 'package:flutter/material.dart'; ...@@ -2,74 +2,75 @@ import 'package:flutter/material.dart';
// TODO: AÑADIR CALIDAD // TODO: AÑADIR CALIDAD
enum Formato { enum Formato {
png('Portable Network Graphics', TipoMultimedia.imagen, Clasificacion.calidad, [], png(['png'], [], 'Portable Network Graphics', TipoMultimedia.imagen, Clasificacion.calidad, [],
'ClaseFormato gráfico basado en un algoritmo de compresión sin pérdida para bitmaps no sujeto a patentes. Fue desarrollado en buena parte para solventar las deficiencias del formato GIF y permite almacenar imágenes con una mayor profundidad de contraste y otros datos importantes.' 'ClaseFormato gráfico basado en un algoritmo de compresión sin pérdida para bitmaps no sujeto a patentes. Fue desarrollado en buena parte para solventar las deficiencias del formato GIF y permite almacenar imágenes con una mayor profundidad de contraste y otros datos importantes.'
), ),
jpg('Joint Photographic Experts Group', TipoMultimedia.imagen, Clasificacion.ligero, [], jpg(['jpeg','jpg','jpe'], Calidad.values, 'Joint Photographic Experts Group', TipoMultimedia.imagen, Clasificacion.ligero, [],
'A pesar de ser un método de compresión, es a menudo considerado como un formato de archivo. Es el formato de imagen más común, utilizado por las cámaras fotográficas digitales y otros dispositivos de captura de imagen' 'A pesar de ser un método de compresión, es a menudo considerado como un formato de archivo. Es el formato de imagen más común, utilizado por las cámaras fotográficas digitales y otros dispositivos de captura de imagen'
), ),
jpeg('Joint Photographic Experts Group', TipoMultimedia.imagen, Clasificacion.ligero, [], tif(['tif','tiff'], [], 'Tagged Image File Format', TipoMultimedia.imagen, Clasificacion.calidad, [],
'A pesar de ser un método de compresión, es a menudo considerado como un formato de archivo. Es el formato de imagen más común, utilizado por las cámaras fotográficas digitales y otros dispositivos de captura de imagen' 'Un formato de archivo informático para almacenar imágenes de mapa de bits. Es prevalente en la industria gráfica y en la fotografía profesional por su versatilidad y compresión no destructiva.'
), ),
tif('Tagged Image File Format', TipoMultimedia.imagen, Clasificacion.calidad, [], webp(['webp'], Calidad.values, 'Web Picture', TipoMultimedia.imagen, Clasificacion.versatil, [],
'Un formato de archivo informático para almacenar imágenes de mapa de bits. Es prevalente en la industria gráfica y en la fotografía profesional por su versatilidad y compresión no destructiva.' 'Formato desarrollado por Google, basándose en tecnología de On2 Technologies. Es un formato gráfico en forma de contenedor, que sustenta tanto compresión con pérdida como sin ella.'
), ),
mp3('MPEG-1 Layer III', TipoMultimedia.audio, Clasificacion.calidad, mp3(['mp3'], [], 'MPEG-1 Layer III', TipoMultimedia.audio, Clasificacion.calidad,
[ MetadatoInfo.title, MetadatoInfo.artist, MetadatoInfo.album, MetadatoInfo.genre, [ MetadatoInfo.title, MetadatoInfo.artist, MetadatoInfo.album, MetadatoInfo.genre,
MetadatoInfo.composer, MetadatoInfo.track, MetadatoInfo.language], MetadatoInfo.composer, MetadatoInfo.track, MetadatoInfo.language],
'Un formato de compresión de audio digital que usa un algoritmo con pérdida para conseguir un menor tamaño de archivo. Es un formato de audio común utilizado para música tanto en computadoras como en reproductores de audio portátil.' 'Un formato de compresión de audio digital que usa un algoritmo con pérdida para conseguir un menor tamaño de archivo. Es un formato de audio común utilizado para música tanto en computadoras como en reproductores de audio portátil.'
), ),
ogg('Xiph.org Ogg', TipoMultimedia.audio, Clasificacion.versatil, [], oga(['oga','opus'], [], 'Xiph.org Ogg Vorbis', TipoMultimedia.audio, Clasificacion.versatil, [],
'Un formato contenedor libre y abierto, desarrollado y mantenido por la Fundación Xiph.Org que no está restringido por las patentes de software, y está diseñado para proporcionar una difusión de flujo eficiente y manipulación de multimedios digitales de alta calidad.' 'Un formato contenedor libre y abierto, desarrollado y mantenido por la Fundación Xiph.Org que no está restringido por las patentes de software, y está diseñado para proporcionar una difusión de flujo eficiente y manipulación de multimedios digitales de alta calidad.'
), ),
wav('Waveform Audio File Format', TipoMultimedia.audio, Clasificacion.calidad, [], wav(['wav','wave'], [], 'Waveform Audio File Format', TipoMultimedia.audio, Clasificacion.calidad, [],
'Un formato de audio digital con o sin compresión de datos desarrollado por Microsoft e IBM que se utiliza para almacenar flujos digitales de audio en el PC, mono y estéreo a diversas resoluciones y velocidades de muestreo.' 'Un formato de audio digital con o sin compresión de datos desarrollado por Microsoft e IBM que se utiliza para almacenar flujos digitales de audio en el PC, mono y estéreo a diversas resoluciones y velocidades de muestreo.'
), ),
mp4('MPEG-4 Parte 14', TipoMultimedia.video, Clasificacion.calidad, flac(['flac'], [], 'Free Lossless Audio Codec', TipoMultimedia.audio, Clasificacion.calidad, [],
'Es un formato abierto con licencia libre de derechos de autor y una implementación de referencia la cual es software libre. FLAC cuenta con soporte para etiquetado de metadatos, inclusión de la portada del álbum, y la búsqueda rápida.'
),
mp4(['mp4','m4a','m4p','m4v','m4b','m4r'], [], 'MPEG-4 Parte 14', TipoMultimedia.video, Clasificacion.versatil,
[ MetadatoInfo.title, MetadatoInfo.author, MetadatoInfo.album, MetadatoInfo.year, [ MetadatoInfo.title, MetadatoInfo.author, MetadatoInfo.album, MetadatoInfo.year,
MetadatoInfo.genre, MetadatoInfo.composer, MetadatoInfo.track, MetadatoInfo.genre, MetadatoInfo.composer, MetadatoInfo.track,
MetadatoInfo.description, MetadatoInfo.comment], MetadatoInfo.description, MetadatoInfo.comment],
'Un formato contenedor especificado como parte del estándar internacional MPEG-4 de ISO/IEC. Es utilizado para almacenar los formatos audiovisuales especificados por ISO/IEC y el grupo MPEG (Moving Picture Experts Group) al igual que otros formatos audiovisuales disponibles.' 'Un formato contenedor especificado como parte del estándar internacional MPEG-4 de ISO/IEC. Es utilizado para almacenar los formatos audiovisuales especificados por ISO/IEC y el grupo MPEG (Moving Picture Experts Group) al igual que otros formatos audiovisuales disponibles.'
), ),
mkv('Matroshka', TipoMultimedia.video, Clasificacion.calidad, mkv(['mkv','mk3d','mka','mks'], [], 'Matroshka', TipoMultimedia.video, Clasificacion.calidad,
[ MetadatoInfo.title, MetadatoInfo.description, MetadatoInfo.language ], [ MetadatoInfo.title, MetadatoInfo.description, MetadatoInfo.language ],
'Un formato contenedor abierto que puede almacenar una cantidad muy grande de vídeo, audio, imagen o pistas de subtítulos dentro de un solo archivo. Su finalidad es la de servir como formato universal para el almacenamiento de contenidos audiovisuales y multimedia, como películas o programas de televisión, imágenes y textos.' 'Un formato contenedor abierto que puede almacenar una cantidad muy grande de vídeo, audio, imagen o pistas de subtítulos dentro de un solo archivo. Su finalidad es la de servir como formato universal para el almacenamiento de contenidos audiovisuales y multimedia, como películas o programas de televisión, imágenes y textos.'
), ),
wmv('Windows Media Video', TipoMultimedia.video, Clasificacion.calidad, ogv(['ogv', 'ogm'], [], 'Xiph.org Ogg Theora', TipoMultimedia.video, Clasificacion.ligero, [],
[ MetadatoInfo.title, MetadatoInfo.author, MetadatoInfo.rating, MetadatoInfo.comment ], 'Un códec de vídeo libre que está siendo desarrollado por la Fundación Xiph.Org, como parte de su proyecto Ogg. Basado en el códec VP3 donado por On2 Technologies, Xiph.Org lo ha refinado y extendido dándole el mismo alcance futuro para mejoras en el codificador como el que posee el códec de audio Vorbis.'
'Un formato de vídeo desarrollado por Microsoft, que forma parte del framework Windows Media. No está contruida solo con tecnología interna de Microsoft. Desde la versión 7 (WMV1), Microsoft ha utilizado su propia versión no estandarizada de MPEG-4. El vídeo a menudo se combina con sonido en formato Windows Media Audio.'
); );
final String _nombreCompleto; final List<String> listExtensiones;
final TipoMultimedia _tipoMultimedia; final List<Calidad> listCalidades;
final Clasificacion _clasificacion; final String nombre;
final List<MetadatoInfo> _metadatos; final TipoMultimedia tipoMultimedia;
final String _descripcion; final Clasificacion clasificacion;
final List<MetadatoInfo> metadatos;
final String descripcion;
String get extension => name; String get extension => name;
String get nombre => _nombreCompleto;
Clasificacion get clasificacion => _clasificacion;
TipoMultimedia get tipoMultimedia => _tipoMultimedia;
List<MetadatoInfo> get metadatos => _metadatos;
String get descripcion => _descripcion;
const Formato(this._nombreCompleto, this._tipoMultimedia, this._clasificacion,
this._metadatos, this._descripcion); const Formato(this.listExtensiones, this.listCalidades, this.nombre,
this.tipoMultimedia, this.clasificacion, this.metadatos, this.descripcion);
/// Devuelve aquellos formatos de TipoMultimedia que no sean excepcion /// Devuelve aquellos formatos de TipoMultimedia que no sean excepcion
static List<Formato> listadoFormatos({required TipoMultimedia tipo, Formato? excepcion}){ static List<Formato> listadoFormatos({required TipoMultimedia tipo, Formato? excepcion}){
final toRet = <Formato>[]; final toRet = <Formato>[];
for(var formato in Formato.values){ for(var formato in Formato.values){
if(formato._tipoMultimedia == tipo && formato != excepcion) { if(formato.tipoMultimedia == tipo && formato != excepcion) {
toRet.add(formato); toRet.add(formato);
} }
} }
...@@ -78,9 +79,16 @@ enum Formato { ...@@ -78,9 +79,16 @@ enum Formato {
/// Si la extensión no es valida devuelve nulo /// Si la extensión no es valida devuelve nulo
static Formato? fromExtension(String extension){ static Formato? fromExtension(String extension){
// COMPROBAR SI UN ARCHIVO OGG CONTIENE VÍDEO O SOLO AUDIO
// ffprobe -v error -select_streams v:0 -show_entries stream=codec_type -of csv=p=0 [ARCHIVO].ogg
// Outputs either video or no output at all.
// https://stackoverflow.com/questions/56397732/how-can-i-know-a-certain-file-is-a-video-file
for(Formato f in Formato.values) { for(Formato f in Formato.values) {
if(f.name == extension){ for(String ext in f.listExtensiones){
return f; if(ext == extension){
return f;
}
} }
} }
return null; return null;
...@@ -98,10 +106,14 @@ enum TipoMultimedia { ...@@ -98,10 +106,14 @@ enum TipoMultimedia {
} }
enum Clasificacion { enum Clasificacion {
calidad("Calidad"), ligero("Ligero"), versatil("Versátil"); calidad("Calidad", Icons.high_quality_outlined),
ligero("Ligero", Icons.electric_bolt_outlined),
versatil("Versátil", Icons.auto_mode_outlined);
final String nombre; final String nombre;
const Clasificacion(this.nombre); final IconData icono;
const Clasificacion(this.nombre, this.icono);
} }
enum Calidad { enum Calidad {
......
...@@ -4,6 +4,7 @@ import 'package:uuid/uuid.dart'; ...@@ -4,6 +4,7 @@ import 'package:uuid/uuid.dart';
import 'carpeta.dart'; import 'carpeta.dart';
import 'elemento_seleccionable.dart'; import 'elemento_seleccionable.dart';
import 'archivo.dart'; import 'archivo.dart';
import 'formato.dart';
class ListaSeleccionables extends ChangeNotifier { class ListaSeleccionables extends ChangeNotifier {
final _seleccionables = <ElementoSeleccionable>[]; final _seleccionables = <ElementoSeleccionable>[];
...@@ -19,18 +20,23 @@ class ListaSeleccionables extends ChangeNotifier { ...@@ -19,18 +20,23 @@ class ListaSeleccionables extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void addArchivo(File file) { bool addArchivo(File file) {
_seleccionables.add(Archivo(id: const Uuid().v1(), if(Formato.fromExtension(file.path.split('.').last) != null){
file: file)); _seleccionables.add(Archivo(id: const Uuid().v1(),
notifyListeners(); file: file));
notifyListeners();
return true;
}
return false;
} }
void addCarpeta(Directory directory){ bool addCarpeta(Directory directory){
final newCarpeta = Carpeta( final newCarpeta = Carpeta(
id: const Uuid().v1(), id: const Uuid().v1(),
directory: directory directory: directory
); );
//if(newCarpeta.formatos.isNotEmpty){
if(newCarpeta.formatos.isNotEmpty){
_seleccionables.add( _seleccionables.add(
Carpeta( Carpeta(
id: const Uuid().v1(), id: const Uuid().v1(),
...@@ -38,7 +44,10 @@ class ListaSeleccionables extends ChangeNotifier { ...@@ -38,7 +44,10 @@ class ListaSeleccionables extends ChangeNotifier {
) )
); );
notifyListeners(); notifyListeners();
//} return true;
}
return false;
} }
void reinsertar(int index, ElementoSeleccionable element){ void reinsertar(int index, ElementoSeleccionable element){
......
...@@ -28,31 +28,31 @@ class _PaginaConfiguracionState extends State<PaginaConfiguracion> { ...@@ -28,31 +28,31 @@ class _PaginaConfiguracionState extends State<PaginaConfiguracion> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: RichText( title: RichText(
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
text: TextSpan( text: TextSpan(
children: [ children: [
WidgetSpan( WidgetSpan(
child: widget._elementoAsociado.icono child: widget._elementoAsociado.icono
), ),
TextSpan( TextSpan(
text: " ${widget._elementoAsociado.nombre}", text: " ${widget._elementoAsociado.nombre}",
style: Theme.of(context).textTheme.titleLarge, style: Theme.of(context).textTheme.titleLarge,
) )
] ]
) )
),
), ),
), body: _construirCuerpo(),
body: _construirCuerpo(), bottomNavigationBar: widget._elementoAsociado is Archivo
bottomNavigationBar: widget._elementoAsociado is Archivo ? BottomNavigationBar(
? BottomNavigationBar( currentIndex: _categoriaActiva,
currentIndex: _categoriaActiva, onTap: (int indice) => setState(() { _categoriaActiva = indice; }),
onTap: (int indice) => setState(() { _categoriaActiva = indice; }), items: _construirElementosBarraNavegacion()
items: _construirElementosBarraNavegacion() )
) : null
: null
); );
} }
...@@ -135,3 +135,4 @@ class _PaginaConfiguracionState extends State<PaginaConfiguracion> { ...@@ -135,3 +135,4 @@ class _PaginaConfiguracionState extends State<PaginaConfiguracion> {
} }
} }
...@@ -54,9 +54,11 @@ class _PaginaConversionState extends State<PaginaConversion> ...@@ -54,9 +54,11 @@ class _PaginaConversionState extends State<PaginaConversion>
_tabController = TabController(length: 3, vsync: this); _tabController = TabController(length: 3, vsync: this);
if(widget._carpeta != null){ if(widget._carpeta != null){
_formatoConvertido = widget._infoFormato!.formatoDestino; _formatoConvertido = widget._infoFormato!.formatoDestino;
_calidadActual = widget._infoFormato!.calidadSalida;
} }
else{ else{
_formatoConvertido = widget._archivo!.formatoDestino; _formatoConvertido = widget._archivo!.formatoDestino;
_calidadActual = widget._archivo!.calidadSalida;
} }
} }
...@@ -139,8 +141,8 @@ class _PaginaConversionState extends State<PaginaConversion> ...@@ -139,8 +141,8 @@ class _PaginaConversionState extends State<PaginaConversion>
shape: StadiumBorder(), shape: StadiumBorder(),
label: Text(elemento.texto), label: Text(elemento.texto),
// TODO: CAMBIAR CALIDAD FORMATO // TODO: CAMBIAR CALIDAD FORMATO
onSelected: (_formatoConvertido == null)? null: onSelected: (_formatoConvertido != null && _formatoConvertido!.listCalidades.contains(elemento))?
(selected) { setState((){_calidadActual = elemento;}); }, (selected) { setState((){_calidadActual = elemento;}); } : null,
); );
}).toList(); }).toList();
...@@ -406,13 +408,43 @@ class _PaginaConversionState extends State<PaginaConversion> ...@@ -406,13 +408,43 @@ class _PaginaConversionState extends State<PaginaConversion>
_formatoConvertido = _calidadActual = null; _formatoConvertido = _calidadActual = null;
_cambiarFormatoCalidad(null, null); _cambiarFormatoCalidad(null, null);
}); });
} : () => _cambiarFormatoCalidad(elemento, Calidad.media), } : () {
Calidad? qual = null;
if(elemento.listCalidades.isNotEmpty){
if(elemento.listCalidades.contains(Calidad.media)) {
qual = Calidad.media;
} else {
qual = elemento.listCalidades.first;
}
}
_cambiarFormatoCalidad(elemento, qual);
},
onLongPress: () { onLongPress: () {
showDialog<void>( showDialog<void>(
context: context, context: context,
builder: (context) { builder: (context) {
return AlertDialog( return AlertDialog(
content: Text(elemento.descripcion), title: Text(
elemento.nombre,
textAlign: TextAlign.center,
),
content: SizedBox(
child: Wrap(
children: [
Text(
'Clasificación: ${elemento.clasificacion.nombre}',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.bold
),
),
Text('\n'),
Text(
elemento.descripcion,
style: Theme.of(context).textTheme.bodyLarge,
)
],
),
),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
...@@ -439,9 +471,12 @@ class _PaginaConversionState extends State<PaginaConversion> ...@@ -439,9 +471,12 @@ class _PaginaConversionState extends State<PaginaConversion>
style: Theme.of(context).textTheme.titleLarge, style: Theme.of(context).textTheme.titleLarge,
textScaler: TextScaler.linear(1.5), textScaler: TextScaler.linear(1.5),
), ),
const SizedBox( SizedBox(
height: 15.0, height: 15.0,
child: Icon(Icons.airplanemode_active), child: Icon(
elemento.clasificacion.icono,
size: (elemento.clasificacion == Clasificacion.calidad)? 32.0 : 28.0,
),
) )
], ],
) )
...@@ -459,11 +494,12 @@ class _PaginaConversionState extends State<PaginaConversion> ...@@ -459,11 +494,12 @@ class _PaginaConversionState extends State<PaginaConversion>
ElementoSeleccionable resultado; ElementoSeleccionable resultado;
if(widget._carpeta != null){ if(widget._carpeta != null){
widget._carpeta!.setFormatoDestino(widget._formatoOriginal, _formatoConvertido); widget._carpeta!.setFormatoDestino(widget._formatoOriginal, _formatoConvertido, _calidadActual);
resultado = widget._carpeta!; resultado = widget._carpeta!;
} }
else{ else{
widget._archivo!.formatoDestino = _formatoConvertido; widget._archivo!.formatoDestino = _formatoConvertido;
widget._archivo!.calidadSalida = _calidadActual;
resultado = widget._archivo!; resultado = widget._archivo!;
} }
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter/ffmpeg_session.dart';
import 'package:ffmpeg_kit_flutter/return_code.dart';
class PaginaPrincipalVacia extends StatelessWidget { class PaginaPrincipalVacia extends StatelessWidget {
const PaginaPrincipalVacia({super.key}); const PaginaPrincipalVacia({super.key});
...@@ -19,7 +22,7 @@ class PaginaPrincipalVacia extends StatelessWidget { ...@@ -19,7 +22,7 @@ class PaginaPrincipalVacia extends StatelessWidget {
Text( Text(
'Pulsa el botón + para agregarlos', 'Pulsa el botón + para agregarlos',
style: Theme.of(context).textTheme.bodyLarge, style: Theme.of(context).textTheme.bodyLarge,
) ),
], ],
), ),
) )
......
...@@ -8,8 +8,10 @@ class ActionButton extends StatelessWidget { ...@@ -8,8 +8,10 @@ class ActionButton extends StatelessWidget {
final ActionButtonTypes tipoBoton; final ActionButtonTypes tipoBoton;
final ListaSeleccionables manager; final ListaSeleccionables manager;
final BuildContext context; final BuildContext context;
final VoidCallback? onSuccess;
const ActionButton({super.key, required this.tipoBoton, const ActionButton({super.key, required this.tipoBoton,
required this.manager, required this.context}); required this.manager, required this.context, this.onSuccess});
void Function() getCallback() { void Function() getCallback() {
return switch(tipoBoton) { return switch(tipoBoton) {
...@@ -41,14 +43,23 @@ class ActionButton extends StatelessWidget { ...@@ -41,14 +43,23 @@ class ActionButton extends StatelessWidget {
FilePickerResult? result = await FilePicker.platform.pickFiles(); FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result != null) { if (result != null) {
File file = File(result.files.first.path!); File file = File(result.files.first.path!);
manager.addArchivo(file); final res = manager.addArchivo(file);
if(res){
if(context.mounted && onSuccess != null){
onSuccess!();
}
}
else{
if (context.mounted) {
_mostrarSnackBar('El archivo seleccionado no es de un formato multimedia conocido');
}
}
} // Mensaje indicando que se seleccione un archivo } // Mensaje indicando que se seleccione un archivo
else { else {
// Comprobar que el widget no ha sido destruido por ser asíncrono // Comprobar que el widget no ha sido destruido por ser asíncrono
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( _mostrarSnackBar('No se ha seleccionado ningún archivo');
SnackBar(content: Text("Selecciona una archivo"))
);
} }
} }
} }
...@@ -76,14 +87,22 @@ class ActionButton extends StatelessWidget { ...@@ -76,14 +87,22 @@ class ActionButton extends StatelessWidget {
FilePicker.platform.getDirectoryPath().then( (path) { FilePicker.platform.getDirectoryPath().then( (path) {
if (path != null) { if (path != null) {
var directory = Directory(path); var directory = Directory(path);
manager.addCarpeta(directory); final res = manager.addCarpeta(directory);
if(res){
if(context.mounted && onSuccess != null){
onSuccess!();
}
}
else{
if (context.mounted) {
_mostrarSnackBar('La carpeta seleccionada no contiene archivos de formatos multimedia conoocidos');
}
}
} // Mensaje indicando que se seleccione una carpeta } // Mensaje indicando que se seleccione una carpeta
else { else {
// Comprobar que el widget no ha sido destruido por ser asíncrono // Comprobar que el widget no ha sido destruido por ser asíncrono
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( _mostrarSnackBar('No se ha seleccionado ninguna carpeta');
SnackBar(content: Text("Selecciona una carpeta"))
);
} }
} }
}); });
...@@ -143,6 +162,13 @@ class ActionButton extends StatelessWidget { ...@@ -143,6 +162,13 @@ class ActionButton extends StatelessWidget {
); );
} }
void _mostrarSnackBar(String text) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
text
)
));
}
} }
enum ActionButtonTypes { enum ActionButtonTypes {
......
...@@ -139,8 +139,17 @@ class _ConVertexFabBarState extends State<ConVertexFabBar> { ...@@ -139,8 +139,17 @@ class _ConVertexFabBarState extends State<ConVertexFabBar> {
List<Widget> _loadAgregarActionButtons(BuildContext context, List<Widget> _loadAgregarActionButtons(BuildContext context,
ListaSeleccionables manager) ListaSeleccionables manager)
{ {
final VoidCallback closeButtons = () {
setState(() {
_convertirOpen = false;
_agregarOpen = false;
});
_convertirKey.currentState?.close();
_agregarKey.currentState?.close();
};
return agregarButtonTypes.map( (type) { return agregarButtonTypes.map( (type) {
return ActionButton(tipoBoton: type, manager: manager, context: context,); return ActionButton(tipoBoton: type, manager: manager, context: context, onSuccess: closeButtons,);
}).toList(); }).toList();
} }
} }
...@@ -7,8 +7,10 @@ import Foundation ...@@ -7,8 +7,10 @@ import Foundation
import ffmpeg_kit_flutter import ffmpeg_kit_flutter
import file_picker import file_picker
import path_provider_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin")) FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
} }
...@@ -216,6 +216,54 @@ packages: ...@@ -216,6 +216,54 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.1" version: "1.9.1"
path_provider:
dependency: "direct main"
description:
name: path_provider
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.dev"
source: hosted
version: "2.1.5"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
url: "https://pub.dev"
source: hosted
version: "2.2.17"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev"
source: hosted
version: "2.3.0"
permission_handler: permission_handler:
dependency: "direct main" dependency: "direct main"
description: description:
...@@ -264,6 +312,14 @@ packages: ...@@ -264,6 +312,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.1" version: "0.2.1"
platform:
dependency: transitive
description:
name: platform
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev"
source: hosted
version: "3.1.6"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
...@@ -389,6 +445,14 @@ packages: ...@@ -389,6 +445,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.10.1" version: "5.10.1"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
sdks: sdks:
dart: ">=3.7.0-0 <4.0.0" dart: ">=3.7.0-0 <4.0.0"
flutter: ">=3.27.0" flutter: ">=3.27.0"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment