ElPoteito 6 meses atrás
pai
commit
1c1206f0af

+ 2 - 0
lib/main.dart

@@ -1,4 +1,5 @@
 import 'package:conalep_pos/viewmodels/corte_caja_view_model.dart';
+import 'package:conalep_pos/viewmodels/mesa_view_model.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:provider/provider.dart';
@@ -48,6 +49,7 @@ void main() async {
       ChangeNotifierProvider(create: (_) => CorteCajaViewModel()),
       ChangeNotifierProvider(create: (_) => DescuentoViewModel()),
       ChangeNotifierProvider(create: (_) => VariableViewModel()),
+      ChangeNotifierProvider(create: (_) => MesaViewModel()),
       // Agrega aquí cualquier otro provider que necesites
     ], child: const MyApp()));
   });

+ 38 - 0
lib/models/mesa_model.dart

@@ -0,0 +1,38 @@
+import 'package:conalep_pos/models/basico_model.dart';
+import '../services/services.dart';
+
+class Mesa extends Basico {
+  String? nombre;
+  String? clave;
+  bool? activa;
+
+  Mesa({
+    super.id,
+    super.idLocal,
+    this.nombre,
+    this.clave,
+    this.activa,
+    super.eliminado
+  });
+
+  @override
+  Map<String, dynamic> toJson() {
+    return {
+      'id': id,
+      'nombre': nombre,
+      'clave': clave,
+      'activa': activa,
+    }..addAll(super.toJson());
+  }
+
+  Mesa.fromJson(Map<String, dynamic> json) {
+    super.parseJson(json);
+    nombre = Basico.parseString(json['nombre']);
+    clave = Basico.parseString(json['clave']);
+    activa = Basico.parseBolean(json['activa']);
+  }
+
+  Future<void> guardar() async {
+    idLocal = await RepoService().guardar(this);
+  }
+}

+ 16 - 2
lib/services/repo_service.dart

@@ -377,8 +377,22 @@ class RepoService<T> {
 
   Future<List<Pedido>> obtenerPedidosPaginados(int limit, int offset) async {
     Database? dbClient = await db;
-    List<Map<String, dynamic>> result = await dbClient!
-        .query('Pedido', limit: limit, offset: offset, orderBy: 'id DESC');
+    List<Map<String, dynamic>> result = await dbClient!.query('Pedido',
+        limit: limit,
+        offset: offset,
+        orderBy: 'id DESC',
+        where: 'idMesa = null');
+    return result.map((map) => Pedido.fromJson(map)).toList();
+  }
+
+  Future<List<Pedido>> obtenerMesaPedidosPaginados(
+      int limit, int offset) async {
+    Database? dbClient = await db;
+    List<Map<String, dynamic>> result = await dbClient!.query('Pedido',
+        limit: limit,
+        offset: offset,
+        orderBy: 'id DESC',
+        where: 'idMesa != null');
     return result.map((map) => Pedido.fromJson(map)).toList();
   }
 

+ 121 - 0
lib/viewmodels/mesa_view_model.dart

@@ -0,0 +1,121 @@
+import 'package:conalep_pos/models/mesa_model.dart';
+import 'package:flutter/material.dart';
+import '../services/services.dart';
+import 'package:sqflite/sqflite.dart';
+
+class MesaViewModel extends ChangeNotifier {
+  String _busqueda = "";
+  String get busqueda => _busqueda;
+
+  List<Mesa> _mesas = [];
+  bool _isLoading = false;
+  Mesa? _selectedMesa;
+
+  List<Mesa> get mesas => _mesas;
+  bool get isLoading => _isLoading;
+  Mesa? get selectedMesa => _selectedMesa;
+
+  int _currentPage = 1;
+  int _totalMesas = 0;
+  int _limit = 10;
+
+  int get currentPage => _currentPage;
+  int get totalMesas => _totalMesas;
+  int get totalPages => (_totalMesas / _limit).ceil();
+
+  setBusqueda(String value) {
+    _busqueda = value;
+    notifyListeners();
+  }
+
+  void selectMesa(Mesa mesa) {
+    _selectedMesa = mesa;
+    notifyListeners();
+  }
+
+  Future<void> fetchLocalAll({int page = 1}) async {
+    _currentPage = page;
+    var db = await RepoService().db;
+
+    int? count =
+        Sqflite.firstIntValue(await db!.rawQuery('SELECT COUNT(*) FROM Mesa'));
+    _totalMesas = count ?? 0;
+
+    int offset = (_limit * (page - 1));
+
+    var query = await db.query('Mesa',
+        orderBy: 'id asc', limit: _limit, offset: offset);
+    _mesas = query.map((element) => Mesa.fromJson(element)).toList();
+    notifyListeners();
+  }
+
+  Future<void> fetchLocalByName({required String nombre}) async {
+    var db = await RepoService().db;
+    var query = await db!.query(
+      'Mesa',
+      where: 'nombre LIKE "%$nombre%"',
+      orderBy: 'id asc',
+    );
+    List<Mesa> aux = [];
+    for (var element in query) {
+      Mesa mesa = Mesa.fromJson(element);
+      aux.add(mesa);
+    }
+    _mesas = aux;
+    notifyListeners();
+  }
+
+  Future<void> addMesa(Mesa mesa) async {
+    await RepoService().guardar(mesa);
+    fetchLocalAll();
+  }
+
+  Future<void> updateMesa(Mesa mesa) async {
+    setIsLoading(true);
+    try {
+      await RepoService().guardar(mesa);
+      fetchLocalAll();
+    } catch (e) {
+      print('Error updating mesa: $e');
+    }
+    setIsLoading(false);
+  }
+
+  Future<void> deleteMesa(int id) async {
+    await RepoService().eliminar<Mesa>(id);
+    fetchLocalAll();
+  }
+
+  void setIsLoading(bool loading) {
+    _isLoading = loading;
+    notifyListeners();
+  }
+
+  void nextPage() {
+    if (_currentPage < totalPages) {
+      fetchLocalAll(page: _currentPage + 1);
+    }
+  }
+
+  void previousPage() {
+    if (_currentPage > 1) {
+      fetchLocalAll(page: _currentPage - 1);
+    }
+  }
+
+  Future<bool> isMesaActive(String clave) async {
+    var db = await RepoService().db;
+    var result = await db!.query(
+      'Mesa',
+      where: 'clave = ?',
+      whereArgs: [clave],
+    );
+
+    if (result.isNotEmpty) {
+      var mesa = Mesa.fromJson(result.first);
+      return mesa.activa == true;
+    }
+
+    return false;
+  }
+}

+ 36 - 0
lib/viewmodels/pedido_view_model.dart

@@ -93,6 +93,22 @@ class PedidoViewModel extends ChangeNotifier {
     notifyListeners();
   }
 
+  Future<void> fetchLocalMesaPedidos({int page = 1}) async {
+    _isLoading = true;
+    _currentPage = page;
+    notifyListeners();
+
+    RepoService<Pedido> repoPedido = RepoService<Pedido>();
+    _totalPedidos = await repoPedido.contarPedidos();
+    int offset = (_limit * (page - 1));
+    List<Pedido> paginatedPedidos =
+        await repoPedido.obtenerMesaPedidosPaginados(_limit, offset);
+
+    _pedidos = paginatedPedidos;
+    _isLoading = false;
+    notifyListeners();
+  }
+
   void nextPage() {
     if (_currentPage < totalPages) {
       fetchLocalPedidosForScreen(page: _currentPage + 1);
@@ -125,6 +141,26 @@ class PedidoViewModel extends ChangeNotifier {
     notifyListeners();
   }
 
+  Future<void> fetchLocalMesaPedidosForScreen({int page = 1}) async {
+    setIsLoading(true);
+    RepoService<Pedido> repoPedido = RepoService<Pedido>();
+    _currentPage = page;
+    var db = await RepoService().db;
+
+    int? count = Sqflite.firstIntValue(
+        await db!.rawQuery('SELECT COUNT(*) FROM Pedido'));
+    _totalPedidos = count ?? 0;
+
+    int offset = (_limit * (page - 1));
+
+    List<Pedido> localPedidos =
+        await repoPedido.obtenerMesaPedidosPaginados(_limit, offset);
+    _pedidos = localPedidos;
+
+    setIsLoading(false);
+    notifyListeners();
+  }
+
   Future<List<Pedido>> fetchAllLocalPedidos() async {
     setIsLoading(true);
     RepoService<Pedido> repoPedido = RepoService<Pedido>();

+ 2 - 4
lib/views/categoria_producto/categoria_producto_screen.dart

@@ -381,8 +381,7 @@ class _CategoriaProductoScreenState extends State<CategoriaProductoScreen> {
                   style: ElevatedButton.styleFrom(
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(20.0),
-                    ),
-                    primary: AppTheme.tertiary,
+                    ), backgroundColor: AppTheme.tertiary,
                     padding: const EdgeInsets.symmetric(vertical: 25),
                   ),
                   child: Text('Limpiar',
@@ -409,8 +408,7 @@ class _CategoriaProductoScreenState extends State<CategoriaProductoScreen> {
                   style: ElevatedButton.styleFrom(
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(20.0),
-                    ),
-                    primary: AppTheme.tertiary,
+                    ), backgroundColor: AppTheme.tertiary,
                     padding: const EdgeInsets.symmetric(vertical: 25),
                   ),
                   child: Text('Buscar',

+ 3 - 3
lib/views/corte_caja/corte_caja_form.dart

@@ -77,7 +77,7 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
                       'Finalizar',
                       style: TextStyle(color: AppTheme.quaternary),
                     ),
-                    style: ElevatedButton.styleFrom(primary: AppTheme.primary),
+                    style: ElevatedButton.styleFrom(backgroundColor: AppTheme.primary),
                   ),
                   ElevatedButton.icon(
                     icon: Image.asset(
@@ -90,7 +90,7 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
                       // Lógica para generar CSV
                     },
                     style: ElevatedButton.styleFrom(
-                        primary: AppTheme.primary,
+                        backgroundColor: AppTheme.primary,
                         padding: EdgeInsets.all(20),
                         shape: RoundedRectangleBorder(
                             borderRadius:
@@ -104,7 +104,7 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
                     onPressed: () {
                       // Lógica para generar PDF
                     },
-                    style: ElevatedButton.styleFrom(primary: AppTheme.primary),
+                    style: ElevatedButton.styleFrom(backgroundColor: AppTheme.primary),
                   ),
                 ],
               )

+ 2 - 4
lib/views/corte_caja/corte_caja_screen.dart

@@ -399,8 +399,7 @@ class _CorteCajaScreenState extends State<CorteCajaScreen> {
                   style: ElevatedButton.styleFrom(
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(20.0),
-                    ),
-                    primary: Colors.redAccent,
+                    ), backgroundColor: Colors.redAccent,
                     padding: const EdgeInsets.symmetric(vertical: 25),
                   ),
                   child: Text('Limpiar',
@@ -428,8 +427,7 @@ class _CorteCajaScreenState extends State<CorteCajaScreen> {
                   style: ElevatedButton.styleFrom(
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(20.0),
-                    ),
-                    primary: AppTheme.tertiary,
+                    ), backgroundColor: AppTheme.tertiary,
                     padding: const EdgeInsets.symmetric(vertical: 25),
                   ),
                   child: Text('Buscar',

+ 110 - 0
lib/views/mesa/mesa_form.dart

@@ -0,0 +1,110 @@
+import 'package:conalep_pos/models/mesa_model.dart';
+import 'package:conalep_pos/themes/themes.dart';
+import 'package:conalep_pos/viewmodels/mesa_view_model.dart';
+import 'package:conalep_pos/widgets/widgets.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+
+class MesaForm extends StatefulWidget {
+  final Mesa mesa;
+
+  const MesaForm({Key? key, required this.mesa}) : super(key: key);
+
+  @override
+  _MesaFormState createState() => _MesaFormState();
+}
+
+class _MesaFormState extends State<MesaForm> {
+  final _nombre = TextEditingController();
+  final _clave = TextEditingController();
+  bool _activa = true;
+
+  @override
+  void initState() {
+    super.initState();
+    _nombre.text = widget.mesa.nombre ?? "";
+    _clave.text = widget.mesa.clave ?? "";
+    _activa = widget.mesa.activa ?? true;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        title: Text(
+          widget.mesa.id == null ? 'Nueva Mesa' : 'Editar Mesa',
+          style: TextStyle(color: AppTheme.secondary),
+        ),
+        iconTheme: IconThemeData(color: AppTheme.secondary),
+      ),
+      body: SingleChildScrollView(
+        padding: EdgeInsets.all(8),
+        child: Column(
+          children: [
+            tarjeta(
+              Padding(
+                padding: const EdgeInsets.all(8),
+                child: Column(
+                  children: [
+                    AppTextField(
+                      maxLength: 100,
+                      etiqueta: 'Nombre',
+                      controller: _nombre,
+                      hintText: 'Nombre de la variable',
+                    ),
+                    AppTextField(
+                      maxLength: 100,
+                      etiqueta: 'Clave',
+                      controller: _clave,
+                      hintText: 'Clave de la variable',
+                    ),
+                    SwitchListTile(
+                      activeColor: AppTheme.primary,
+                      title: const Text(
+                        "Activo",
+                        style: TextStyle(
+                            fontWeight: FontWeight.bold, fontSize: 18),
+                      ),
+                      value: _activa,
+                      onChanged: (bool value) {
+                        setState(() {
+                          _activa = value;
+                        });
+                      },
+                    ),
+                  ],
+                ),
+              ),
+            ),
+            SizedBox(height: 15),
+            boton("Guardar", () async {
+              Provider.of<MesaViewModel>(context, listen: false)
+                  .setIsLoading(true);
+
+              widget.mesa.nombre = _nombre.text;
+              widget.mesa.clave = _clave.text;
+              widget.mesa.activa = _activa;
+
+              await Provider.of<MesaViewModel>(context, listen: false)
+                  .updateMesa(widget.mesa);
+
+              Provider.of<MesaViewModel>(context, listen: false)
+                  .setIsLoading(false);
+
+              if (context.mounted) {
+                Navigator.pop(context);
+              }
+            })
+          ],
+        ),
+      ),
+    );
+  }
+
+  @override
+  void dispose() {
+    _nombre.dispose();
+    _clave.dispose();
+    super.dispose();
+  }
+}

