Commit f9ffbd50 by Diego Pérez Peña

Fusión ramas WidgetArchivo y mainFBAs

parents 124f442f adcb0b2f
import 'package:flutter/material.dart';
class ActionButton extends StatelessWidget {
final VoidCallback? onPressed;
final String label;
final Icon icon;
const ActionButton({super.key, this.onPressed, required this.label, required this.icon});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Directionality(
textDirection: TextDirection.rtl,
child: FilledButton.icon(
onPressed: onPressed,
label: Text(label, textScaler: const TextScaler.linear(1.2)),
icon: icon
),
);
}
}
import 'conversion.dart';
import 'elemento_seleccionable.dart';
class ArchivoIndividual extends ElementoSeleccionable{
final Conversion _conversion;
List<String> metadatos = [];
ArchivoIndividual({required super.id, required super.nombre, required super.localizacion,
required Conversion conversion}): _conversion = conversion;
@override
void convertir() {
_conversion.convertir();
}
}
\ No newline at end of file
import 'conversion.dart';
import 'elemento_seleccionable.dart';
import 'formato.dart';
class Carpeta extends ElementoSeleccionable{
bool _incluirSubcarpetas = false;
final Map<Formato, bool> _formatosAConvertir;
final Map<Formato, Conversion> _conversiones;
Carpeta({required super.id, required super.nombre, required super.localizacion}):
_formatosAConvertir = {}, _conversiones = {};
@override
void convertir() {
_conversiones.values.forEach((conv) => conv.convertir());
}
}
\ No newline at end of file
import 'formato.dart';
class Conversion{
final Formato _formatoOriginal;
Formato? _formatoDestino;
Conversion({required Formato formatoOriginal, Formato? formatoDestino = null}):
_formatoOriginal = formatoOriginal, _formatoDestino = formatoDestino;
void convertir(){
// TODO: <implement>
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'action_button.dart';
import 'expandable_fab.dart';
class ConVertexFabBar extends StatefulWidget {
const ConVertexFabBar({super.key});
@override
State<ConVertexFabBar> createState() => _ConVertexFabBarState();
}
class _ConVertexFabBarState extends State<ConVertexFabBar> {
bool _convertirOpen = false;
bool _agregarOpen = false;
final _agregarKey = GlobalKey<ExpandableFabState>();
final _convertirKey = GlobalKey<ExpandableFabState>();
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return SizedBox(
width: MediaQuery.of(context).size.width,
height: (_agregarOpen || _convertirOpen)? MediaQuery.of(context).size.height : 56,
child: Stack(
children: [
GestureDetector(
onTap: () {
setState(() {
_agregarOpen = false;
_convertirOpen = false;
});
_agregarKey.currentState?.close();
_convertirKey.currentState?.close();
},
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [..._buildFABs()],
)
],
),
);
}
List<Widget> _buildFABs() {
final toRet = <Widget>[];
// Convertir FAB
toRet.add(Stack(
alignment: Alignment.bottomLeft,
children: [
ExpandableFab(
invert: true,
distance: 60,
icon: Icon(Icons.label_important_outline),
label: 'Convertir',
children: _loadConvertirActionButtons(context),
key: _convertirKey
),
SizedBox(
width: 130,
height: 56,
child: GestureDetector(
onTap: () {
setState(() {
_agregarOpen = false;
_convertirOpen = !_convertirOpen;
});
_agregarKey.currentState?.close();
_convertirKey.currentState?.tap();
},
),
)
],
));
// Agregar FAB
toRet.add(Stack(
alignment: Alignment.bottomRight,
children: [
ExpandableFab(
distance: 60,
icon: Icon(Icons.add),
children: _loadAgregarActionButtons(context),
key: _agregarKey,
),
SizedBox(
width: 56,
height: 56,
child: GestureDetector(
onTap: () {
setState(() {
_convertirOpen = false;
_agregarOpen = !_agregarOpen;
});
_convertirKey.currentState?.close();
_agregarKey.currentState?.tap();
},
),
)
],
));
return toRet;
}
List<Widget> _loadAgregarActionButtons(BuildContext context){
final buttons = <Widget>[];
for(var element in _AgregarActionButtons.values){
buttons.add(ActionButton(
onPressed: () => _showPlaceholderAction(context),
label: element.label,
icon: element.icon)
);
}
return buttons;
}
List<Widget> _loadConvertirActionButtons(BuildContext context){
final buttons = <Widget>[];
for(var element in _ConvertirActionButtons.values){
buttons.add(ActionButton(
onPressed: () => _showPlaceholderAction(context),
label: element.label,
icon: element.icon)
);
}
return buttons;
}
void _showPlaceholderAction(BuildContext context) {
showDialog<void>(
context: context,
builder: (context) {
return AlertDialog(
content: Text('Funcionalidad a implementar'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('CLOSE'),
),
],
);
},
);
}
}
enum _AgregarActionButtons{
NUEVO_ARCHIVO('Archivo', Icon(Icons.description_outlined)),
NUEVA_CARPETA('Carpeta', Icon(Icons.folder_outlined)),
NUEVO_ENLACE('Enlace', Icon(Icons.link_outlined));
final String label;
final Icon icon;
const _AgregarActionButtons(this.label, this.icon);
}
enum _ConvertirActionButtons{
COPIAR_ARCHIVOS('Copiar', Icon(Icons.copy)),
COMPRIMIR_ARCHIVOS('Comprimir', Icon(Icons.splitscreen_outlined)),
REEMPLAZAR_ARCHIVOS('Reemplazar', Icon(Icons.change_circle_outlined));
final String label;
final Icon icon;
const _ConvertirActionButtons(this.label, this.icon);
}
\ No newline at end of file
abstract class ElementoSeleccionable{
final String _id;
final String _nombre;
final String _localizacion;
String get id => this._id;
String get nombre => this._nombre;
String get localizacion => this._localizacion;
ElementoSeleccionable({required String id,
required String nombre,
required String localizacion}):
_id = id, _nombre = nombre, _localizacion = localizacion;
void convertir();
}
\ No newline at end of file
import 'archivo_individual.dart';
class Enlace extends ArchivoIndividual{
final RedSocial _redSocial;
Enlace({required super.id, required super.nombre,
required super.localizacion, required super.conversion,
required redSocial}): _redSocial = redSocial;
@override
void convertir() {
// TODO: <implement> Descarga desde internet...
super.convertir();
}
}
enum RedSocial{
FACEBOOK,
TWITTER,
INSTAGRAM
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'dart:math';
@immutable
class ExpandableFab extends StatefulWidget {
final bool? initialOpen;
final bool invert;
final Icon icon;
final String? label;
final double distance;
final List<Widget> children;
const ExpandableFab({
super.key,
this.initialOpen,
this.invert = false,
required this.icon,
this.label,
required this.distance,
required this.children
});
@override
State<ExpandableFab> createState() => ExpandableFabState();
}
class ExpandableFabState extends State<ExpandableFab>
with SingleTickerProviderStateMixin {
late final AnimationController _controller;
late final Animation<double> _expandAnimation;
bool _open = false;
@override
void initState() {
super.initState();
_open = widget.initialOpen ?? false;
_controller = AnimationController(
value: _open? 1.0 : 0.0,
duration: const Duration(milliseconds: 250),
vsync: this
);
_expandAnimation = CurvedAnimation(
curve: Curves.fastOutSlowIn,
reverseCurve: Curves.easeOutQuad,
parent: _controller
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void tap(){
_toggle();
}
void close(){
if(_open){
_toggle();
}
}
void _toggle(){
setState(() {
_open = !_open;
if(_open){
_controller.forward();
}
else{
_controller.reverse();
}
});
}
@override
Widget build(BuildContext context) {
return Container(
width: _computeWidth(),
height: _open? 56 + (widget.distance*widget.children.length) : (MediaQuery.of(context).size.height),
child: SizedBox.expand(
child: Stack(
alignment: widget.invert? Alignment.bottomLeft : Alignment.bottomRight,
clipBehavior: Clip.none,
children: [
GestureDetector(
onTap: () {if(_open) _toggle();},
),
_buildTapToCloseFab(),
..._buildExpandingActionButtons(),
_buildTapToOpenFab()]
),
),
);
}
Widget _buildTapToCloseFab() {
return SizedBox(
width: 56,
height: 56,
child: Center(
child: Material(
shape: const RoundedRectangleBorder(),
clipBehavior: Clip.antiAlias,
elevation: 4,
child: InkWell(
onTap: _toggle,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.close,
color: Theme.of(context).primaryColor
),
),
),
),
),
);
}
Widget _buildTapToOpenFab() {
return IgnorePointer(
ignoring: _open,
child: AnimatedContainer(
transformAlignment: Alignment.center,
transform: Matrix4.diagonal3Values(
_open? 0.7 : 1.0,
_open? 0.7 : 1.0,
1.0
),
duration: const Duration(milliseconds: 250),
curve: const Interval(0.0, 0.5, curve: Curves.easeOut),
child: AnimatedOpacity(
opacity: _open? 0.0 : 1.0,
curve: const Interval(0.0, 0.5, curve: Curves.easeInOut),
duration: const Duration(milliseconds: 250),
child: _loadFloatingActionButton()
),
),
);
}
Widget _loadFloatingActionButton(){
if(widget.label == null){
return FloatingActionButton(
onPressed: _toggle,
child: widget.icon,
);
}
return FloatingActionButton.extended(
onPressed: _toggle,
icon: widget.icon,
label: Text(
widget.label!,
textScaler: TextScaler.linear(1.2)
)
);
}
List<Widget> _buildExpandingActionButtons() {
final children = <Widget>[];
final count = widget.children.length;
final step = 90.0 / (count - 1);
for(var i = 0; i < count; i++){
children.add(
_ExpandingActionButton(
invert: widget.invert,
directionInDegrees: 90,
maxDistance: widget.distance * (i+1),
progress: _expandAnimation,
child: widget.children[i]
)
);
}
return children;
}
double _computeWidth() {
if(_open){
if(widget.label != null) return 170.0;
return 130.0;
}
else{
if(widget.label != null) return 130.0;
return 56.0;
}
}
}
class _ExpandingActionButton extends StatelessWidget {
final bool invert;
final double directionInDegrees;
final double maxDistance;
final Animation<double> progress;
final Widget child;
const _ExpandingActionButton({
super.key,
this.invert = false,
required this.directionInDegrees,
required this.maxDistance,
required this.progress,
required this.child
});
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: progress,
builder: (context, child) {
final offset = Offset.fromDirection(
directionInDegrees * (pi / 180.0),
progress.value * maxDistance
);
return Positioned(
right: invert? null : 4.0 + offset.dx,
bottom: 4.0 + offset.dy,
//top: 0,
left: invert? 4.0 + offset.dx : null,
child: child!
);
},
child: FadeTransition(opacity: progress, child: child)
);
}
}
class Formato{
final ClaseFormato _extension;
Calidad _calidad;
Formato({required ClaseFormato extension, Calidad calidad = Calidad.ORIGINAL}):
_extension = extension, _calidad = calidad;
}
enum ClaseFormato{
PNG(".png", "Portable Network Graphics", "Calidad", "Nombre, Autor...", "Formato 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.");
final String _extension;
final String _nombre;
final String _descripcion;
final String _clasificacion;
final String _metadatos;
const ClaseFormato(this._extension, this._nombre, this._clasificacion, this._metadatos, this._descripcion);
}
enum Calidad{
BAJA,
MEDIA,
ALTA,
MUY_ALTA,
ORIGINAL
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:prueba_multimedia/convertex_fab_bar.dart';
import 'pagina_principal_llena.dart';
import 'pagina_principal_vacia.dart';
......@@ -20,22 +21,69 @@ class PaginaPrincipal extends StatefulWidget {
* si
*/
Widget construirPaginaPrincipal() {
return PaginaPrincipalLlena();
}
class _PaginaPrincipalState extends State<PaginaPrincipal> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Convertex Prototipo"
),
title: Text('Convertex Prototipo'),
backgroundColor: Theme.of(context).primaryColor,
actions: [
IconButton(onPressed: () {
showDialog<void>(
context: context,
builder: (context) {
return AlertDialog(
content: Text('Funcionalidad a implementar'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('CLOSE'),
),
],
);
},
);
},
icon: Icon(Icons.settings_outlined))
],
),
body: _construirCuerpo(context),
floatingActionButton: Padding(
padding: const EdgeInsets.all(16.0),
child: ConVertexFabBar()
),
body: construirPaginaPrincipal(),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
body: construirPaginaPrincipal(),
Widget _construirCuerpo(BuildContext context) {
if(false){
return PaginaPrincipalLlena();
}
else{
return PaginaPrincipalVacia();
}
/*return SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'No hay archivos seleccionados',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 16.0),
Text(
'Pulsa el botón + para agregarlos',
style: Theme.of(context).textTheme.bodyLarge,
)
],
),
)
);*/
}
}
import 'formato.dart';
class Perfil{
final String _identificador;
final String _nombre;
final Formato _formatoCorrespondiente;
Perfil({required String identificador, required String nombre, required Formato formatoCorrespondiente}):
_identificador = identificador, _nombre = nombre, _formatoCorrespondiente = formatoCorrespondiente;
}
\ No newline at end of file
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