Interfaz de conversión agregada, arreglos menores

parent 9ad69105
......@@ -8,7 +8,12 @@ import 'formato.dart';
class ListaSeleccionables extends ChangeNotifier {
final _seleccionables = <ElementoSeleccionable>[];
bool _convirtiendo = false;
int _progress = 0;
List<ElementoSeleccionable> get seleccionables => List.unmodifiable(_seleccionables);
bool get convirtiendo => _convirtiendo;
int get progress => _progress;
void borraSeleccionable(int indice) {
_seleccionables.removeAt(indice);
......@@ -54,4 +59,20 @@ class ListaSeleccionables extends ChangeNotifier {
_seleccionables.insert(index, element);
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 'carpeta.dart';
export 'conversor.dart';
export 'convertible.dart';
export 'elemento_seleccionable.dart';
export 'enlace.dart';
export 'formato.dart';
export 'lista_seleccionables.dart';
export 'perfil.dart';
export 'conversor.dart';
\ No newline at end of file
export 'perfil.dart';
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:open_file/open_file.dart';
import 'package:provider/provider.dart';
import 'package:prueba_multimedia/widgets/widgets.dart';
import 'package:prueba_multimedia/modelo/modelo.dart';
......@@ -10,13 +11,36 @@ class PaginaPrincipal extends StatelessWidget {
@override
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(
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,
actions: [
IconButton(
icon: Icon(Icons.settings_outlined),
icon: Icon(
Icons.settings_outlined,
color: Colors.white,
),
onPressed: () {
showDialog(
context: context,
......@@ -37,10 +61,7 @@ class PaginaPrincipal extends StatelessWidget {
]
),
body: _construirCuerpo(context),
floatingActionButton: Padding (
padding: const EdgeInsets.all(16.0),
child: ConVertexFabBar()
),
floatingActionButton: _construitFAB(context, mostrarSnackBarConvertir),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
......@@ -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 {
itemBuilder: (context, index) {
return Dismissible(
key: Key(seleccionables[index].id),
direction: listaSeleccionables.convirtiendo?
DismissDirection.none :
DismissDirection.horizontal,
background: Container(
color: Colors.red,
alignment: Alignment.centerLeft,
......
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 {
const PaginaPrincipalVacia({super.key});
......
......@@ -9,11 +9,18 @@ class ActionButton extends StatelessWidget {
final ListaSeleccionables manager;
final BuildContext context;
final VoidCallback? onSuccess;
const ActionButton({super.key, required this.tipoBoton,
required this.manager, required this.context, this.onSuccess});
void Function() getCallback() {
final bool disabled;
const ActionButton({
super.key,
required this.tipoBoton,
required this.manager,
required this.context,
this.onSuccess,
required this.disabled});
void Function()? getCallback() {
if(disabled) return null;
return switch(tipoBoton) {
ActionButtonTypes.archivo => archivoAction,
ActionButtonTypes.carpeta => carpetaAction,
......@@ -113,31 +120,72 @@ class ActionButton extends StatelessWidget {
}
void copiarAction() async {
// Averiguamos donde colocar los archivos de salida
String? directorioSalida;
while (directorioSalida == null) {
directorioSalida = await FilePicker.platform.getDirectoryPath();
}
if(await comprobacionesPrevias()){
actualizadorProgreso();
// 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
List<Archivo> archivos = manager.seleccionables.whereType<Archivo>().toList();
for (var archivo in archivos) {
Conversor.convertir(archivo, directorioSalida);
manager.finalizarConversion();
}
}
void comprimirAction() {
void comprimirAction() async {
if(await comprobacionesPrevias()){
actualizadorProgreso();
// TODO: Código de compresión
}
}
void reemplazarAction() async {
// Convertimos los archivos como tal
List<Archivo> archivos = manager.seleccionables.whereType<Archivo>().toList();
for (var archivo in archivos) {
Conversor.getMetadatos(archivo);
if(await comprobacionesPrevias()){
actualizadorProgreso();
// 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{
await showDialog(
context: context,
......@@ -182,5 +230,17 @@ enum ActionButtonTypes {
final String label;
final Icon 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';
import 'package:prueba_multimedia/widgets/widgets.dart';
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
State<ConVertexFabBar> createState() => _ConVertexFabBarState();
......@@ -69,7 +76,13 @@ class _ConVertexFabBarState extends State<ConVertexFabBar> {
ListaSeleccionables manager)
{
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();
}
......@@ -149,7 +162,13 @@ class _ConVertexFabBarState extends State<ConVertexFabBar> {
};
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();
}
}
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 'carpeta_widget.dart';
export 'convertex_fab_bar.dart';
export 'convertex_progress_bar.dart';
export 'convertex_prototipo_app.dart';
export 'expandable_fab.dart';
export 'convertible_widget.dart';
\ No newline at end of file
export 'convertible_widget.dart';
export 'expandable_fab.dart';
\ No newline at end of file
......@@ -6,6 +6,10 @@
#include "generated_plugin_registrant.h"
#include <open_file_linux/open_file_linux_plugin.h>
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 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
open_file_linux
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
......
......@@ -5,12 +5,12 @@
import FlutterMacOS
import Foundation
import ffmpeg_kit_flutter
import file_picker
import open_file_mac
import path_provider_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
}
......@@ -5,10 +5,10 @@ packages:
dependency: transitive
description:
name: async
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted
version: "2.12.0"
version: "2.13.0"
boolean_selector:
dependency: transitive
description:
......@@ -69,10 +69,10 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
version: "1.3.3"
ffi:
dependency: transitive
description:
......@@ -148,10 +148,10 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
url: "https://pub.dev"
source: hosted
version: "10.0.8"
version: "10.0.9"
leak_tracker_flutter_testing:
dependency: transitive
description:
......@@ -208,6 +208,70 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
......@@ -425,10 +489,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
url: "https://pub.dev"
source: hosted
version: "14.3.1"
version: "15.0.0"
web:
dependency: transitive
description:
......
......@@ -40,6 +40,7 @@ dependencies:
ffmpeg_kit_flutter: ^6.0.3
path_provider: ^2.1.5
permission_handler: ^12.0.0+1
open_file: ^3.5.10
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