+ 410 - 0
lib/views/mesa/mesa_screen.dart

@@ -0,0 +1,410 @@
+import 'package:conalep_pos/models/mesa_model.dart';
+import 'package:conalep_pos/themes/themes.dart';
+import 'package:conalep_pos/viewmodels/mesa_view_model.dart';
+import 'package:conalep_pos/views/mesa/mesa_form.dart';
+import 'package:conalep_pos/widgets/widgets.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import '../../widgets/widgets_components.dart' as clase;
+
+class MesasScreen extends StatefulWidget {
+  @override
+  _MesasScreenState createState() => _MesasScreenState();
+}
+
+class _MesasScreenState extends State<MesasScreen> {
+  final _busqueda = TextEditingController(text: '');
+  ScrollController horizontalScrollController = ScrollController();
+
+  @override
+  void initState() {
+    super.initState();
+    Provider.of<MesaViewModel>(context, listen: false).fetchLocalAll();
+  }
+
+  void go(Mesa variable) {
+    Navigator.push(
+      context,
+      MaterialPageRoute(
+        builder: (context) => MesaForm(mesa: variable),
+      ),
+    ).then((_) =>
+        Provider.of<MesaViewModel>(context, listen: false).fetchLocalAll());
+  }
+
+  void clearSearchAndReset() {
+    setState(() {
+      _busqueda.clear();
+      Provider.of<MesaViewModel>(context, listen: false).fetchLocalAll();
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final model = Provider.of<MesaViewModel>(context);
+    double screenWidth = MediaQuery.of(context).size.width;
+    final isMobile = screenWidth < 1250;
+    final double? columnSpacing = isMobile ? null : 0;
+    TextStyle estilo = const TextStyle(fontWeight: FontWeight.bold);
+
+    List<DataRow> registros = [];
+    for (Mesa item in model.mesas) {
+      registros.add(DataRow(cells: [
+        DataCell(
+            Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
+          PopupMenuButton(
+            itemBuilder: (context) => [
+              PopupMenuItem(
+                child: const Text('Editar'),
+                onTap: () => go(item),
+              ),
+              PopupMenuItem(
+                child: const Text('Eliminar'),
+                onTap: () async {
+                  await Future.delayed(Duration(milliseconds: 100));
+                  bool confirmado = await showDialog<bool>(
+                        context: context,
+                        builder: (context) {
+                          return AlertDialog(
+                            title: const Text("Eliminar",
+                                style: TextStyle(
+                                    fontWeight: FontWeight.w500, fontSize: 22)),
+                            content: const Text(
+                                '¿Estás seguro de que deseas eliminar esta variable?',
+                                style: TextStyle(fontSize: 18)),
+                            actions: [
+                              Row(
+                                mainAxisAlignment:
+                                    MainAxisAlignment.spaceBetween,
+                                children: [
+                                  TextButton(
+                                    onPressed: () =>
+                                        Navigator.of(context).pop(false),
+                                    child: const Text('No',
+                                        style: TextStyle(fontSize: 18)),
+                                    style: ButtonStyle(
+                                        padding: MaterialStatePropertyAll(
+                                            EdgeInsets.fromLTRB(
+                                                20, 10, 20, 10)),
+                                        backgroundColor:
+                                            MaterialStatePropertyAll(
+                                                AppTheme.primary),
+                                        foregroundColor:
+                                            MaterialStatePropertyAll(
+                                                AppTheme.secondary)),
+                                  ),
+                                  TextButton(
+                                    onPressed: () =>
+                                        Navigator.of(context).pop(true),
+                                    child: const Text('Sí',
+                                        style: TextStyle(fontSize: 18)),
+                                    style: ButtonStyle(
+                                        padding: MaterialStatePropertyAll(
+                                            EdgeInsets.fromLTRB(
+                                                20, 10, 20, 10)),
+                                        backgroundColor:
+                                            MaterialStatePropertyAll(
+                                                AppTheme.tertiary),
+                                        foregroundColor:
+                                            MaterialStatePropertyAll(
+                                                AppTheme.quaternary)),
+                                  ),
+                                ],
+                              )
+                            ],
+                          );
+                        },
+                      ) ??
+                      false;
+
+                  if (confirmado) {
+                    await model.deleteMesa(item.id!);
+                    model.fetchLocalAll();
+                  }
+                },
+              )
+            ],
+            icon: const Icon(Icons.more_vert),
+          ),
+        ])),
+        DataCell(
+          Text(item.id.toString()),
+          onTap: () {
+            Provider.of<MesaViewModel>(context, listen: false)
+                .selectMesa(item);
+            go(item);
+          },
+        ),
+        DataCell(
+          Text(item.nombre.toString()),
+          onTap: () {
+            Provider.of<MesaViewModel>(context, listen: false)
+                .selectMesa(item);
+            go(item);
+          },
+        ),
+      ]));
+    }
+
+    return Scaffold(
+      appBar: AppBar(
+        title: Text(
+          'Mesas',
+          style: TextStyle(color: AppTheme.secondary),
+        ),
+        iconTheme: IconThemeData(color: AppTheme.secondary),
+      ),
+      body: Column(
+        children: [
+          Expanded(
+            child: ListView(
+              padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
+              children: [
+                const SizedBox(height: 8),
+                clase.tarjeta(
+                  Padding(
+                    padding: const EdgeInsets.all(8.0),
+                    child: LayoutBuilder(
+                      builder: (context, constraints) {
+                        if (screenWidth > 1000) {
+                          return Row(
+                            children: [
+                              Expanded(
+                                flex: 7,
+                                child: busquedaTextField(),
+                              ),
+                              SizedBox(width: 5),
+                              botonBuscar()
+                            ],
+                          );
+                        } else {
+                          return Column(
+                            children: [
+                              Row(
+                                children: [busquedaTextField()],
+                              ),
+                              SizedBox(height: 15),
+                              Row(
+                                children: [botonBuscar()],
+                              ),
+                            ],
+                          );
+                        }
+                      },
+                    ),
+                  ),
+                ),
+                const SizedBox(height: 8),
+                model.isLoading
+                    ? const Center(child: CircularProgressIndicator())
+                    : Container(),
+                clase.tarjeta(
+                  Column(
+                    children: [
+                      LayoutBuilder(builder: (context, constraints) {
+                        return SingleChildScrollView(
+                          scrollDirection: Axis.vertical,
+                          child: Scrollbar(
+                            controller: horizontalScrollController,
+                            interactive: true,
+                            thumbVisibility: true,
+                            thickness: 10.0,
+                            child: SingleChildScrollView(
+                              controller: horizontalScrollController,
+                              scrollDirection: Axis.horizontal,
+                              child: ConstrainedBox(
+                                constraints: BoxConstraints(
+                                    minWidth: isMobile
+                                        ? constraints.maxWidth
+                                        : screenWidth),
+                                child: DataTable(
+                                  columnSpacing: columnSpacing,
+                                  sortAscending: true,
+                                  sortColumnIndex: 1,
+                                  columns: [
+                                    DataColumn(label: Text(" ", style: estilo)),
+                                    DataColumn(
+                                        label: Text("ID", style: estilo)),
+                                    DataColumn(
+                                        label: Text("NOMBRE", style: estilo)),
+                                  ],
+                                  rows: registros,
+                                ),
+                              ),
+                            ),
+                          ),
+                        );
+                      }),
+                    ],
+                  ),
+                ),
+                const SizedBox(
+                  height: 15,
+                ),
+                if (!model.isLoading) ...[
+                  Row(
+                    mainAxisAlignment: MainAxisAlignment.center,
+                    children: [
+                      TextButton(
+                        onPressed:
+                            model.currentPage > 1 ? model.previousPage : null,
+                        child: Text('Anterior'),
+                        style: ButtonStyle(
+                          backgroundColor:
+                              MaterialStateProperty.resolveWith<Color?>(
+                            (Set<MaterialState> states) {
+                              if (states.contains(MaterialState.disabled)) {
+                                return Colors.grey;
+                              }
+                              return AppTheme.tertiary;
+                            },
+                          ),
+                          foregroundColor:
+                              MaterialStateProperty.resolveWith<Color?>(
+                            (Set<MaterialState> states) {
+                              if (states.contains(MaterialState.disabled)) {
+                                return Colors.black;
+                              }
+                              return Colors.white;
+                            },
+                          ),
+                        ),
+                      ),
+                      SizedBox(width: 15),
+                      Text(
+                          'Página ${model.currentPage} de ${model.totalPages}'),
+                      SizedBox(width: 15),
+                      TextButton(
+                        onPressed: model.currentPage < model.totalPages
+                            ? model.nextPage
+                            : null,
+                        child: Text('Siguiente'),
+                        style: ButtonStyle(
+                          backgroundColor:
+                              MaterialStateProperty.resolveWith<Color?>(
+                            (Set<MaterialState> states) {
+                              if (states.contains(MaterialState.disabled)) {
+                                return Colors.grey;
+                              }
+                              return AppTheme.tertiary;
+                            },
+                          ),
+                          foregroundColor:
+                              MaterialStateProperty.resolveWith<Color?>(
+                            (Set<MaterialState> states) {
+                              if (states.contains(MaterialState.disabled)) {
+                                return Colors.black;
+                              }
+                              return Colors.white;
+                            },
+                          ),
+                        ),
+                      ),
+                    ],
+                  ),
+                ],
+                const SizedBox(
+                  height: 15,
+                ),
+              ],
+            ),
+          ),
+        ],
+      ),
+      floatingActionButton: FloatingActionButton.extended(
+        onPressed: () async {
+          Mesa nuevaMesa = Mesa();
+          Navigator.push(
+            context,
+            MaterialPageRoute(
+              builder: (context) => MesaForm(mesa: nuevaMesa),
+            ),
+          ).then((_) => Provider.of<MesaViewModel>(context, listen: false)
+              .fetchLocalAll());
+        },
+        icon: Icon(Icons.add, size: 30, color: AppTheme.quaternary),
+        label: Text(
+          "Agregar Mesa",
+          style: TextStyle(fontSize: 18, color: AppTheme.quaternary),
+        ),
+        shape: RoundedRectangleBorder(
+          borderRadius: BorderRadius.circular(8),
+        ),
+        materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+        backgroundColor: AppTheme.tertiary,
+      ),
+    );
+  }
+
+  Widget busquedaTextField() {
+    return Row(
+      children: [
+        Expanded(
+          flex: 3,
+          child: AppTextField(
+            prefixIcon: const Icon(Icons.search),
+            etiqueta: 'Búsqueda por nombre...',
+            controller: _busqueda,
+            hintText: 'Búsqueda por nombre...',
+          ),
+        ),
+        const SizedBox(width: 5),
+      ],
+    );
+  }
+
+  Widget botonBuscar() {
+    return Expanded(
+        flex: 2,
+        child: Row(
+          children: [
+            Expanded(
+              flex: 2,
+              child: Padding(
+                padding: const EdgeInsets.only(top: 30),
+                child: ElevatedButton(
+                  onPressed: clearSearchAndReset,
+                  style: ElevatedButton.styleFrom(
+                    shape: RoundedRectangleBorder(
+                      borderRadius: BorderRadius.circular(20.0),
+                    ),
+                    backgroundColor: AppTheme.tertiary,
+                    padding: const EdgeInsets.symmetric(vertical: 25),
+                  ),
+                  child: Text('Limpiar',
+                      style: TextStyle(color: AppTheme.quaternary)),
+                ),
+              ),
+            ),
+            const SizedBox(width: 8),
+            Expanded(
+              flex: 2,
+              child: Padding(
+                padding: const EdgeInsets.only(top: 30),
+                child: ElevatedButton(
+                  onPressed: () async {
+                    if (_busqueda.text.isNotEmpty) {
+                      await Provider.of<MesaViewModel>(context,
+                              listen: false)
+                          .fetchLocalByName(nombre: _busqueda.text.trim());
+                    } else {
+                      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
+                          content: Text('Introduce un nombre para buscar.')));
+                    }
+                  },
+                  style: ElevatedButton.styleFrom(
+                    shape: RoundedRectangleBorder(
+                      borderRadius: BorderRadius.circular(20.0),
+                    ),
+                    backgroundColor: AppTheme.tertiary,
+                    padding: const EdgeInsets.symmetric(vertical: 25),
+                  ),
+                  child: Text('Buscar',
+                      style: TextStyle(color: AppTheme.quaternary)),
+                ),
+              ),
+            ),
+          ],
+        ));
+  }
+}

