Bladeren bron

Buscador y listado de productos

OscarGil03 8 maanden geleden
bovenliggende
commit
42f27efa06

+ 4 - 7
lib/viewmodels/producto_view_model.dart

@@ -78,17 +78,14 @@ class ProductoViewModel<T> extends ChangeNotifier {
 
 
   Future<void> fetchLocalByName({required String nombre}) async {
   Future<void> fetchLocalByName({required String nombre}) async {
     var db = await RepoService().db;
     var db = await RepoService().db;
+    // Realiza la búsqueda sin filtrar por categoría
     var query = await db!.query(
     var query = await db!.query(
       'Producto',
       'Producto',
-      where: 'nombre LIKE "%$nombre%"',
+      where: 'nombre LIKE ?',
+      whereArgs: ['%$nombre%'],
       orderBy: 'idLocal asc',
       orderBy: 'idLocal asc',
     );
     );
-    List<Producto> aux = [];
-    for (var element in query) {
-      Producto producto = Producto.fromJson(element);
-      aux.add(producto);
-    }
-    _productos = aux;
+    _productos = query.map((e) => Producto.fromJson(e)).toList();
     notifyListeners();
     notifyListeners();
   }
   }
 
 

+ 91 - 75
lib/views/pedido/pedido_form.dart

@@ -31,7 +31,8 @@ class _PedidoFormState extends State<PedidoForm> {
   Producto? _productoActual;
   Producto? _productoActual;
   bool _estadoBusqueda = false;
   bool _estadoBusqueda = false;
   Pedido? pedidoActual;
   Pedido? pedidoActual;
-  ScrollController _gridViewController = ScrollController();
+  ScrollController _listViewController = ScrollController();
+  ScrollController _categoryScrollController = ScrollController();
   final _searchController = TextEditingController();
   final _searchController = TextEditingController();
   final NumberFormat _numberFormat = NumberFormat.decimalPattern('es_MX');
   final NumberFormat _numberFormat = NumberFormat.decimalPattern('es_MX');
   int? selectedDescuento = 0;
   int? selectedDescuento = 0;
@@ -91,10 +92,17 @@ class _PedidoFormState extends State<PedidoForm> {
     Provider.of<DescuentoViewModel>(context, listen: false).cargarDescuentos();
     Provider.of<DescuentoViewModel>(context, listen: false).cargarDescuentos();
   }
   }
 
 
-  _onSearchChanged(String value) {
+  void _onSearchChanged(String value) {
     if (value.isEmpty) {
     if (value.isEmpty) {
-      cargarProductosIniciales();
+      // Si no hay valor de búsqueda, cargar los productos iniciales y restaurar la categoría seleccionada.
+      cargarProductosPorCategoria(
+          categoriaSeleccionada?.id ?? categorias.first.id);
     } else {
     } else {
+      // Realiza la búsqueda y desactiva la categoría seleccionada para mostrar productos de todas las categorías.
+      setState(() {
+        _estadoBusqueda = true; // Indicamos que hay una búsqueda activa
+        categoriaSeleccionada = null; // Ignoramos la categoría seleccionada
+      });
       Provider.of<ProductoViewModel>(context, listen: false)
       Provider.of<ProductoViewModel>(context, listen: false)
           .fetchLocalByName(nombre: value);
           .fetchLocalByName(nombre: value);
     }
     }
@@ -585,8 +593,9 @@ class _PedidoFormState extends State<PedidoForm> {
 
 
   @override
   @override
   void dispose() {
   void dispose() {
-    _gridViewController.dispose();
+    _listViewController.dispose();
     _searchController.dispose();
     _searchController.dispose();
+    _categoryScrollController.dispose();
     super.dispose();
     super.dispose();
   }
   }
 
 
@@ -1019,69 +1028,55 @@ class _PedidoFormState extends State<PedidoForm> {
   Widget _buildProductsSection() {
   Widget _buildProductsSection() {
     return Column(
     return Column(
       children: [
       children: [
+        const SizedBox(height: 5),
+        _buildSearchBar(),
         const SizedBox(height: 10),
         const SizedBox(height: 10),
         _buildCategoryButtons(),
         _buildCategoryButtons(),
         const SizedBox(height: 15),
         const SizedBox(height: 15),
         Expanded(
         Expanded(
           child: Consumer<ProductoViewModel>(builder: (context, model, child) {
           child: Consumer<ProductoViewModel>(builder: (context, model, child) {
             productos = model.productos;
             productos = model.productos;
-            return GridView.builder(
-              controller: _gridViewController,
-              key: ValueKey<int>(categoriaSeleccionada?.id ?? 0),
-              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
-                crossAxisCount: 3,
-                childAspectRatio: 3 / 2,
-              ),
-              itemCount: productos.length,
-              itemBuilder: (context, index) {
-                final producto = productos[index];
-                if (producto.idCategoria != categoriaSeleccionada?.id) {
-                  return Container();
-                }
-                return Card(
-                  child: InkWell(
-                    onTap: () => agregarAlCarrito(producto),
-                    child: Column(
-                      mainAxisAlignment: MainAxisAlignment.center,
-                      children: [
-                        if (producto.imagen != null &&
-                            File(producto.imagen!).existsSync())
-                          Image.file(
-                            File(producto.imagen!),
-                            height: 120,
-                            fit: BoxFit.cover,
-                          )
-                        else
-                          const Icon(Icons.fastfood, size: 80),
-                        const SizedBox(height: 8),
-                        Padding(
-                          padding: const EdgeInsets.symmetric(horizontal: 8.0),
-                          child: Text(
+            return Scrollbar(
+              controller: _listViewController,
+              thumbVisibility: true,
+              trackVisibility: true,
+              child: ListView.builder(
+                controller: _listViewController,
+                itemCount: productos.length,
+                itemBuilder: (context, index) {
+                  final producto = productos[index];
+                  return Card(
+                    child: ListTile(
+                      title: Row(
+                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                        children: [
+                          Text(
                             producto.nombre ?? '',
                             producto.nombre ?? '',
                             style: const TextStyle(
                             style: const TextStyle(
                               fontSize: 16,
                               fontSize: 16,
                               fontWeight: FontWeight.bold,
                               fontWeight: FontWeight.bold,
                             ),
                             ),
-                            textAlign: TextAlign.center,
+                            textAlign: TextAlign.left,
                           ),
                           ),
-                        ),
-                        const SizedBox(height: 8),
-                        Text(
-                          '\$${producto.precio}',
-                          style: const TextStyle(
-                            fontSize: 16,
-                            fontWeight: FontWeight.bold,
-                            color: Color(0xFF008000),
+                          Text(
+                            '\$${producto.precio}',
+                            style: const TextStyle(
+                              fontSize: 16,
+                              fontWeight: FontWeight.bold,
+                              color: Colors.green,
+                            ),
+                            textAlign: TextAlign.right,
                           ),
                           ),
-                        ),
-                      ],
+                        ],
+                      ),
+                      onTap: () => agregarAlCarrito(producto),
                     ),
                     ),
-                  ),
-                );
-              },
+                  );
+                },
+              ),
             );
             );
           }),
           }),
-        )
+        ),
       ],
       ],
     );
     );
   }
   }
@@ -1092,31 +1087,38 @@ class _PedidoFormState extends State<PedidoForm> {
 
 
     return Container(
     return Container(
       height: 50,
       height: 50,
-      child: ListView.builder(
-        scrollDirection: Axis.horizontal,
-        itemCount: categoriasFiltradas.length,
-        itemBuilder: (context, index) {
-          final categoria = categoriasFiltradas[index];
-          bool isSelected = categoriaSeleccionada?.id == categoria.id;
-          return Padding(
-            padding: const EdgeInsets.symmetric(horizontal: 4.0),
-            child: ElevatedButton(
-              onPressed: () {
-                cargarProductosPorCategoria(categoria.id);
-                setState(() {
-                  categoriaSeleccionada = categoria;
-                });
-              },
-              style: ElevatedButton.styleFrom(
-                primary: isSelected ? AppTheme.tertiary : Colors.grey,
-                foregroundColor:
-                    isSelected ? AppTheme.quaternary : AppTheme.secondary,
-                onPrimary: AppTheme.secondary,
+      child: Scrollbar(
+        thumbVisibility: true,
+        trackVisibility: true,
+        interactive: true,
+        controller: _categoryScrollController,
+        child: ListView.builder(
+          controller: _categoryScrollController,
+          scrollDirection: Axis.horizontal,
+          itemCount: categoriasFiltradas.length,
+          itemBuilder: (context, index) {
+            final categoria = categoriasFiltradas[index];
+            bool isSelected = categoriaSeleccionada?.id == categoria.id;
+            return Padding(
+              padding: const EdgeInsets.symmetric(horizontal: 4.0),
+              child: ElevatedButton(
+                onPressed: () {
+                  cargarProductosPorCategoria(categoria.id);
+                  setState(() {
+                    categoriaSeleccionada = categoria;
+                  });
+                },
+                style: ElevatedButton.styleFrom(
+                  primary: isSelected ? AppTheme.tertiary : Colors.grey,
+                  foregroundColor:
+                      isSelected ? AppTheme.quaternary : AppTheme.secondary,
+                  onPrimary: AppTheme.secondary,
+                ),
+                child: Text(categoria.nombre!),
               ),
               ),
-              child: Text(categoria.nombre!),
-            ),
-          );
-        },
+            );
+          },
+        ),
       ),
       ),
     );
     );
   }
   }
@@ -1129,9 +1131,23 @@ class _PedidoFormState extends State<PedidoForm> {
         decoration: InputDecoration(
         decoration: InputDecoration(
           hintText: 'Buscar producto...',
           hintText: 'Buscar producto...',
           prefixIcon: const Icon(Icons.search),
           prefixIcon: const Icon(Icons.search),
+          suffixIcon: IconButton(
+            icon: Icon(Icons.clear),
+            onPressed: () {
+              _searchController.clear();
+              _onSearchChanged('');
+            },
+          ),
           border: OutlineInputBorder(
           border: OutlineInputBorder(
             borderRadius: BorderRadius.circular(12.0),
             borderRadius: BorderRadius.circular(12.0),
           ),
           ),
+          enabledBorder: OutlineInputBorder(
+              borderRadius: BorderRadius.circular(12.0),
+              borderSide: BorderSide(width: 1.5)),
+          focusedBorder: OutlineInputBorder(
+            borderSide: BorderSide(color: Colors.black),
+            borderRadius: BorderRadius.circular(12.0),
+          ),
         ),
         ),
         onChanged: _onSearchChanged,
         onChanged: _onSearchChanged,
       ),
       ),

+ 20 - 16
lib/views/pedido/pedido_ticket.dart

@@ -210,15 +210,15 @@ pw.Page generarPaginaSegundoTicket(Pedido pedido) {
       mainAxisAlignment: pw.MainAxisAlignment.spaceAround,
       mainAxisAlignment: pw.MainAxisAlignment.spaceAround,
       children: [
       children: [
         pw.Text('${pedido.folio}',
         pw.Text('${pedido.folio}',
-            style: pw.TextStyle(fontSize: 9, fontWeight: pw.FontWeight.bold)),
+            style: pw.TextStyle(fontSize: 12, fontWeight: pw.FontWeight.bold)),
         pw.Text('${pedido.peticion}',
         pw.Text('${pedido.peticion}',
-            style: pw.TextStyle(fontSize: 9, fontWeight: pw.FontWeight.bold)),
+            style: pw.TextStyle(fontSize: 12, fontWeight: pw.FontWeight.bold)),
       ],
       ],
     ),
     ),
     pw.SizedBox(height: 5),
     pw.SizedBox(height: 5),
     if (pedido.nombreCliente != null && pedido.nombreCliente!.isNotEmpty)
     if (pedido.nombreCliente != null && pedido.nombreCliente!.isNotEmpty)
       pw.Text('Cliente: ${pedido.nombreCliente}',
       pw.Text('Cliente: ${pedido.nombreCliente}',
-          style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 9)),
+          style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 12)),
     pw.SizedBox(height: 10),
     pw.SizedBox(height: 10),
   ];
   ];
 
 
