Interfaz de conversión agregada, arreglos menores

parent 9ad69105
...@@ -8,7 +8,12 @@ import 'formato.dart'; ...@@ -8,7 +8,12 @@ import 'formato.dart';
class ListaSeleccionables extends ChangeNotifier { class ListaSeleccionables extends ChangeNotifier {
final _seleccionables = <ElementoSeleccionable>[]; final _seleccionables = <ElementoSeleccionable>[];
bool _convirtiendo = false;
int _progress = 0;
List<ElementoSeleccionable> get seleccionables => List.unmodifiable(_seleccionables); List<ElementoSeleccionable> get seleccionables => List.unmodifiable(_seleccionables);
bool get convirtiendo => _convirtiendo;
int get progress => _progress;
void borraSeleccionable(int indice) { void borraSeleccionable(int indice) {
_seleccionables.removeAt(indice); _seleccionables.removeAt(indice);
...@@ -54,4 +59,20 @@ class ListaSeleccionables extends ChangeNotifier { ...@@ -54,4 +59,20 @@ class ListaSeleccionables extends ChangeNotifier {
_seleccionables.insert(index, element); _seleccionables.insert(index, element);
notifyListeners(); notifyListeners();
} }
void iniciarConversion() {
_convirtiendo = true;
notifyListeners();
}
void finalizarConversion() {
_convirtiendo = false;
_progress = 0;
notifyListeners();
}
void actualizarProgreso(int initialSize) {
_progress = ((1 - (_seleccionables.length / initialSize))*100).floor();
notifyListeners();
}
} }
\ No newline at end of file
export 'archivo.dart'; export 'archivo.dart';
export 'carpeta.dart'; export 'carpeta.dart';
export 'conversor.dart';
export 'convertible.dart'; export 'convertible.dart';
export 'elemento_seleccionable.dart'; export 'elemento_seleccionable.dart';
export 'enlace.dart'; export 'enlace.dart';
export 'formato.dart'; export 'formato.dart';
export 'lista_seleccionables.dart'; export 'lista_seleccionables.dart';
export 'perfil.dart'; export 'perfil.dart';
export 'conversor.dart'; \ No newline at end of file
\ No newline at end of file
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:open_file/open_file.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:prueba_multimedia/widgets/widgets.dart'; import 'package:prueba_multimedia/widgets/widgets.dart';
import 'package:prueba_multimedia/modelo/modelo.dart'; import 'package:prueba_multimedia/modelo/modelo.dart';
...@@ -10,13 +11,36 @@ class PaginaPrincipal extends StatelessWidget { ...@@ -10,13 +11,36 @@ class PaginaPrincipal extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
void mostrarSnackBarConvertir(){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'¡Conversión de archivos completada!'
),
action: SnackBarAction(
label: 'VER',
onPressed: () async {
// TODO: Cambiar esta dirección por la de los ajustes
await OpenFile.open('/storage/emulated/0/Pictures/Screenshots');
},
),
));
};
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text('Convertex Prototipo'), title: Text(
'Convertex Prototipo',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: Colors.white
),
),
backgroundColor: Theme.of(context).primaryColor, backgroundColor: Theme.of(context).primaryColor,
actions: [ actions: [
IconButton( IconButton(
icon: Icon(Icons.settings_outlined), icon: Icon(
Icons.settings_outlined,
color: Colors.white,
),
onPressed: () { onPressed: () {
showDialog( showDialog(
context: context, context: context,
...@@ -37,10 +61,7 @@ class PaginaPrincipal extends StatelessWidget { ...@@ -37,10 +61,7 @@ class PaginaPrincipal extends StatelessWidget {
] ]
), ),
body: _construirCuerpo(context), body: _construirCuerpo(context),
floatingActionButton: Padding ( floatingActionButton: _construitFAB(context, mostrarSnackBarConvertir),
padding: const EdgeInsets.all(16.0),
child: ConVertexFabBar()
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
); );
} }
...@@ -56,4 +77,29 @@ class PaginaPrincipal extends StatelessWidget { ...@@ -56,4 +77,29 @@ class PaginaPrincipal extends StatelessWidget {
} }
); );
} }
Widget _construitFAB(BuildContext context, VoidCallback function){
return Consumer<ListaSeleccionables>(
builder: (context, manager, child) {
if (manager.convirtiendo) {
return Padding (
padding: const EdgeInsets.all(16.0),
child: ConvertexProgressBar(
progress: manager.progress,
textColor: Colors.black,
completedBackground: Colors.purpleAccent.shade100,
)
);
} else {
return Padding (
padding: const EdgeInsets.all(16.0),
child: ConVertexFabBar(
allowConversion: manager.seleccionables.isNotEmpty,
onConvertSuccess: function,
)
);
}
}
);
}
} }
...@@ -22,6 +22,9 @@ class PaginaPrincipalLlena extends StatelessWidget { ...@@ -22,6 +22,9 @@ class PaginaPrincipalLlena extends StatelessWidget {
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Dismissible( return Dismissible(
key: Key(seleccionables[index].id), key: Key(seleccionables[index].id),
direction: listaSeleccionables.convirtiendo?
DismissDirection.none :
DismissDirection.horizontal,
background: Container( background: Container(
color: Colors.red, color: Colors.red,
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
......
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});
......
...@@ -9,11 +9,18 @@ class ActionButton extends StatelessWidget { ...@@ -9,11 +9,18 @@ class ActionButton extends StatelessWidget {
final ListaSeleccionables manager; final ListaSeleccionables manager;
final BuildContext context; final BuildContext context;
final VoidCallback? onSuccess; final VoidCallback? onSuccess;
final bool disabled;
const ActionButton({super.key, required this.tipoBoton,
required this.manager, required this.context, this.onSuccess}); const ActionButton({
super.key,
void Function() getCallback() { required this.tipoBoton,
required this.manager,
required this.context,
this.onSuccess,
required this.disabled});
void Function()? getCallback() {
if(disabled) return null;
return switch(tipoBoton) { return switch(tipoBoton) {
ActionButtonTypes.archivo => archivoAction, ActionButtonTypes.archivo => archivoAction,
ActionButtonTypes.carpeta => carpetaAction, ActionButtonTypes.carpeta => carpetaAction,
...@@ -113,31 +120,72 @@ class ActionButton extends StatelessWidget { ...@@ -113,31 +120,72 @@ class ActionButton extends StatelessWidget {
} }
void copiarAction() async { void copiarAction() async {
// Averiguamos donde colocar los archivos de salida if(await comprobacionesPrevias()){
String? directorioSalida; actualizadorProgreso();
while (directorioSalida == null) {
directorioSalida = await FilePicker.platform.getDirectoryPath(); // Averiguamos donde colocar los archivos de salida
} String? directorioSalida;
while (directorioSalida == null) {
directorioSalida = await FilePicker.platform.getDirectoryPath();
}
// Convertimos los archivos como tal
List<Archivo> archivos = manager.seleccionables.whereType<Archivo>().toList();
for (var archivo in archivos) {
Conversor.convertir(archivo, directorioSalida);
}
// Convertimos los archivos como tal manager.finalizarConversion();
List<Archivo> archivos = manager.seleccionables.whereType<Archivo>().toList();
for (var archivo in archivos) {
Conversor.convertir(archivo, directorioSalida);
} }
} }
void comprimirAction() { void comprimirAction() async {
if(await comprobacionesPrevias()){
actualizadorProgreso();
// TODO: Código de compresión
}
} }
void reemplazarAction() async { void reemplazarAction() async {
// Convertimos los archivos como tal if(await comprobacionesPrevias()){
List<Archivo> archivos = manager.seleccionables.whereType<Archivo>().toList(); actualizadorProgreso();
for (var archivo in archivos) {
Conversor.getMetadatos(archivo); // Convertimos los archivos como tal
List<Archivo> archivos = manager.seleccionables.whereType<Archivo>().toList();
for (var archivo in archivos) {
Conversor.getMetadatos(archivo);
}
} }
} }
void actualizadorProgreso() async {
manager.iniciarConversion();
int initialSize = manager.seleccionables.length;
await Future.delayed(Duration(milliseconds: 200));
while(manager.seleccionables.isNotEmpty){
manager.actualizarProgreso(initialSize);
await Future.delayed(Duration(milliseconds: 200));
}
if(manager.progress < 100){
manager.actualizarProgreso(initialSize);
await Future.delayed(Duration(milliseconds: 200));
}
manager.finalizarConversion();
if(this.onSuccess != null){
this.onSuccess!();
}
}
Future<bool> comprobacionesPrevias() async {
// TODO: Me gustaría añadir aquí una notificación para avisar al usuario de si quiere realmente convertir una carpeta muy grande
return true;
}
Future<void> _mostrarNotificacion(String text, bool opcion) async{ Future<void> _mostrarNotificacion(String text, bool opcion) async{
await showDialog( await showDialog(
context: context, context: context,
...@@ -182,5 +230,17 @@ enum ActionButtonTypes { ...@@ -182,5 +230,17 @@ enum ActionButtonTypes {
final String label; final String label;
final Icon icon; final Icon icon;
const ActionButtonTypes(this.label, this.icon); const ActionButtonTypes(this.label, this.icon);
bool isConvertir() {
switch(this){
case ActionButtonTypes.copiar:
case ActionButtonTypes.comprimir:
case ActionButtonTypes.reemplazar:
return true;
default:
return false;
}
}
} }
...@@ -4,7 +4,14 @@ import 'package:prueba_multimedia/modelo/modelo.dart'; ...@@ -4,7 +4,14 @@ import 'package:prueba_multimedia/modelo/modelo.dart';
import 'package:prueba_multimedia/widgets/widgets.dart'; import 'package:prueba_multimedia/widgets/widgets.dart';
class ConVertexFabBar extends StatefulWidget { class ConVertexFabBar extends StatefulWidget {
const ConVertexFabBar({super.key}); final bool allowConversion;
final VoidCallback onConvertSuccess;
const ConVertexFabBar({
super.key,
required this.allowConversion,
required this.onConvertSuccess
});
@override @override
State<ConVertexFabBar> createState() => _ConVertexFabBarState(); State<ConVertexFabBar> createState() => _ConVertexFabBarState();
...@@ -69,7 +76,13 @@ class _ConVertexFabBarState extends State<ConVertexFabBar> { ...@@ -69,7 +76,13 @@ class _ConVertexFabBarState extends State<ConVertexFabBar> {
ListaSeleccionables manager) ListaSeleccionables manager)
{ {
return convertirButtonTypes.map((type) { return convertirButtonTypes.map((type) {
return ActionButton(tipoBoton: type, manager: manager, context: context,); return ActionButton(
tipoBoton: type,
manager: manager,
context: context,
disabled: !widget.allowConversion && type.isConvertir(),
onSuccess: widget.onConvertSuccess,
);
}).toList(); }).toList();
} }
...@@ -149,7 +162,13 @@ class _ConVertexFabBarState extends State<ConVertexFabBar> { ...@@ -149,7 +162,13 @@ class _ConVertexFabBarState extends State<ConVertexFabBar> {
}; };
return agregarButtonTypes.map( (type) { return agregarButtonTypes.map( (type) {
return ActionButton(tipoBoton: type, manager: manager, context: context, onSuccess: closeButtons,); return ActionButton(
tipoBoton: type,
manager: manager,
context: context,
onSuccess: closeButtons,
disabled: false
);
}).toList(); }).toList();
} }
} }
import 'package:flutter/material.dart';
class ConvertexProgressBar extends StatelessWidget {
final int progress;
final double? width;
final double? height;
final Color? background;
final Color? completedBackground;
final Color? borderColor;
final Color? textColor;
const ConvertexProgressBar({
super.key,
required this.progress,
this.width,
this.height,
this.background,
this.completedBackground,
this.borderColor,
this.textColor
});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
double defHeight = (constraints.maxHeight > 64)? 64.0 : constraints.maxHeight;
double? both;
Color completed = completedBackground ?? Colors.red;
if(progress == 0){
both = 0;
}
else if(progress == 100){
both = 100;
}
return SizedBox(
width: width ?? constraints.maxWidth,
height: height ?? defHeight,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
completed,
completed,
background ?? completed.withAlpha(0),
background ?? completed.withAlpha(0)
],
stops: [
0,
both ?? ((progress > 5)? (progress-5)/100 : 0.0),
both ?? ((progress < 95)? (progress+5)/100 : 1.0),
1.0
]
),
border: Border.fromBorderSide(
BorderSide(
color: borderColor ?? Colors.black,
width: 3.0
)
),
borderRadius: BorderRadius.circular(22.0)
),
child: FittedBox(
child: Text(
'$progress%',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: textColor ?? Colors.white,
fontWeight: FontWeight.bold
),
),
),
),
);
}
);
}
}
export 'action_button.dart'; export 'action_button.dart';
export 'carpeta_widget.dart';
export 'convertex_fab_bar.dart'; export 'convertex_fab_bar.dart';
export 'convertex_progress_bar.dart';
export 'convertex_prototipo_app.dart'; export 'convertex_prototipo_app.dart';
export 'expandable_fab.dart'; export 'convertible_widget.dart';
export 'convertible_widget.dart'; export 'expandable_fab.dart';
\ No newline at end of file \ No newline at end of file
...@@ -6,6 +6,10 @@ ...@@ -6,6 +6,10 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <open_file_linux/open_file_linux_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) open_file_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "OpenFileLinuxPlugin");
open_file_linux_plugin_register_with_registrar(open_file_linux_registrar);
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
open_file_linux
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST
......
...@@ -5,12 +5,12 @@ ...@@ -5,12 +5,12 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import ffmpeg_kit_flutter
import file_picker import file_picker
import open_file_mac
import path_provider_foundation import path_provider_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
} }
...@@ -5,10 +5,10 @@ packages: ...@@ -5,10 +5,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: async name: async
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.12.0" version: "2.13.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
...@@ -69,10 +69,10 @@ packages: ...@@ -69,10 +69,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" version: "1.3.3"
ffi: ffi:
dependency: transitive dependency: transitive
description: description:
...@@ -148,10 +148,10 @@ packages: ...@@ -148,10 +148,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.8" version: "10.0.9"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
...@@ -208,6 +208,70 @@ packages: ...@@ -208,6 +208,70 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0" version: "1.0.0"
open_file:
dependency: "direct main"
description:
name: open_file
sha256: d17e2bddf5b278cb2ae18393d0496aa4f162142ba97d1a9e0c30d476adf99c0e
url: "https://pub.dev"
source: hosted
version: "3.5.10"
open_file_android:
dependency: transitive
description:
name: open_file_android
sha256: "58141fcaece2f453a9684509a7275f231ac0e3d6ceb9a5e6de310a7dff9084aa"
url: "https://pub.dev"
source: hosted
version: "1.0.6"
open_file_ios:
dependency: transitive
description:
name: open_file_ios
sha256: "02996f01e5f6863832068e97f8f3a5ef9b613516db6897f373b43b79849e4d07"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
open_file_linux:
dependency: transitive
description:
name: open_file_linux
sha256: d189f799eecbb139c97f8bc7d303f9e720954fa4e0fa1b0b7294767e5f2d7550
url: "https://pub.dev"
source: hosted
version: "0.0.5"
open_file_mac:
dependency: transitive
description:
name: open_file_mac
sha256: "1440b1e37ceb0642208cfeb2c659c6cda27b25187a90635c9d1acb7d0584d324"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
open_file_platform_interface:
dependency: transitive
description:
name: open_file_platform_interface
sha256: "101b424ca359632699a7e1213e83d025722ab668b9fd1412338221bf9b0e5757"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
open_file_web:
dependency: transitive
description:
name: open_file_web
sha256: e3dbc9584856283dcb30aef5720558b90f88036360bd078e494ab80a80130c4f
url: "https://pub.dev"
source: hosted
version: "0.0.4"
open_file_windows:
dependency: transitive
description:
name: open_file_windows
sha256: d26c31ddf935a94a1a3aa43a23f4fff8a5ff4eea395fe7a8cb819cf55431c875
url: "https://pub.dev"
source: hosted
version: "0.0.3"
path: path:
dependency: transitive dependency: transitive
description: description:
...@@ -425,10 +489,10 @@ packages: ...@@ -425,10 +489,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.3.1" version: "15.0.0"
web: web:
dependency: transitive dependency: transitive
description: description:
......
...@@ -40,6 +40,7 @@ dependencies: ...@@ -40,6 +40,7 @@ dependencies:
ffmpeg_kit_flutter: ^6.0.3 ffmpeg_kit_flutter: ^6.0.3
path_provider: ^2.1.5 path_provider: ^2.1.5
permission_handler: ^12.0.0+1 permission_handler: ^12.0.0+1
open_file: ^3.5.10
dev_dependencies: dev_dependencies:
flutter_test: 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