+ 1 - 1
lib/views/pedido/pedido_detalle_screen.dart

@@ -264,7 +264,7 @@ class PedidoDetalleScreen extends StatelessWidget {
                 ),
                 style: ElevatedButton.styleFrom(
                   padding: const EdgeInsets.fromLTRB(50, 20, 50, 20),
-                  primary: AppTheme.tertiary,
+                  backgroundColor: AppTheme.tertiary,
                 ),
               ),
             )

+ 3 - 3
lib/views/pedido/pedido_form.dart

@@ -978,7 +978,7 @@ class _PedidoFormState extends State<PedidoForm> {
             child: ElevatedButton(
               onPressed: _finalizeOrder,
               style: ElevatedButton.styleFrom(
-                primary: AppTheme.tertiary,
+                backgroundColor: AppTheme.tertiary,
                 textStyle: const TextStyle(fontSize: 22),
                 fixedSize: const Size(250, 50),
               ),
@@ -1108,10 +1108,10 @@ class _PedidoFormState extends State<PedidoForm> {
                 });
               },
               style: ElevatedButton.styleFrom(
-                primary: isSelected ? AppTheme.tertiary : Colors.grey,
+                backgroundColor: isSelected ? AppTheme.tertiary : Colors.grey,
                 foregroundColor:
                     isSelected ? AppTheme.quaternary : AppTheme.secondary,
-                onPrimary: AppTheme.secondary,
+                // onbackgroundColor: AppTheme.secondary,
               ),
               child: Text(categoria.nombre!),
             ),

+ 2 - 2
lib/views/pedido/pedido_screen.dart

@@ -457,7 +457,7 @@ class _PedidoScreenState extends State<PedidoScreen> {
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(20.0),
                     ),
