Commit 2c62c397 by Rafa Castillo Passols

Versión medianamente funcional del proyecto. Los enlaces ya funcionan pero hay…

Versión medianamente funcional del proyecto. Los enlaces ya funcionan pero hay un bug. Falta convertir de video a imagen
parents d2d62b36 a138b91c
import 'dart:io';
import 'package:ffmpeg_kit_flutter_new/return_code.dart';
import 'package:prueba_multimedia/modelo/conversor.dart';
import 'convertible.dart';
......@@ -22,4 +23,9 @@ class Archivo extends Convertible {
{
metadatos = Conversor.getMetadatos(this);
}
@override
Future<ReturnCode?> convertir(String pathSalida) async {
return Conversor.convertir(this, pathSalida);
}
}
import 'dart:io';
import 'package:ffmpeg_kit_flutter_new/return_code.dart';
import 'package:flutter/material.dart';
import 'package:prueba_multimedia/modelo/archivo.dart';
import 'package:uuid/uuid.dart';
......@@ -199,4 +200,9 @@ class InfoFormato extends Convertible {
@override
int get hashCode => Object.hash(formatoOriginal, formatoDestino, calidadSalida, _carpeta, seleccionado, subCarpeta);
@override
Future<ReturnCode?> convertir(String _) {
throw UnimplementedError("Esta función no debería de llamarse nunca");
}
}
\ No newline at end of file
import 'elemento_seleccionable.dart';
import 'formato.dart';
import 'package:ffmpeg_kit_flutter_new/return_code.dart';
/// Clase que representa genéricamente cualquier elemento que se pueda convertir
class Convertible extends ElementoSeleccionable {
abstract class Convertible extends ElementoSeleccionable{
/// Formato original del elemento
final Formato _formatoOriginal;
/// Formato del fichero de salida
......@@ -10,10 +10,11 @@ class Convertible extends ElementoSeleccionable {
/// Calidad del fichero de salida
Calidad? calidadSalida;
/// Devuelve el formato original de este elemento
Formato get formatoOriginal => _formatoOriginal;
Convertible({required super.id, required super.nombre, required super.icon,
required Formato formatoOriginal}):
_formatoOriginal = formatoOriginal;
Future<ReturnCode?> convertir(String pathSalida);
}
\ No newline at end of file
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:ffmpeg_kit_flutter_new/return_code.dart';
import 'package:flutter/material.dart';
import 'convertible.dart';
import 'formato.dart';
import 'package:path_provider/path_provider.dart';
import 'package:uuid/uuid.dart';
import 'package:prueba_multimedia/modelo/modelo.dart';
// TODO: QUE PASA SI NO RECONOCEMOS EL FORMATO?
class Enlace extends Convertible{
final String _direccion;
final RedSocial _redSocial;
List<String> metadatos = [];
class Enlace extends Convertible {
final String _url;
late final Future<File> _file;
bool _descargado = false;
String? _nombreArchivo;
String get url => _url;
String? get nombreArchivo => _nombreArchivo;
bool get descargado => _descargado;
Enlace({required String super.id, required String direccion}):
_direccion = direccion,
_redSocial = RedSocial.FACEBOOK,
super(nombre: direccion.split('/').last,
// TODO: POR AHORA USAMOS (!) PERO HAY QUE TENERLO EN CUENTA
formatoOriginal: Formato.fromExtension('png')!,
icon: Icon(Icons.insert_drive_file_outlined));
_url = direccion, super(
nombre: direccion.length < 33
? direccion
: "${direccion.substring(0, 33)}...",
formatoOriginal: Formato.fromExtension('jpg')!,
icon: const Icon(Icons.link)
)
{
_file = _descargar(_url);
}
Future<File> _descargar(String direccion) async {
// Descargamos los datos
final dio = Dio();
final response = await dio.get(_url,
options: Options(
responseType: ResponseType.bytes
)
);
// Miramos el nombre del archivo en la respuesta o lo generamos aleatoriamente
String? nombre = response.headers.map['Content-Disposition']?.first;
if (nombre == null) {
nombre = const Uuid().v1().toString();
} else {
nombre = nombre.split('=').last;
// filename encoding, quitamos los "..."
if (nombre.startsWith('"')) {
nombre = nombre.substring(1, nombre.length-1);
}
// filename* encoding, habría que parsear en UTF8
// TODO: parsear en el caso de filename*
else {
nombre = nombre.substring(7);
}
}
_nombreArchivo = nombre;
// Escribimos los datos en archivo temporal
Directory temp = await getTemporaryDirectory();
final File file = await File("${temp.path}/$nombre.${formatoOriginal.name}").create();
final raf = file.openSync(mode: FileMode.write);
raf.writeFromSync(response.data);
await raf.close();
_descargado = true;
return file;
}
@override
Future<ReturnCode?> convertir(String pathSalida) async {
// Eliminamos el archivo temporal después de la conversión
Archivo archivo = Archivo(id: id, file: await _file);
archivo.formatoDestino = formatoDestino;
final result = Conversor.convertir(archivo, pathSalida);
result.then((_) async => (await _file).delete());
return result;
}
}
enum RedSocial{
......
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:prueba_multimedia/modelo/enlace.dart';
import 'package:uuid/uuid.dart';
import 'carpeta.dart';
import 'elemento_seleccionable.dart';
......@@ -64,6 +65,16 @@ class ListaSeleccionables extends ChangeNotifier {
return false;
}
/// Agrega un enlace (archivo para descargar) a ala lista
bool addEnlace(String url) {
_seleccionables.add( Enlace(
id: const Uuid().v1(),
direccion: url
));
notifyListeners();
return true;
}
/// Reinserta un elemento anteriormente eliminado de la lista
void reinsertar(int index, ElementoSeleccionable element){
if(index > _seleccionables.length){
......
......@@ -85,30 +85,77 @@ class ActionButton extends StatelessWidget {
}
}
// TODO: Implementar descarga de archivos
void enlaceAction() {}
/// Pide al usuario que introduzca un enlace y descarga el archivo
void enlaceAction() async {
String? url = await showDialog(context: context, builder: (context) {
final textEditingController = TextEditingController();
return SimpleDialog(
title: const Text("Introducir enlace"),
children: [
SimpleDialogOption(
child: Column(
children: [
SimpleDialogOption(
child: TextField(
controller: textEditingController,
),
),
const SizedBox(height: 16.0,),
SimpleDialogOption(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, textEditingController.text);
},
child: const Text("Aceptar"),
),
SimpleDialogOption(
onPressed: () { Navigator.pop(context); },
child: const Text("Cancelar"),
),
],
),
)
],
),
)
],
);
});
if (url != null) {
manager.addEnlace(url);
}
}
/// Coloca el resultado de la conversión en la carpeta de salida
void copiarAction() async {
if(await _comprobacionesPreviasConversion(context)) {
// Averiguamos donde colocar los archivos de salida
String? directorioSalida = providerAjustes.carpetaSalida.isNotEmpty
? providerAjustes.carpetaSalida
: await FilePicker.platform.getDirectoryPath();
final resultados = <Future<ReturnCode?>>[];
if(directorioSalida != null){
_actualizadorProgreso();
while(manager.seleccionables.isNotEmpty){
ElementoSeleccionable sel = manager.seleccionables.first;
if(sel is Carpeta){
Directory d = await Directory("$directorioSalida/${sel.nombre}").create();
for (var archivo in sel.elementosSeleccionados) {
Directory d = await Directory("$directorioSalida/${sel.nombre}").create();
Conversor.convertir(archivo, d.path);
resultados.add(archivo.convertir(d.path));
}
}
else if (sel is Archivo){
Conversor.convertir(sel, directorioSalida);
else if (sel is Convertible){
resultados.add(sel.convertir(directorioSalida));
}
if (manager.seleccionables.length == 1) {
for (final result in resultados) {
await result;
}
}
manager.borraSeleccionable(0);
......@@ -118,6 +165,7 @@ class ActionButton extends StatelessWidget {
}
/// Igual que copiar pero guarda el resultado en un .zip
/// TODO (RAFA): CREAR LOS ARCHIVOS TEMPORALES EN OTRO SITIO
void comprimirAction() async {
if(await _comprobacionesPreviasConversion(context)) {
// Averiguamos donde colocar los archivos de salida
......@@ -143,7 +191,7 @@ class ActionButton extends StatelessWidget {
Directory d = await Directory("$directorioSalida/${sel.nombre}").create();
final resultsConversion = <Future<ReturnCode?>>[];
for (var archivo in sel.elementosSeleccionados) {
resultsConversion.add(Conversor.convertir(archivo, d.path));
resultsConversion.add(archivo.convertir(d.path));
}
// Esperamos a la conversión y añadimos a zip
......@@ -151,14 +199,15 @@ class ActionButton extends StatelessWidget {
await result;
}
resultsZip.add(
zipFileEncoder.addDirectory(d)..then((_) => d.delete(recursive: true))
// Cuando se añada al zip eliminamos los archivos temporales
zipFileEncoder.addDirectory(d)..then((_) => d.delete(recursive: true))
);
}
// Conversion de archivos
else if (sel is Archivo){
// Esperamos a la conversión y añadimos a zip
await Conversor.convertir(sel, directorioSalida);
// Conversion de archivos y enlaces
else if (sel is Convertible){
sel.convertir(directorioSalida);
File tempFile = await File(
// TODO: Esto da bug con los enlaces por el nombre
"$directorioSalida/${sel.nombre}.${sel.formatoDestino?.name}"
).create();
resultsZip.add(
......@@ -188,6 +237,7 @@ class ActionButton extends StatelessWidget {
// ------------------------ UTILIDADES ------------------------ //
/// Actualiza la barra de progreso de la conversión de forma asíncrona
void _actualizadorProgreso() async {
......
......@@ -43,6 +43,7 @@ dependencies:
ffmpeg_kit_flutter_new: ^1.6.1
shared_preferences: ^2.5.3
archive: ^4.0.7
dio: ^5.8.0+1
dev_dependencies:
flutter_test:
......
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