From 02adba50499af7324208fc4ce669e21311e584f2 Mon Sep 17 00:00:00 2001 From: nayeli92433 Date: Thu, 1 Aug 2024 13:41:05 -0600 Subject: [PATCH] Listado de categorias --- android/app/build.gradle | 1 + lib/config/routes.dart | 12 ------------ lib/config/rutas.dart | 12 ++++++++++++ lib/environments/archivo.dart | 1 + lib/main.dart | 3 ++- lib/src/controllers/CategoriaController.dart | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/src/http_api/CategoryApi.dart | 39 +++++++++++++++++++++++++++++++++++++++ lib/src/models/ArticuloModel.dart | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/src/models/CategoriaModel.dart | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/src/pages/category/CategoryListWidget.dart | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/src/pages/home_page.dart | 54 ++++++++---------------------------------------------- lib/src/shared_widgets/widget_mensajes.dart | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/src/specific_widgets/menu.dart | 46 ++++++++++++++++++++++++++++++++++++++++++++++ macos/Flutter/GeneratedPluginRegistrant.swift | 2 ++ pubspec.lock | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pubspec.yaml | 7 +++++++ windows/flutter/generated_plugin_registrant.cc | 3 +++ windows/flutter/generated_plugins.cmake | 1 + 18 files changed, 548 insertions(+), 59 deletions(-) delete mode 100644 lib/config/routes.dart create mode 100644 lib/config/rutas.dart create mode 100644 lib/environments/archivo.dart create mode 100644 lib/src/controllers/CategoriaController.dart create mode 100644 lib/src/http_api/CategoryApi.dart create mode 100644 lib/src/models/ArticuloModel.dart create mode 100644 lib/src/models/CategoriaModel.dart create mode 100644 lib/src/pages/category/CategoryListWidget.dart create mode 100644 lib/src/shared_widgets/widget_mensajes.dart create mode 100644 lib/src/specific_widgets/menu.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index c7dc696..0c1896e 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,3 +1,4 @@ + plugins { id "com.android.application" id "kotlin-android" diff --git a/lib/config/routes.dart b/lib/config/routes.dart deleted file mode 100644 index aaa4c02..0000000 --- a/lib/config/routes.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter/material.dart'; -import '../src/pages/articles_page.dart'; -import '../src/pages/home_page.dart'; -import '../src/pages/login_page.dart'; - -Map getApplicationRoutes() { - return { - 'login': (context) => const LoginPage(), - 'home': (context) => const HomePage(), - 'articles': (context) => const ArticlesPage(), - }; -} diff --git a/lib/config/rutas.dart b/lib/config/rutas.dart new file mode 100644 index 0000000..aaa4c02 --- /dev/null +++ b/lib/config/rutas.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; +import '../src/pages/articles_page.dart'; +import '../src/pages/home_page.dart'; +import '../src/pages/login_page.dart'; + +Map getApplicationRoutes() { + return { + 'login': (context) => const LoginPage(), + 'home': (context) => const HomePage(), + 'articles': (context) => const ArticlesPage(), + }; +} diff --git a/lib/environments/archivo.dart b/lib/environments/archivo.dart new file mode 100644 index 0000000..1a692be --- /dev/null +++ b/lib/environments/archivo.dart @@ -0,0 +1 @@ +const apiApp = 'https://basic2.visorus.com.mx'; \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 1b404bd..91e3043 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; -import 'config/routes.dart'; +import 'config/rutas.dart'; void main() { runApp(const MyApp()); } + class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); diff --git a/lib/src/controllers/CategoriaController.dart b/lib/src/controllers/CategoriaController.dart new file mode 100644 index 0000000..f331fd7 --- /dev/null +++ b/lib/src/controllers/CategoriaController.dart @@ -0,0 +1,53 @@ +import 'dart:convert'; +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:miapp_flutter/src/models/CategoriaModel.dart'; + +import '../http_api/CategoryApi.dart'; + +class CategoryController { + final Connectivity _connectivity = Connectivity(); + final CategoryApi _categoryApi = CategoryApi(); + + Future> getCategories() async { + Map mapResp = { + 'ok': false, + 'message': 'No hay categorias', + 'data': null + }; + + // Verificar la conectividad de la red + List connectivityResult = await _connectivity.checkConnectivity(); + if (!connectivityResult.contains(ConnectivityResult.none)) { + if (connectivityResult.contains(ConnectivityResult.wifi) || connectivityResult.contains(ConnectivityResult.mobile)) { + try { + // Realizar la solicitud a la API + Map respGet = await _categoryApi.getCategories(); + if (respGet['statusCode'] == 200) { + try { + var decodeResp = json.decode(respGet['body']); + List listCategories = CategoriaModel + .fromJsonArray(decodeResp['data']); + mapResp['ok'] = true; + mapResp['message'] = + "${listCategories.length} categorías encontradas"; + mapResp['data'] = listCategories; + } catch (e) { + mapResp['message'] = "Error en procesamiento de datos: $e"; + } + } else { + mapResp['message'] = + "Error en la respuesta de la API: ${respGet['body']}"; + } + } catch (e) { + mapResp['message'] = "Error en la solicitud a la API: $e"; + } + } else { + mapResp['message'] = 'No hay conexión a internet'; + } + } else { + mapResp['message'] = 'No hay conexión a internet'; + } + + return mapResp; + } +} diff --git a/lib/src/http_api/CategoryApi.dart b/lib/src/http_api/CategoryApi.dart new file mode 100644 index 0000000..edc7646 --- /dev/null +++ b/lib/src/http_api/CategoryApi.dart @@ -0,0 +1,39 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:flutter/foundation.dart'; +import 'package:miapp_flutter/environments/archivo.dart'; + +class CategoryApi { + + final String apiUrl = 'categoria'; + + // Método para obtener las categorías + Future> getCategories() async { + String url = '${apiApp}/$apiUrl?offset=0&max=100'; + if (kDebugMode) { + print('Url -> $url'); + + } + try { + final response = await http.get(Uri.parse(url)); + + // Verifica el estado de la respuesta + if (response.statusCode == 200) { + return { + 'statusCode': response.statusCode, + 'body': response.body, + }; + } else { + return { + 'statusCode': response.statusCode, + 'body': 'Error: ${response.reasonPhrase}', + }; + } + } catch (e) { + return { + 'statusCode': 501, + 'body': 'Error: $e', + }; + } + } +} diff --git a/lib/src/models/ArticuloModel.dart b/lib/src/models/ArticuloModel.dart new file mode 100644 index 0000000..12e6def --- /dev/null +++ b/lib/src/models/ArticuloModel.dart @@ -0,0 +1,54 @@ +import 'dart:convert'; + +class ArticleModel { + final int id; + final String clave; + final String nombre; + final int categoriaId; + final List precios; + final bool activo; + + ArticleModel({ + required this.id, + required this.clave, + required this.nombre, + required this.categoriaId, + required this.precios, + required this.activo, + }); + + factory ArticleModel.fromJson(Map json) { + var list = json['precios'] as List; + List preciosList = list.map((i) => Price.fromJson(i)).toList(); + + return ArticleModel( + id: json['id'], + clave: json['clave'], + nombre: json['nombre'], + categoriaId: json['categoria']['id'], + precios: preciosList, + activo: json['activo'], + ); + } + + static List fromJsonArray(List jsonArray) { + return jsonArray.map((json) => ArticleModel.fromJson(json)).toList(); + } +} + +class Price { + final int id; + final double precio; + + Price({ + required this.id, + required this.precio, + }); + + factory Price.fromJson(Map json) { + return Price( + id: json['id'], + precio: json['precio'].toDouble(), + ); + } +} \ No newline at end of file diff --git a/lib/src/models/CategoriaModel.dart b/lib/src/models/CategoriaModel.dart new file mode 100644 index 0000000..ce28f56 --- /dev/null +++ b/lib/src/models/CategoriaModel.dart @@ -0,0 +1,74 @@ +// lib/src/models/category_model.dart + +class CategoriaModel { + int id; + int? version; + String? key; + String? name; + int? createdDate; + CategoriaModel? parentCategory; + List? subCategories; + bool? active; + + CategoriaModel({ + required this.id, + this.version, + this.key, + this.name, + this.createdDate, + this.parentCategory, + this.subCategories, + this.active, + }); + + // Método para crear una instancia de CategoryModel desde un JSON + factory CategoriaModel.fromJson(Map json) { + return CategoriaModel( + id: json['id'], + version: json['version'], + key: json['clave'], + name: json['nombre'], + createdDate: json['fechaCreado'], + parentCategory: json['categoria'] != null + ? CategoriaModel.fromJson(json['categoria']) + : null, + subCategories: json['categorias'] != null + ? CategoriaModel.fromJsonArray(json['categorias']) + : [], + active: json['activo'], + ); + } + + // Este metodo sirve para para convertir una instancia de CategoryModel a JSON + Map toJson() { + return { + "id": id, + "version": version, + "clave": key, + "nombre": name, + "fechaCreado": createdDate, + "categoria": parentCategory?.toJson(), + "categorias": subCategories != null + ? CategoriaModel.toJsonArray(subCategories!) + : [], + "activo": active, + }; + } + + // Método para crear una lista de CategoryModel desde un JSON + static List fromJsonArray(json) { + if (json == null) return []; + var list = json as List; + List listResult = + list.map((data) => CategoriaModel.fromJson(data)).toList(); + return listResult; + } + + static toJsonArray(List list) { + List> listMap = []; + for (CategoriaModel item in list) { + listMap.add(item.toJson()); + } + return listMap; + } +} \ No newline at end of file diff --git a/lib/src/pages/category/CategoryListWidget.dart b/lib/src/pages/category/CategoryListWidget.dart new file mode 100644 index 0000000..d7a4182 --- /dev/null +++ b/lib/src/pages/category/CategoryListWidget.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; + +import '../../controllers/CategoriaController.dart'; +import '../../models/CategoriaModel.dart'; + +class CategoryListWidget extends StatefulWidget { + @override + _CategoryWidgetState createState() => _CategoryWidgetState(); +} + +class _CategoryWidgetState extends State { + final CategoryController _categoryCtrl = CategoryController(); //El categoryCtrl se usa para obtener las categorías + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: FutureBuilder>( //El futureBuilder se utiliza para + // manejar operaciones asíncronas y donde map tiene las categorias + future: _categoryCtrl.getCategories(), + builder: (context, snapshot) { + if (snapshot.hasData) { + if (snapshot.data!['ok']) { + if (snapshot.data!['data'] != null && (snapshot.data!['data'] as List).isNotEmpty) { + List categories = snapshot.data!['data']; + return ListView.builder( + itemBuilder: (BuildContext context, int index) { + final category = categories[index]; + return Card( + child: ListTile( + title: Text(category.name ?? 'No Name'), + leading: const Icon(Icons.touch_app), + onTap: () { + // Navegar al listado de servicios + }, + ), + ); + }, + itemCount: categories.length, + ); + } else { + return Center(child: Text("No se encontraron categorías")); + } + } else { + return Center(child: Text("Error: ${snapshot.data!['message']}")); + } + } else if (snapshot.hasError) { + return Center(child: Text("Error: ${snapshot.error.toString()}")); + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + }, + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/src/pages/home_page.dart b/lib/src/pages/home_page.dart index a9cd8c0..4130c7c 100644 --- a/lib/src/pages/home_page.dart +++ b/lib/src/pages/home_page.dart @@ -1,4 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:miapp_flutter/src/specific_widgets/menu.dart' ; + +import 'category/CategoryListWidget.dart'; void main() => runApp(const DrawerApp()); @@ -59,60 +62,19 @@ class _HomePageState extends State { ], ), ), - drawer: Drawer( - child: ListView( - padding: EdgeInsets.zero, - children: [ - const DrawerHeader( - decoration: BoxDecoration( - color: Colors.blue, - ), - child: Text( - 'Menu App', - style: TextStyle( - color: Colors.white, - fontSize: 24, - ), - ), - ), - ListTile( - leading: const Icon(Icons.message), - title: const Text('Mensajes'), - onTap: () { - setState(() { - selectedPage = 'Messages'; - }); - Navigator.pop(context); // Close the drawer - }, - ), - ListTile( - leading: const Icon(Icons.settings), - title: const Text('Configuraciones'), - onTap: () { - setState(() { - selectedPage = 'Settings'; - }); - Navigator.pop(context); // Close the drawer - }, - ), - ], - ), - ), + drawer: MenuWidget(), body: TabBarView( children: [ - Column( - mainAxisAlignment: MainAxisAlignment.start, + Column( children: [ Expanded( - child: Center( - - ), + child: CategoryListWidget(), ), Padding( - padding: const EdgeInsets.all(50.0), + padding: const EdgeInsets.all(16.0), child: ElevatedButton( onPressed: _handleNewCategory, - child: const Text('Nueva categoria'), + child: const Text('Nueva categoría'), ), ), ], diff --git a/lib/src/shared_widgets/widget_mensajes.dart b/lib/src/shared_widgets/widget_mensajes.dart new file mode 100644 index 0000000..5ddfcee --- /dev/null +++ b/lib/src/shared_widgets/widget_mensajes.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; + +// Widget para mostrar mensajes de error +Widget alertDanger(String message) { + return Container( + width: double.infinity, + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + const Icon( + Icons.error, + color: Colors.white, + ), + const SizedBox( + width: 10.0, + ), + Expanded( + child: Text( + message, + style: const TextStyle(color: Colors.red), + ), + ) + ], + ), + ); +} + +// Widget para mostrar mensajes de éxito +Widget alertSuccess(String message) { + return Container( + width: double.infinity, + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + const Icon( + Icons.check_circle_outline, + color: Colors.white, + ), + const SizedBox( + width: 10.0, + ), + Expanded( + child: Text( + message, + style: const TextStyle(color: Colors.lightGreen), + ), + ) + ], + ), + ); +} + +// Widget para mostrar mensajes de espera +Widget alertWait(String message) { + return Container( + width: double.infinity, + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + const Icon( + Icons.info, + color: Colors.white, + ), + const SizedBox( + width: 10.0, + ), + Expanded( + child: Text( + message, + style: const TextStyle(color: Colors.lightBlueAccent), + ), + ) + ], + ), + ); +} diff --git a/lib/src/specific_widgets/menu.dart b/lib/src/specific_widgets/menu.dart new file mode 100644 index 0000000..a81d522 --- /dev/null +++ b/lib/src/specific_widgets/menu.dart @@ -0,0 +1,46 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class MenuWidget extends StatelessWidget { + const MenuWidget({super.key}); + + @override + Widget build(BuildContext context) { + return Drawer( + child: ListView( + padding: EdgeInsets.zero, + children: [ + const DrawerHeader( + decoration: BoxDecoration( + color: Colors.blue, + ), + child: Text( + 'Menu App', + style: TextStyle( + color: Colors.white, + fontSize: 24, + ), + ), + ), + ListTile( + leading: const Icon(Icons.message), + title: const Text('Mensajes'), + onTap: () { + + Navigator.pop(context); // Close the drawer + }, + ), + ListTile( + leading: const Icon(Icons.settings), + title: const Text('Configuraciones'), + onTap: () { + + + Navigator.pop(context); // Close the drawer + }, + ), + ], + ), + ); + } +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index cccf817..ad535f5 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,8 @@ import FlutterMacOS import Foundation +import connectivity_plus func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 6cb5f72..58e5797 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + args: + dependency: transitive + description: + name: args + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + url: "https://pub.dev" + source: hosted + version: "2.5.0" async: dependency: transitive description: @@ -41,6 +49,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + connectivity_plus: + dependency: "direct main" + description: + name: connectivity_plus + sha256: "3e7d1d9dbae40ae82cbe6c23c518f0c4ffe32764ee9749b9a99d32cbac8734f6" + url: "https://pub.dev" + source: hosted + version: "6.0.4" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" + url: "https://pub.dev" + source: hosted + version: "2.0.1" cupertino_icons: dependency: "direct main" description: @@ -49,6 +73,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dbus: + dependency: transitive + description: + name: dbus + sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" + url: "https://pub.dev" + source: hosted + version: "0.7.10" fake_async: dependency: transitive description: @@ -57,6 +89,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + url: "https://pub.dev" + source: hosted + version: "2.1.2" flutter: dependency: "direct main" description: flutter @@ -75,6 +115,27 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + url: "https://pub.dev" + source: hosted + version: "1.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" leak_tracker: dependency: transitive description: @@ -131,6 +192,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.12.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" path: dependency: transitive description: @@ -139,6 +208,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" sky_engine: dependency: transitive description: flutter @@ -192,6 +277,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.0" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" vector_math: dependency: transitive description: @@ -208,6 +301,22 @@ packages: url: "https://pub.dev" source: hosted version: "14.2.1" + web: + dependency: transitive + description: + name: web + sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" sdks: dart: ">=3.4.4 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/pubspec.yaml b/pubspec.yaml index b3d3ec6..f3cfe6b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,9 +32,13 @@ dependencies: sdk: flutter + + # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.6 + http: ^1.2.2 + connectivity_plus: ^6.0.4 dev_dependencies: flutter_test: @@ -93,3 +97,6 @@ flutter: assets: - assets/img/ + + + diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8b6d468..8777c93 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b93c4c3..cc1361d 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + connectivity_plus ) list(APPEND FLUTTER_FFI_PLUGIN_LIST -- libgit2 0.27.1