-                    primary: AppTheme.tertiary,
+                    backgroundColor: AppTheme.tertiary,
                     padding: const EdgeInsets.symmetric(vertical: 25),
                   ),
                   child: Text('Limpiar',
@@ -488,7 +488,7 @@ class _PedidoScreenState extends State<PedidoScreen> {
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(20.0),
                     ),
-                    primary: AppTheme.tertiary,
+                    backgroundColor: AppTheme.tertiary,
                     padding: const EdgeInsets.symmetric(vertical: 25),
                   ),
                   child: Text('Buscar',

+ 316 - 0
lib/views/pedido_mesa/pedido_mesa_detalle.dart

@@ -0,0 +1,316 @@
+import 'package:intl/intl.dart';
+import 'package:flutter/material.dart';
+import '../../models/models.dart';
+import '../../themes/themes.dart';
+import '../pedido/pedido_ticket.dart';
+
+class PedidoMesaDetalleScreen extends StatelessWidget {
+  final Pedido pedido;
+
+  const PedidoMesaDetalleScreen({Key? key, required this.pedido}) : super(key: key);
+
+  String formatCurrency(double amount) {
+    final format = NumberFormat("#,##0.00", "es_MX");
+    return format.format(amount);
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    double totalSinDescuento =
+        pedido.productos.fold(0, (previousValue, element) {
+      double productTotal = element.cantidad! *
+          (double.tryParse(element.producto?.precio ?? '') ?? 0.0);
+
+      double toppingsTotal = element.toppings.fold(0, (toppingTotal, topping) {
+        return toppingTotal +
+            (double.tryParse(topping.topping?.precio ?? '') ?? 0.0) *
+                element.cantidad!;
+      });
+
+      return previousValue + productTotal + toppingsTotal;
+    });
+
+    double descuento = pedido.descuento?.toDouble() ?? 0.0;
+    double precioDescuento = totalSinDescuento * (descuento / 100);
+    double totalConDescuento = totalSinDescuento - precioDescuento;
+
+    return Scaffold(
+      appBar: AppBar(
+        title: Text(
+          'Detalle del Pedido ${pedido.folio}',
+          style: TextStyle(fontWeight: FontWeight.w500),
+        ),
+      ),
+      body: SingleChildScrollView(
+        padding: const EdgeInsets.all(12.0),
+        child: Column(
+          children: [
+            Card(
+              elevation: 4,
+              color: Colors.white,
+              child: Column(
+                children: [
+                  ListTile(
+                    title: Text(
+                      'Cliente: ${pedido.nombreCliente}',
+                      style:
+                          TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
+                    ),
+                    subtitle: Text(
+                      'Comentarios: ${pedido.comentarios}',
+                      style:
+                          TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
+                    ),
+                  ),
+                  ListTile(
+                    title: Text(
+                      'Estado del Pedido: ${pedido.estatus}',
+                      style: TextStyle(
+                        fontSize: 22,
+                        fontWeight: FontWeight.bold,
+                      ),
+                    ),
+                  )
+                ],
+              ),
+            ),
+            SizedBox(height: 10),
+            Card(
+              elevation: 4,
+              color: Colors.white,
+              child: Padding(
+                padding: const EdgeInsets.all(8.0),
+                child: Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    Text('Productos',
+                        style: TextStyle(
+                            fontSize: 22, fontWeight: FontWeight.bold)),
+                    const SizedBox(height: 15),
+                    ListView.builder(
+                      shrinkWrap: true,
+                      physics: NeverScrollableScrollPhysics(),
+                      itemCount: pedido.productos.length,
+                      itemBuilder: (context, index) {
+                        final producto = pedido.productos[index];
+                        return Padding(
+                          padding: const EdgeInsets.symmetric(vertical: 4.0),
+                          child: Column(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              Row(
+                                children: [
+                                  Expanded(
+                                    flex: 6,
+                                    child: Text(
+                                      producto.producto?.nombre ??
+                                          "Producto no especificado",
+                                      style: TextStyle(
+                                          fontWeight: FontWeight.bold,
+                                          fontSize: 17),
+                                      overflow: TextOverflow.ellipsis,
+                                    ),
+                                  ),
+                                  Expanded(
+                                    flex: 1,
+                                    child: Text(
+                                      'x${producto.cantidad}',
+                                      style: TextStyle(
+                                          fontWeight: FontWeight.w500,
+                                          fontSize: 17),
+                                      textAlign: TextAlign.center,
+                                    ),
+                                  ),
+                                  Expanded(
+                                    flex: 2,
+                                    child: Text(
+                                      '\$${formatCurrency(double.tryParse(producto.producto?.precio ?? '0.0') ?? 0.0)}',
+                                      style: TextStyle(
+                                          fontWeight: FontWeight.w500,
+                                          fontSize: 17),
+                                      textAlign: TextAlign.right,
+                                    ),
+                                  ),
+                                ],
+                              ),
+                              if (producto.toppings.isNotEmpty)
+                                Padding(
+                                  padding: const EdgeInsets.only(top: 4.0),
+                                  child: Column(
+                                    crossAxisAlignment:
+                                        CrossAxisAlignment.start,
+                                    children: producto.toppings.map((topping) {
+                                      return Padding(
+                                        padding: const EdgeInsets.symmetric(
+                                            vertical: 2.0),
+                                        child: Row(
+                                          children: [
+                                            Text(
+                                              '- ${topping.topping?.nombre ?? "Topping no especificado"}',
+                                              style: TextStyle(
+                                                  fontSize: 15,
+                                                  color: Colors.grey[600]),
+                                            ),
+                                            Spacer(),
+                                            Text(
+                                              '\$${formatCurrency(double.tryParse(topping.topping?.precio ?? '0.0') ?? 0.0)}',
+                                              style: TextStyle(
+                                                  fontSize: 15,
+                                                  color: Colors.grey[600]),
+                                            ),
+                                          ],
+                                        ),
+                                      );
+                                    }).toList(),
+                                  ),
+                                ),
+                            ],
+                          ),
+                        );
+                      },
+                    ),
+                    Divider(),
+                    Padding(
+                      padding: const EdgeInsets.symmetric(vertical: 8.0),
+                      child: Column(
+                        crossAxisAlignment: CrossAxisAlignment.end,
+                        children: [
+                          Row(
+                            mainAxisAlignment: MainAxisAlignment.end,
+                            children: [
+                              const Text('Subtotal:',
+                                  style: TextStyle(
+                                      fontSize: 16,
+                                      fontWeight: FontWeight.bold)),
+                              const SizedBox(width: 5),
+                              Text('\$${formatCurrency(totalSinDescuento)}',
+                                  style: const TextStyle(
+                                      fontSize: 16,
+                                      fontWeight: FontWeight.bold)),
+                            ],
+                          ),
+                          if (descuento > 0) ...[
+                            Row(
+                              mainAxisAlignment: MainAxisAlignment.end,
+                              children: [
+                                Text(
+                                    'Descuento (${descuento.toStringAsFixed(0)}%):',
+                                    style: const TextStyle(
+                                        fontSize: 16,
+                                        fontWeight: FontWeight.bold)),
+                                const SizedBox(width: 8),
+                                Text('-\$${formatCurrency(precioDescuento)}',
+                                    style: const TextStyle(
+                                        fontSize: 16,
+                                        fontWeight: FontWeight.bold)),
+                              ],
+                            ),
+                          ],
+                          Row(
+                            mainAxisAlignment: MainAxisAlignment.end,
+                            children: [
+                              const Text('Total:',
+                                  style: TextStyle(
+                                      fontSize: 16,
+                                      fontWeight: FontWeight.bold)),
+                              const SizedBox(width: 5),
+                              Text('\$${formatCurrency(totalConDescuento)}',
+                                  style: const TextStyle(
+                                      fontSize: 16,
+                                      fontWeight: FontWeight.bold)),
+                            ],
+                          ),
+                        ],
+                      ),
+                    ),
+                  ],
+                ),
+              ),
+            ),
+            const SizedBox(height: 10),
+            Card(
+              elevation: 4,
+              color: Colors.white,
+              child: Padding(
+                padding: const EdgeInsets.all(8.0),
+                child: Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    Text('Pago',
+                        style: TextStyle(
+                            fontSize: 22, fontWeight: FontWeight.bold)),
+                    const SizedBox(height: 10),
+                    _buildPaymentDetails(),
+                  ],
+                ),
+              ),
+            ),
+            const SizedBox(height: 20),
+            Align(
+              alignment: Alignment.centerLeft,
+              child: ElevatedButton.icon(
+                icon: Icon(
+                  Icons.receipt_long_outlined,
+                  color: AppTheme.quaternary,
+                  size: 30,
+                ),
+                onPressed: () => imprimirTicketsJuntos(context, pedido),
+                label: Text(
+                  'Imprimir Ticket',
+                  style: TextStyle(
+                      fontWeight: FontWeight.w500,
+                      fontSize: 18,
+                      color: AppTheme.quaternary),
+                ),
+                style: ElevatedButton.styleFrom(
+                  padding: const EdgeInsets.fromLTRB(50, 20, 50, 20),
+                  backgroundColor: AppTheme.tertiary,
+                ),
+              ),
+            )
+          ],
+        ),
+      ),
+    );
+  }
+
+  Widget _buildPaymentDetails() {
+    List<Widget> paymentDetails = [];
+
+    if (pedido.cantEfectivo != null && pedido.cantEfectivo! > 0) {
+      paymentDetails.add(_buildPaymentRow("Efectivo", pedido.cantEfectivo!));
+    }
+    if (pedido.cantTarjeta != null && pedido.cantTarjeta! > 0) {
+      paymentDetails.add(_buildPaymentRow("Tarjeta", pedido.cantTarjeta!));
+    }
+    if (pedido.cantTransferencia != null && pedido.cantTransferencia! > 0) {
+      paymentDetails
+          .add(_buildPaymentRow("Transferencia", pedido.cantTransferencia!));
+    }
+    if (paymentDetails.isEmpty) {
+      paymentDetails.add(Text("No se especificaron métodos de pago.",
+          style: TextStyle(fontSize: 16, color: Colors.grey[600])));
+    }
+
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: paymentDetails,
+    );
+  }
+
+  Widget _buildPaymentRow(String paymentType, double amount) {
+    return Row(
+      mainAxisAlignment: MainAxisAlignment.spaceBetween,
+      children: [
+        Text(
+          paymentType,
+          style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
+        ),
+        Text(
+          '\$${formatCurrency(amount)}',
+          style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
+        ),
+      ],
+    );
+  }
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 1273 - 0
lib/views/pedido_mesa/pedido_mesa_form.dart