@@ -241,14 +241,14 @@ pw.Page generarPaginaSegundoTicket(Pedido pedido) {
                 flex: 3,
                 flex: 3,
                 child: pw.Text(
                 child: pw.Text(
                     '-${topping.topping?.nombre ?? "Topping no especificado"}',
                     '-${topping.topping?.nombre ?? "Topping no especificado"}',
-                    style: const pw.TextStyle(fontSize: 7)),
+                    style: const pw.TextStyle(fontSize: 9)),
               ),
               ),
               if (toppingPrice > 0)
               if (toppingPrice > 0)
                 pw.Expanded(
                 pw.Expanded(
                   flex: 1,
                   flex: 1,
                   child: pw.Text(
                   child: pw.Text(
                     '\$${numberFormat.format(toppingTotal)}',
                     '\$${numberFormat.format(toppingTotal)}',
-                    style: const pw.TextStyle(fontSize: 7),
+                    style: const pw.TextStyle(fontSize: 9),
                     textAlign: pw.TextAlign.right,
                     textAlign: pw.TextAlign.right,
                   ),
                   ),
                 ),
                 ),
@@ -263,19 +263,19 @@ pw.Page generarPaginaSegundoTicket(Pedido pedido) {
               pw.Expanded(
               pw.Expanded(
                 flex: 1,
                 flex: 1,
                 child: pw.Text('${producto.cantidad}',
                 child: pw.Text('${producto.cantidad}',
-                    style: const pw.TextStyle(fontSize: 9)),
+                    style: const pw.TextStyle(fontSize: 12)),
               ),
               ),
               pw.Expanded(
               pw.Expanded(
                 flex: 3,
                 flex: 3,
                 child: pw.Text(
                 child: pw.Text(
                     producto.producto?.nombre ?? "Producto no especificado",
                     producto.producto?.nombre ?? "Producto no especificado",
-                    style: const pw.TextStyle(fontSize: 9)),
+                    style: const pw.TextStyle(fontSize: 11)),
               ),
               ),
               pw.Expanded(
               pw.Expanded(
                 flex: 2,
                 flex: 2,
                 child: pw.Text(
                 child: pw.Text(
                   '\$${numberFormat.format(productTotal)}',
                   '\$${numberFormat.format(productTotal)}',
-                  style: const pw.TextStyle(fontSize: 9),
+                  style: const pw.TextStyle(fontSize: 12),
                   textAlign: pw.TextAlign.right,
                   textAlign: pw.TextAlign.right,
                 ),
                 ),
               ),
               ),
@@ -299,18 +299,22 @@ pw.Page generarPaginaSegundoTicket(Pedido pedido) {
         mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
         mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
         children: [
         children: [
           pw.Text('Subtotal:',
           pw.Text('Subtotal:',
-              style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 9)),
+              style:
+                  pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 12)),
           pw.Text('\$${numberFormat.format(subtotal)}',
           pw.Text('\$${numberFormat.format(subtotal)}',
-              style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 9)),
+              style:
+                  pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 12)),
         ],
         ],
       ),
       ),
       pw.Row(
       pw.Row(
         mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
         mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
         children: [
         children: [
           pw.Text('Descuento:',
           pw.Text('Descuento:',
-              style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 9)),
+              style:
+                  pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 12)),
           pw.Text('-\$${numberFormat.format(precioDescuento)}',
           pw.Text('-\$${numberFormat.format(precioDescuento)}',
-              style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 9)),
+              style:
+                  pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 12)),
         ],
         ],
       ),
       ),
     ]);
     ]);
@@ -321,10 +325,10 @@ pw.Page generarPaginaSegundoTicket(Pedido pedido) {
       mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
       mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
       children: [
       children: [
         pw.Text('Total:',
         pw.Text('Total:',
-            style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 9)),
+            style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 12)),
         pw.Text(
         pw.Text(
             '\$${numberFormat.format(descuento > 0 ? totalConDescuento : subtotal)}',
             '\$${numberFormat.format(descuento > 0 ? totalConDescuento : subtotal)}',
-            style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 9)),
+            style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 12)),
       ],
       ],
     ),
     ),
   );
   );
@@ -332,11 +336,11 @@ pw.Page generarPaginaSegundoTicket(Pedido pedido) {
   if (pedido.comentarios != null && pedido.comentarios!.isNotEmpty) {
   if (pedido.comentarios != null && pedido.comentarios!.isNotEmpty) {
     content.add(pw.SizedBox(height: 10));
     content.add(pw.SizedBox(height: 10));
     content.add(pw.Text('Comentarios:',
     content.add(pw.Text('Comentarios:',
-        style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 9)));
+        style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 12)));
     content.add(pw.Padding(
     content.add(pw.Padding(
       padding: const pw.EdgeInsets.only(right: 15),
       padding: const pw.EdgeInsets.only(right: 15),
       child:
       child:
-          pw.Text(pedido.comentarios!, style: const pw.TextStyle(fontSize: 9)),
+          pw.Text(pedido.comentarios!, style: const pw.TextStyle(fontSize: 12)),
     ));
     ));
     content.add(pw.Text('.', style: pw.TextStyle(fontSize: 1)));
     content.add(pw.Text('.', style: pw.TextStyle(fontSize: 1)));
     content.add(pw.Text('.', style: pw.TextStyle(fontSize: 1)));
     content.add(pw.Text('.', style: pw.TextStyle(fontSize: 1)));

+ 13 - 13
lib/widgets/app_drawer.dart

@@ -147,18 +147,18 @@ class AppDrawer extends StatelessWidget {
                 ),
                 ),
               },
               },
             ),
             ),