+ 498 - 0
lib/views/pedido_mesa/pedido_mesa_screen.dart

@@ -0,0 +1,498 @@
+import 'package:conalep_pos/models/models.dart';
+import 'package:conalep_pos/themes/themes.dart';
+import 'package:conalep_pos/viewmodels/viewmodels.dart';
+import 'package:conalep_pos/views/pedido_mesa/pedido_mesa_detalle.dart';
+import 'package:conalep_pos/views/pedido_mesa/pedido_mesa_form.dart';
+import 'package:conalep_pos/widgets/widgets.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import '../../widgets/widgets_components.dart' as clase;
+
+class PedidoMesaScreen extends StatefulWidget {
+  const PedidoMesaScreen({Key? key}) : super(key: key);
+
+  @override
+  State<PedidoMesaScreen> createState() => _PedidoMesaScreenState();
+}
+
+class _PedidoMesaScreenState extends State<PedidoMesaScreen> {
+  final _busqueda = TextEditingController(text: '');
+  DateTime? fechaInicio;
+  DateTime? fechaFin;
+  ScrollController horizontalScrollController = ScrollController();
+
+  @override
+  void initState() {
+    super.initState();
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      Provider.of<PedidoViewModel>(context, listen: false).fetchLocalMesaPedidosForScreen();
+    });
+  }
+
+  // void exportCSV() async {
+  //   final pedidosViewModel =
+  //       Provider.of<PedidoViewModel>(context, listen: false);
+  //   List<Pedido> pedidosConProductos = [];
+
+  //   for (Pedido pedido in pedidosViewModel.pedidos) {
+  //     Pedido? pedidoConProductos =
+  //         await pedidosViewModel.fetchPedidoConProductos(pedido.id);
+  //     if (pedidoConProductos != null) {
+  //       pedidosConProductos.add(pedidoConProductos);
+  //     }
+  //   }
+
+  //   if (pedidosConProductos.isNotEmpty) {
+  //     String fileName = 'Pedidos_OlivaMia_POS';
+  //     if (fechaInicio != null && fechaFin != null) {
+  //       String startDateStr = DateFormat('dd-MM-yyyy').format(fechaInicio!);
+  //       String endDateStr = DateFormat('dd-MM-yyyy').format(fechaFin!);
+  //       fileName += '_${startDateStr}_al_${endDateStr}';
+  //     }
+  //     fileName += '.csv';
+
+  //     await exportarPedidosACSV(pedidosConProductos, fileName);
+  //     ScaffoldMessenger.of(context).showSnackBar(SnackBar(
+  //         content: Text('Archivo CSV descargado! Archivo: $fileName')));
+  //   } else {
+  //     ScaffoldMessenger.of(context).showSnackBar(
+  //         SnackBar(content: Text('No hay pedidos para exportar.')));
+  //   }
+  // }
+
+  void clearSearchAndReset() {
+    setState(() {
+      _busqueda.clear();
+      fechaInicio = null;
+      fechaFin = null;
+      Provider.of<PedidoViewModel>(context, listen: false)
+          .fetchLocalPedidosForScreen();
+    });
+  }
+
+  void go(Pedido item) async {
+    Pedido? pedidoCompleto =
+        await Provider.of<PedidoViewModel>(context, listen: false)
+            .fetchPedidoConProductos(item.id);
+    if (pedidoCompleto != null) {
+      Navigator.push(
+        context,
+        MaterialPageRoute(
+          builder: (context) => PedidoMesaDetalleScreen(pedido: pedidoCompleto),
+        ),
+      );
+    } else {
+      print("Error al cargar el pedido con productos");
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final pvm = Provider.of<PedidoViewModel>(context);
+    double screenWidth = MediaQuery.of(context).size.width;
+    final isMobile = screenWidth < 1250;
+    final double? columnSpacing = isMobile ? null : 0;
+    TextStyle estilo = const TextStyle(fontWeight: FontWeight.bold);
+    List<DataRow> registros = [];
+    for (Pedido item in pvm.pedidos) {
+      registros.add(DataRow(cells: [
+        DataCell(
+            Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
+          PopupMenuButton(
+            itemBuilder: (context) => [
+              PopupMenuItem(
+                child: const Text('Detalle'),
+                onTap: () => go(item),
+              ),
+              PopupMenuItem(
+                child: const Text('Cancelar Pedido'),
+                onTap: () async {
+                  bool confirmado = await showDialog<bool>(
+                        context: context,
+                        builder: (context) {
+                          return AlertDialog(
+                            title: const Text("Cancelar Pedido",
+                                style: TextStyle(
+                                    fontWeight: FontWeight.w500, fontSize: 22)),
+                            content: const Text(
+                                '¿Estás seguro de que deseas cancelar este pedido?',
+                                style: TextStyle(fontSize: 18)),
+                            actions: [
+                              Row(
+                                mainAxisAlignment:
+                                    MainAxisAlignment.spaceBetween,
+                                children: [
+                                  TextButton(
+                                    onPressed: () =>
+                                        Navigator.of(context).pop(false),
+                                    child: const Text('No',
+                                        style: TextStyle(fontSize: 18)),
+                                    style: ButtonStyle(
+                                        padding: MaterialStatePropertyAll(
+                                            EdgeInsets.fromLTRB(
+                                                20, 10, 20, 10)),
+                                        backgroundColor:
+                                            MaterialStatePropertyAll(
+                                                Colors.red),
+                                        foregroundColor:
+                                            MaterialStatePropertyAll(
+                                                AppTheme.secondary)),
+                                  ),
+                                  TextButton(
+                                    onPressed: () =>
+                                        Navigator.of(context).pop(true),
+                                    child: const Text('Sí',
+                                        style: TextStyle(fontSize: 18)),
+                                    style: ButtonStyle(
+                                        padding: MaterialStatePropertyAll(
+                                            EdgeInsets.fromLTRB(
+                                                20, 10, 20, 10)),
+                                        backgroundColor:
+                                            MaterialStatePropertyAll(
+                                                AppTheme.tertiary),
+                                        foregroundColor:
+                                            MaterialStatePropertyAll(
+                                                AppTheme.quaternary)),
+                                  ),
+                                ],
+                              )
+                            ],
+                          );
+                        },
+                      ) ??
+                      false;
+
+                  if (confirmado) {
+                    await Provider.of<PedidoViewModel>(context, listen: false)
+                        .cancelarPedido(item.id);
+                    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
+                        content: Text("Pedido cancelado correctamente")));
+                  }
+                },
+              )
+            ],
+            icon: const Icon(Icons.more_vert),
+          )
+        ])),
+        DataCell(
+          Text(item.folio.toString()),
+          onTap: () => go(item),
+        ),
+        DataCell(
+          Text(item.nombreCliente ?? "Sin nombre"),
+          onTap: () => go(item),
+        ),
+        DataCell(
+          Text(item.comentarios ?? "Sin comentarios"),
+          onTap: () => go(item),
+        ),
+        DataCell(
+          Text(item.estatus ?? "Sin Estatus"),
+          onTap: () => go(item),
+        ),
+        DataCell(
+          Text(item.peticion ?? "Sin fecha"),
+          onTap: () => go(item),
+        ),
+      ]));
+    }
+
+    return Scaffold(
+      appBar: AppBar(
+          title: Text(
+            'Pedidos de Mesa',
+            style: TextStyle(
+                color: AppTheme.secondary, fontWeight: FontWeight.w500),
+          ),
+          // actions: <Widget>[
+          //   IconButton(
+          //     icon: const Icon(Icons.save_alt),
+          //     onPressed: exportCSV,
+          //     tooltip: 'Exportar a CSV',
+          //   ),
+          // ],
+          iconTheme: IconThemeData(color: AppTheme.secondary)),
+      floatingActionButton: FloatingActionButton.extended(
+        onPressed: () async {
+          await Navigator.push(
+            context,
+            MaterialPageRoute(
+              builder: (context) => PedidoMesaForm(),
+            ),
+          ).then((_) => Provider.of<PedidoViewModel>(context, listen: false)
+              .fetchLocalPedidosForScreen());
+        },
+        icon: Icon(Icons.add, size: 30, color: AppTheme.quaternary),
+        label: Text(
+          "Agregar Pedido",
+          style: TextStyle(fontSize: 20, color: AppTheme.quaternary),
+        ),
+        shape: RoundedRectangleBorder(
+          borderRadius: BorderRadius.circular(8),
+        ),
+        materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+        backgroundColor: AppTheme.tertiary,
+      ),
+      body: Column(
+        children: [
+          Expanded(
+            child: ListView(
+              padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
+              children: [
+                const SizedBox(height: 8),
+                clase.tarjeta(
+                  Padding(
+                    padding: const EdgeInsets.all(8.0),
+                    child: LayoutBuilder(
+                      builder: (context, constraints) {
+                        if (screenWidth > 1000) {
+                          return Row(
+                            crossAxisAlignment: CrossAxisAlignment.end,
+                            children: [
+                              Expanded(
+                                flex: 7,
+                                child: _buildDateRangePicker(),
+                              ),
+                              const SizedBox(width: 5),
+                              botonBuscar()
+                            ],
+                          );
+                        } else {
+                          return Column(
+                            children: [
+                              Row(
+                                children: [_buildDateRangePicker()],
+                              ),
+                              Row(
+                                children: [botonBuscar()],
+                              ),
+                            ],
+                          );
+                        }
+                      },
+                    ),
+                  ),
+                ),
+                const SizedBox(height: 8),
+                pvm.isLoading
+                    ? const Center(child: CircularProgressIndicator())
+                    : Container(),
+                clase.tarjeta(
+                  Column(
+                    children: [
+                      LayoutBuilder(builder: (context, constraints) {
+                        return SingleChildScrollView(
+                          scrollDirection: Axis.vertical,
+                          child: Scrollbar(
+                            controller: horizontalScrollController,
+                            interactive: true,
+                            thumbVisibility: true,
+                            thickness: 10.0,
+                            child: SingleChildScrollView(
+                              controller: horizontalScrollController,
+                              scrollDirection: Axis.horizontal,
+                              child: ConstrainedBox(
+                                constraints: BoxConstraints(
+                                    minWidth: isMobile
+                                        ? constraints.maxWidth
+                                        : screenWidth),
+                                child: DataTable(
+                                  columnSpacing: columnSpacing,
+                                  sortAscending: true,
+                                  sortColumnIndex: 1,
+                                  columns: [
+                                    DataColumn(label: Text(" ", style: estilo)),
+                                    DataColumn(
+                                        label: Text("FOLIO", style: estilo)),
+                                    DataColumn(
+                                        label: Text("NOMBRE", style: estilo)),
+                                    DataColumn(
+                                        label:
+                                            Text("COMENTARIOS", style: estilo)),
+                                    DataColumn(
+                                        label: Text("ESTATUS", style: estilo)),
+                                    DataColumn(
+                                        label: Text("FECHA", style: estilo)),
+                                  ],
+                                  rows: registros,
+                                ),
+                              ),
+                            ),
+                          ),
+                        );
+                      }),
+                    ],
+                  ),
+                ),
+                const SizedBox(height: 15),
+                if (!pvm.isLoading)
+                  Row(
+                    mainAxisAlignment: MainAxisAlignment.center,
+                    children: [
+                      TextButton(
+                        onPressed:
+                            pvm.currentPage > 1 ? pvm.previousPage : null,
+                        child: Text('Anterior'),
+                        style: ButtonStyle(
+                          backgroundColor:
+                              MaterialStateProperty.resolveWith<Color?>(
+                            (Set<MaterialState> states) {
+                              if (states.contains(MaterialState.disabled)) {
+                                return Colors.grey;
+                              }
+                              return AppTheme.tertiary;
+                            },
+                          ),
+                          foregroundColor:
+                              MaterialStateProperty.resolveWith<Color?>(
+                            (Set<MaterialState> states) {
+                              if (states.contains(MaterialState.disabled)) {
+                                return Colors.black;
+                              }
+                              return Colors.white;
+                            },
+                          ),
+                        ),
+                      ),
+                      SizedBox(width: 15),
+                      Text('Página ${pvm.currentPage} de ${pvm.totalPages}'),
+                      SizedBox(width: 15),
+                      TextButton(
+                        onPressed: pvm.currentPage < pvm.totalPages
+                            ? pvm.nextPage
+                            : null,
+                        child: Text('Siguiente'),
+                        style: ButtonStyle(
+                          backgroundColor:
+                              MaterialStateProperty.resolveWith<Color?>(
+                            (Set<MaterialState> states) {
+                              if (states.contains(MaterialState.disabled)) {
+                                return Colors.grey;
+                              }
+                              return AppTheme.tertiary;
+                            },
+                          ),
+                          foregroundColor:
+                              MaterialStateProperty.resolveWith<Color?>(
+                            (Set<MaterialState> states) {
+                              if (states.contains(MaterialState.disabled)) {
+                                return Colors.black;
+                              }
+                              return Colors.white;
+                            },
+                          ),
+                        ),
+                      ),
+                    ],
+                  ),
+                const SizedBox(height: 15),
+              ],
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+
+  Widget _buildDateRangePicker() {
+    return Row(
+      children: [
+        Expanded(
+          flex: 3,
+          child: AppTextField(
+            prefixIcon: const Icon(Icons.search),
+            etiqueta: 'Búsqueda por folio...',
+            controller: _busqueda,
+            hintText: 'Búsqueda por folio...',
+          ),
+        ),
+        const SizedBox(width: 5),
+        Expanded(
+          flex: 3,
+          child: clase.FechaSelectWidget(
+            fecha: fechaInicio,
+            onFechaChanged: (d) {
+              setState(() {
+                fechaInicio = d;
+              });
+            },
+            etiqueta: "Fecha Inicial",
+            context: context,
+          ),
+        ),
+        const SizedBox(width: 5),
+        Expanded(
+          flex: 3,
+          child: clase.FechaSelectWidget(
+            fecha: fechaFin,
+            onFechaChanged: (d) {
+              setState(() {
+                fechaFin = d;
+              });
+            },
+            etiqueta: "Fecha Final",
+            context: context,
+          ),
+        ),
+      ],
+    );
+  }
+
+  Widget botonBuscar() {
+    return Expanded(
+        flex: 2,
+        child: Row(
+          children: [
+            Expanded(
+              flex: 2,
+              child: Padding(
+                padding: const EdgeInsets.only(bottom: 5),
+                child: ElevatedButton(
+                  onPressed: clearSearchAndReset,
+                  style: ElevatedButton.styleFrom(
+                    shape: RoundedRectangleBorder(
+                      borderRadius: BorderRadius.circular(20.0),
+                    ),
+                    backgroundColor: AppTheme.tertiary,
+                    padding: const EdgeInsets.symmetric(vertical: 25),
+                  ),
+                  child: Text('Limpiar',
+                      style: TextStyle(color: AppTheme.quaternary)),
+                ),
+              ),
+            ),
+            const SizedBox(width: 8),
+            Expanded(
+              flex: 2,
+              child: Padding(
+                padding: const EdgeInsets.only(bottom: 5),
+                child: ElevatedButton(
+                  onPressed: () async {
+                    if (_busqueda.text.isNotEmpty) {
+                      await Provider.of<PedidoViewModel>(context, listen: false)
+                          .buscarPedidosPorFolio(_busqueda.text.trim());
+                    } else if (fechaInicio != null && fechaFin != null) {
+                      await Provider.of<PedidoViewModel>(context, listen: false)
+                          .buscarPedidosPorFecha(fechaInicio!, fechaFin!);
+                    } else {
+                      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
+                          content: Text(
+                              'Introduce un folio o selecciona un rango de fechas para buscar.')));
+                    }
+                  },
+                  style: ElevatedButton.styleFrom(
+                    shape: RoundedRectangleBorder(
+                      borderRadius: BorderRadius.circular(20.0),
+                    ),
+                    backgroundColor: AppTheme.tertiary,
+                    padding: const EdgeInsets.symmetric(vertical: 25),
+                  ),
+                  child: Text('Buscar',
+                      style: TextStyle(color: AppTheme.quaternary)),
+                ),
+              ),
+            ),
+          ],
+        ));
+  }
+}

+ 2 - 2
lib/views/producto/producto_form.dart

@@ -209,8 +209,8 @@ class Formulario extends State<ProductoForm> {
                           shape: RoundedRectangleBorder(
                               borderRadius:
                                   BorderRadius.all(Radius.circular(20))),
-                          primary: AppTheme.tertiary,
-                          onPrimary: AppTheme.quaternary,
+                          backgroundColor: AppTheme.tertiary,
+                          // onbackgroundColor: AppTheme.quaternary,
                         ),
                         child: Column(
                           mainAxisSize: MainAxisSize.min,

+ 2 - 2
lib/views/producto/producto_screen.dart

@@ -399,7 +399,7 @@ class _ProductoScreenState extends State<ProductoScreen> {
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(20.0),
                     ),
-                    primary: AppTheme.tertiary,
+                    backgroundColor: AppTheme.tertiary,
                     padding: const EdgeInsets.symmetric(vertical: 25),
                   ),
                   child: Text('Limpiar',
@@ -427,7 +427,7 @@ class _ProductoScreenState extends State<ProductoScreen> {
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(20.0),
                     ),
-                    primary: AppTheme.tertiary,
+                    backgroundColor: AppTheme.tertiary,
                     padding: const EdgeInsets.symmetric(vertical: 25),
                   ),
                   child: Text('Buscar',

+ 2 - 2
lib/views/variable/variable_screen.dart

@@ -368,7 +368,7 @@ class _VariablesScreenState extends State<VariablesScreen> {
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(20.0),
                     ),
-                    primary: AppTheme.tertiary,
+                    backgroundColor: AppTheme.tertiary,
                     padding: const EdgeInsets.symmetric(vertical: 25),
                   ),
                   child: Text('Limpiar',
@@ -396,7 +396,7 @@ class _VariablesScreenState extends State<VariablesScreen> {
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(20.0),
                     ),
-                    primary: AppTheme.tertiary,
+                    backgroundColor: AppTheme.tertiary,
                     padding: const EdgeInsets.symmetric(vertical: 25),
                   ),
                   child: Text('Buscar',

+ 1 - 1
lib/views/venta/venta_screen.dart

@@ -104,7 +104,7 @@ class _VentaScreenState extends State<VentaScreen> {
                         shape: RoundedRectangleBorder(
                           borderRadius: BorderRadius.circular(20.0),
                         ),
-                        primary: AppTheme.tertiary,
+                        backgroundColor: AppTheme.tertiary,
                         padding: const EdgeInsets.symmetric(vertical: 25),
                       ),
                       child: Text('Limpiar',

+ 26 - 0
lib/widgets/app_drawer.dart

@@ -3,7 +3,9 @@
 import 'package:conalep_pos/models/models.dart';
 import 'package:conalep_pos/views/categoria_producto/categoria_producto_screen.dart';
 import 'package:conalep_pos/views/corte_caja/corte_caja_screen.dart';
+import 'package:conalep_pos/views/mesa/mesa_screen.dart';
 import 'package:conalep_pos/views/pedido/pedido_screen.dart';
+import 'package:conalep_pos/views/pedido_mesa/pedido_mesa_screen.dart';
 import 'package:conalep_pos/views/producto/producto_screen.dart';
 import 'package:conalep_pos/views/venta/venta_screen.dart';
 import 'package:flutter/material.dart';
@@ -112,6 +114,18 @@ class AppDrawer extends StatelessWidget {
               },
             ),
             ListTile(
+              leading: circulo(const Icon(Icons.restaurant_menu)),
+              title: const Text('Pedidos Mesa'),
+              onTap: () => {
+                Navigator.pop(context),
+                Navigator.of(context).push(
+                  MaterialPageRoute(
+                    builder: (context) => const PedidoMesaScreen(),
+                  ),
+                ),
+              },
+            ),
+            ListTile(
               leading: circulo(const Icon(Icons.menu_book_rounded)),
               title: const Text('Productos'),
               onTap: () => {
@@ -187,6 +201,18 @@ class AppDrawer extends StatelessWidget {
                     ),
                   },
                 ),
+                ListTile(
+                  leading: circulo(const Icon(Icons.table_restaurant)),
+                  title: const Text('Mesas'),
+                  onTap: () => {
+                    Navigator.pop(context),
+                    Navigator.of(context).push(
+                      MaterialPageRoute(
+                        builder: (context) => MesasScreen(),
+                      ),
+                    ),
+                  },
+                ),
               ],
             ),
             // ListTile(

+ 2 - 2
lib/widgets/widgets_components.dart

@@ -193,7 +193,7 @@ Future<DateTime?> showDatetimePicker(BuildContext context, DateTime? fecha,
           ),
           textButtonTheme: TextButtonThemeData(
             style: TextButton.styleFrom(
-              primary: AppTheme.secondary,
+              backgroundColor: AppTheme.secondary,
             ),
           ),
         ),