-            ListTile(
-              leading: circulo(const Icon(Icons.point_of_sale_rounded)),
-              title: const Text('Corte De Caja'),
-              onTap: () => {
-                Navigator.pop(context),
-                Navigator.of(context).push(
-                  MaterialPageRoute(
-                    builder: (context) => CorteCajaScreen(),
-                  ),
-                ),
-              },
-            ),
+            // ListTile(
+            //   leading: circulo(const Icon(Icons.point_of_sale_rounded)),
+            //   title: const Text('Corte De Caja'),
+            //   onTap: () => {
+            //     Navigator.pop(context),
+            //     Navigator.of(context).push(
+            //       MaterialPageRoute(
+            //         builder: (context) => CorteCajaScreen(),
+            //       ),
+            //     ),
+            //   },
+            // ),
             ExpansionTile(
             ExpansionTile(
               leading: circulo(const Icon(Icons.admin_panel_settings)),
               leading: circulo(const Icon(Icons.admin_panel_settings)),
               title: const Text('Administración'),
               title: const Text('Administración'),
@@ -202,7 +202,7 @@ class AppDrawer extends StatelessWidget {
               child: Align(
               child: Align(
                 alignment: Alignment.bottomCenter,
                 alignment: Alignment.bottomCenter,
                 child: Text(
                 child: Text(
-                  'v1.24.08.22',
+                  'v1.24.08.27',
                   style: TextStyle(fontWeight: FontWeight.w300),
                   style: TextStyle(fontWeight: FontWeight.w300),
                 ),
                 ),
               ))
               ))