@@ -224,7 +224,7 @@ Future<DateTime?> showDatetimePicker(BuildContext context, DateTime? fecha,
           ),
           textButtonTheme: TextButtonThemeData(
             style: TextButton.styleFrom(
-              primary: AppTheme.secondary,
+              backgroundColor: AppTheme.secondary,
             ),
           ),
         ),

+ 136 - 128
pubspec.lock

@@ -5,10 +5,10 @@ packages:
     dependency: transitive
     description:
       name: archive
-      sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
+      sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
       url: "https://pub.dev"
     source: hosted
-    version: "3.4.10"
+    version: "3.6.1"
   args:
     dependency: transitive
     description:
@@ -29,18 +29,18 @@ packages:
     dependency: transitive
     description:
       name: barcode
-      sha256: "1fe4a55344505850517ce72d4a3a7b9ccf51b0dc1631ee7e552f6eacc4947f96"
+      sha256: ab180ce22c6555d77d45f0178a523669db67f95856e3378259ef2ffeb43e6003
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.7"
+    version: "2.2.8"
   bidi:
     dependency: transitive
     description:
       name: bidi
-      sha256: "1a7d0c696324b2089f72e7671fd1f1f64fef44c980f3cebc84e803967c597b63"
+      sha256: "9a712c7ddf708f7c41b1923aa83648a3ed44cfd75b04f72d598c45e5be287f9d"
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.10"
+    version: "2.0.12"
   boolean_selector:
     dependency: transitive
     description:
@@ -53,42 +53,42 @@ packages:
     dependency: "direct main"
     description:
       name: camera
-      sha256: "9499cbc2e51d8eb0beadc158b288380037618ce4e30c9acbc4fae1ac3ecb5797"
+      sha256: dfa8fc5a1adaeb95e7a54d86a5bd56f4bb0e035515354c8ac6d262e35cec2ec8
       url: "https://pub.dev"
     source: hosted
-    version: "0.10.5+9"
+    version: "0.10.6"
   camera_android:
     dependency: transitive
     description:
       name: camera_android
-      sha256: "7b0aba6398afa8475e2bc9115d976efb49cf8db781e922572d443795c04a4f4f"
+      sha256: "32f04948a284b71d938fe275616faf4957d07f9b3aab8021bfc8c418301a289e"
       url: "https://pub.dev"
     source: hosted
-    version: "0.10.9+1"
+    version: "0.10.9+11"
   camera_avfoundation:
     dependency: transitive
     description:
       name: camera_avfoundation
-      sha256: "608b56b0880722f703871329c4d7d4c2f379c8e2936940851df7fc041abc6f51"
+      sha256: "7c28969a975a7eb2349bc2cb2dfe3ad218a33dba9968ecfb181ce08c87486655"
       url: "https://pub.dev"
     source: hosted
-    version: "0.9.13+10"
+    version: "0.9.17+3"
   camera_platform_interface:
     dependency: transitive
     description:
       name: camera_platform_interface
-      sha256: a250314a48ea337b35909a4c9d5416a208d736dcb01d0b02c6af122be66660b0
+      sha256: b3ede1f171532e0d83111fe0980b46d17f1aa9788a07a2fbed07366bbdbb9061
       url: "https://pub.dev"
     source: hosted
-    version: "2.7.4"
+    version: "2.8.0"
   camera_web:
     dependency: transitive
     description:
       name: camera_web
-      sha256: "9e9aba2fbab77ce2472924196ff8ac4dd8f9126c4f9a3096171cd1d870d6b26c"
+      sha256: "595f28c89d1fb62d77c73c633193755b781c6d2e0ebcd8dc25b763b514e6ba8f"
       url: "https://pub.dev"
     source: hosted
-    version: "0.3.3"
+    version: "0.3.5"
   characters:
     dependency: transitive
     description:
@@ -137,30 +137,22 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.18.0"
-  convert:
-    dependency: transitive
-    description:
-      name: convert
-      sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
-      url: "https://pub.dev"
-    source: hosted
-    version: "3.1.1"
   cross_file:
     dependency: transitive
     description:
       name: cross_file
-      sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e
+      sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
       url: "https://pub.dev"
     source: hosted
-    version: "0.3.3+8"
+    version: "0.3.4+2"
   crypto:
     dependency: transitive
     description:
       name: crypto
-      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
+      sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.3"
+    version: "3.0.5"
   csslib:
     dependency: transitive
     description:
@@ -213,10 +205,10 @@ packages:
     dependency: transitive
     description:
       name: ffi
-      sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
+      sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.0"
+    version: "2.1.3"
   file:
     dependency: transitive
     description:
@@ -229,10 +221,10 @@ packages:
     dependency: "direct main"
     description:
       name: file_picker
-      sha256: d1d0ac3966b36dc3e66eeefb40280c17feb87fa2099c6e22e6a1fc959327bd03
+      sha256: "167bb619cdddaa10ef2907609feb8a79c16dfa479d3afaf960f8e223f754bf12"
       url: "https://pub.dev"
     source: hosted
-    version: "8.0.0+1"
+    version: "8.1.2"
   flutter:
     dependency: "direct main"
     description: flutter
@@ -250,10 +242,10 @@ packages:
     dependency: transitive
     description:
       name: flutter_plugin_android_lifecycle
-      sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f"
+      sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda"
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.19"
+    version: "2.0.22"
   flutter_test:
     dependency: "direct dev"
     description: flutter
@@ -276,10 +268,10 @@ packages:
     dependency: "direct main"
     description:
       name: http
-      sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
+      sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
       url: "https://pub.dev"
     source: hosted
-    version: "1.2.0"
+    version: "1.2.2"
   http_parser:
     dependency: transitive
     description:
@@ -292,10 +284,10 @@ packages:
     dependency: "direct main"
     description:
       name: image
-      sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
+      sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8"
       url: "https://pub.dev"
     source: hosted
-    version: "4.1.7"
+    version: "4.2.0"
   intl:
     dependency: "direct main"
     description:
@@ -304,14 +296,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.19.0"
-  js:
-    dependency: transitive
-    description:
-      name: js
-      sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.6.7"
   json_annotation:
     dependency: transitive
     description:
@@ -320,30 +304,54 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "4.9.0"
+  leak_tracker:
+    dependency: transitive
+    description:
+      name: leak_tracker
+      sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
+      url: "https://pub.dev"
+    source: hosted
+    version: "10.0.5"
+  leak_tracker_flutter_testing:
+    dependency: transitive
+    description:
+      name: leak_tracker_flutter_testing
+      sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.5"
+  leak_tracker_testing:
+    dependency: transitive
+    description:
+      name: leak_tracker_testing
+      sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.1"
   matcher:
     dependency: transitive
     description:
       name: matcher
-      sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
+      sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
       url: "https://pub.dev"
     source: hosted
-    version: "0.12.16"
+    version: "0.12.16+1"
   material_color_utilities:
     dependency: transitive
     description:
       name: material_color_utilities
-      sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
+      sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
       url: "https://pub.dev"
     source: hosted
-    version: "0.5.0"
+    version: "0.11.1"
   meta:
     dependency: transitive
     description:
       name: meta
-      sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
+      sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
       url: "https://pub.dev"
     source: hosted
-    version: "1.10.0"
+    version: "1.15.0"
   nested:
     dependency: transitive
     description:
@@ -364,10 +372,10 @@ packages:
     dependency: transitive
     description:
       name: path
-      sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
+      sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
       url: "https://pub.dev"
     source: hosted
-    version: "1.8.3"
+    version: "1.9.0"
   path_parsing:
     dependency: transitive
     description:
@@ -380,26 +388,26 @@ packages:
     dependency: "direct main"
     description:
       name: path_provider
-      sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
+      sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.3"
+    version: "2.1.4"
   path_provider_android:
     dependency: transitive
     description:
       name: path_provider_android
-      sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d
+      sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.4"
+    version: "2.2.10"
   path_provider_foundation:
     dependency: transitive
     description:
       name: path_provider_foundation
-      sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
+      sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.2"
+    version: "2.4.0"
   path_provider_linux:
     dependency: transitive
     description:
@@ -420,26 +428,26 @@ packages:
     dependency: transitive
     description:
       name: path_provider_windows
-      sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
+      sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.1"
+    version: "2.3.0"
   pdf:
     dependency: "direct main"
     description:
       name: pdf
-      sha256: "243f05342fc0bdf140eba5b069398985cdbdd3dbb1d776cf43d5ea29cc570ba6"
+      sha256: "05df53f8791587402493ac97b9869d3824eccbc77d97855f4545cf72df3cae07"
       url: "https://pub.dev"
     source: hosted
-    version: "3.10.8"
+    version: "3.11.1"
   pdf_widget_wrapper:
     dependency: transitive
     description:
       name: pdf_widget_wrapper
-      sha256: e9d31fd7782ce28ae346b127ea7d1cd748d799bddee379f31191693610e23749
+      sha256: c930860d987213a3d58c7ec3b7ecf8085c3897f773e8dc23da9cae60a5d6d0f5
       url: "https://pub.dev"
     source: hosted
-    version: "1.0.1"
+    version: "1.0.4"
   petitparser:
     dependency: transitive
     description:
@@ -452,10 +460,10 @@ packages:
     dependency: transitive
     description:
       name: platform
-      sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
+      sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.4"
+    version: "3.1.5"
   plugin_platform_interface:
     dependency: transitive
     description:
@@ -464,22 +472,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.8"
-  pointycastle:
-    dependency: transitive
-    description:
-      name: pointycastle
-      sha256: "79fbafed02cfdbe85ef3fd06c7f4bc2cbcba0177e61b765264853d4253b21744"
-      url: "https://pub.dev"
-    source: hosted
-    version: "3.9.0"
   printing:
     dependency: "direct main"
     description:
       name: printing
-      sha256: "1c99cab90ebcc1fff65831d264627d5b529359d563e53f33ab9b8117f2d280bc"
+      sha256: b576764370c920b510cedf3eac7dc199d6d4af34336d608e97546392c0113362
       url: "https://pub.dev"
     source: hosted
-    version: "5.12.0"
+    version: "5.13.3"
   provider:
     dependency: "direct main"
     description:
@@ -492,66 +492,66 @@ packages:
     dependency: transitive
     description:
       name: qr
-      sha256: "64957a3930367bf97cc211a5af99551d630f2f4625e38af10edd6b19131b64b3"
+      sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445"
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.1"
+    version: "3.0.2"
   shared_preferences:
     dependency: "direct main"
     description:
       name: shared_preferences
-      sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180
+      sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.3"
+    version: "2.3.2"
   shared_preferences_android:
     dependency: transitive
     description:
       name: shared_preferences_android
-      sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
+      sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.2"
+    version: "2.3.2"
   shared_preferences_foundation:
     dependency: transitive
     description:
       name: shared_preferences_foundation
-      sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
+      sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.5"
+    version: "2.5.2"
   shared_preferences_linux:
     dependency: transitive
     description:
       name: shared_preferences_linux
-      sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
+      sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.2"
+    version: "2.4.1"
   shared_preferences_platform_interface:
     dependency: transitive
     description:
       name: shared_preferences_platform_interface
-      sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
+      sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.2"
+    version: "2.4.1"
   shared_preferences_web:
     dependency: transitive
     description:
       name: shared_preferences_web
-      sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
+      sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.2"
+    version: "2.4.2"
   shared_preferences_windows:
     dependency: transitive
     description:
       name: shared_preferences_windows
-      sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
+      sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.2"
+    version: "2.4.1"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -577,34 +577,34 @@ packages:
     dependency: "direct main"
     description:
       name: sqflite
-      sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6
+      sha256: ff5a2436ef8ebdfda748fbfe957f9981524cb5ff11e7bafa8c42771840e8a788
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.2"
+    version: "2.3.3+2"
   sqflite_common:
     dependency: transitive
     description:
       name: sqflite_common
-      sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5"
+      sha256: "2d8e607db72e9cb7748c9c6e739e2c9618320a5517de693d5a24609c4671b1a4"
       url: "https://pub.dev"
     source: hosted
-    version: "2.5.3"
+    version: "2.5.4+4"
   sqflite_common_ffi:
     dependency: "direct main"
     description:
       name: sqflite_common_ffi
-      sha256: "754927d82de369a6b9e760fb60640aa81da650f35ffd468d5a992814d6022908"
+      sha256: a6057d4c87e9260ba1ec436ebac24760a110589b9c0a859e128842eb69a7ef04
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.2+1"
+    version: "2.3.3+1"
   sqlite3:
     dependency: transitive
     description:
       name: sqlite3
-      sha256: "072128763f1547e3e9b4735ce846bfd226d68019ccda54db4cd427b12dfdedc9"
+      sha256: "45f168ae2213201b54e09429ed0c593dc2c88c924a1488d6f9c523a255d567cb"
       url: "https://pub.dev"
     source: hosted
-    version: "2.4.0"
+    version: "2.4.6"
   stack_trace:
     dependency: transitive
     description:
@@ -641,10 +641,10 @@ packages:
     dependency: transitive
     description:
       name: synchronized
-      sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558"
+      sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.0+1"
+    version: "3.3.0+3"
   term_glyph:
     dependency: transitive
     description:
@@ -657,18 +657,18 @@ packages:
     dependency: transitive
     description:
       name: test_api
-      sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
+      sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
       url: "https://pub.dev"
     source: hosted
-    version: "0.6.1"
+    version: "0.7.2"
   timezone:
     dependency: "direct main"
     description:
       name: timezone
-      sha256: a6ccda4a69a442098b602c44e61a1e2b4bf6f5516e875bbf0f427d5df14745d5
+      sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
       url: "https://pub.dev"
     source: hosted
-    version: "0.9.3"
+    version: "0.9.4"
   typed_data:
     dependency: transitive
     description:
@@ -697,42 +697,42 @@ packages:
     dependency: "direct main"
     description:
       name: url_launcher
-      sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e"
+      sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
       url: "https://pub.dev"
     source: hosted
-    version: "6.2.6"
+    version: "6.3.0"
   url_launcher_android:
     dependency: transitive
     description:
       name: url_launcher_android
-      sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775"
+      sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab
       url: "https://pub.dev"
     source: hosted
-    version: "6.3.1"
+    version: "6.3.10"
   url_launcher_ios:
     dependency: transitive
     description:
       name: url_launcher_ios
-      sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03"
+      sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
       url: "https://pub.dev"
     source: hosted
-    version: "6.2.4"
+    version: "6.3.1"
   url_launcher_linux:
     dependency: transitive
     description:
       name: url_launcher_linux
-      sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811
+      sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.1"
+    version: "3.2.0"
   url_launcher_macos:
     dependency: transitive
     description:
       name: url_launcher_macos
-      sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
+      sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.0"
+    version: "3.2.1"
   url_launcher_platform_interface:
     dependency: transitive
     description:
@@ -745,18 +745,18 @@ packages:
     dependency: transitive
     description:
       name: url_launcher_web
-      sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b
+      sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.3"
+    version: "2.3.3"
   url_launcher_windows:
     dependency: transitive
     description:
       name: url_launcher_windows
-      sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7
+      sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.1"
+    version: "3.1.2"
   vector_math:
     dependency: transitive
     description:
@@ -765,22 +765,30 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.4"
+  vm_service:
+    dependency: transitive
+    description:
+      name: vm_service
+      sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "14.2.5"
   web:
     dependency: transitive
     description:
       name: web
-      sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
+      sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
       url: "https://pub.dev"
     source: hosted
-    version: "0.3.0"
+    version: "1.1.0"
   win32:
     dependency: transitive
     description:
       name: win32
-      sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
+      sha256: "4d45dc9069dba4619dc0ebd93c7cec5e66d8482cb625a370ac806dcc8165f2ec"
       url: "https://pub.dev"
     source: hosted
-    version: "5.2.0"
+    version: "5.5.5"
   xdg_directories:
     dependency: transitive
     description:
@@ -806,5 +814,5 @@ packages:
     source: hosted
     version: "3.1.2"
 sdks:
-  dart: ">=3.2.3 <4.0.0"
-  flutter: ">=3.16.0"
+  dart: ">=3.5.0 <4.0.0"
+  flutter: ">=3.24.0"