toping_form.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. // ignore_for_file: use_build_context_synchronously
  2. import 'package:camera/camera.dart';
  3. import 'package:file_picker/file_picker.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:yoshi_papas_app/views/home/home_screen.dart';
  6. import 'package:yoshi_papas_app/widgets/widgets.dart';
  7. import 'package:provider/provider.dart';
  8. import '../../models/models.dart';
  9. import '../../viewmodels/viewmodels.dart';
  10. class TopingForm extends StatefulWidget {
  11. const TopingForm({Key? key}) : super(key: key);
  12. @override
  13. State<TopingForm> createState() => Formulario();
  14. }
  15. class Formulario extends State<TopingForm> {
  16. final _clave = TextEditingController();
  17. final _nombre = TextEditingController();
  18. final _descripcion = TextEditingController();
  19. final _costo = TextEditingController();
  20. final _categoria = TextEditingController();
  21. int? _selectedCategoriaId;
  22. TopingCategoria? _selectedCategoria;
  23. final _imagen = TextEditingController();
  24. bool activo = false;
  25. @override
  26. void initState() {
  27. super.initState();
  28. WidgetsBinding.instance.addPostFrameCallback((_) {
  29. _initializeForm();
  30. });
  31. }
  32. Future<void> _initializeForm() async {
  33. Provider.of<TopingViewModel>(context, listen: false).setIsLoading(true);
  34. final mvm = Provider.of<TopingViewModel>(context, listen: false);
  35. final tcv = Provider.of<TopingCategoriaViewModel>(context, listen: false);
  36. Toping? modelo = mvm.selectedToping;
  37. if (modelo != null && modelo.id > 0) {
  38. activo = modelo.activo!;
  39. _clave.text = modelo.clave.toString();
  40. _nombre.text = modelo.nombre.toString();
  41. _descripcion.text = modelo.descripcion.toString();
  42. _costo.text = modelo.costo.toString();
  43. _selectedCategoriaId = modelo.idCategoria;
  44. // Asegurarse de que las categorías están cargadas
  45. if (tcv.registros.isEmpty) {
  46. await tcv.fetchRegistros();
  47. }
  48. // Buscar la categoría seleccionada
  49. final TopingCategoria? categoriaSeleccionada =
  50. tcv.getById(_selectedCategoriaId!);
  51. if (categoriaSeleccionada != null) {
  52. setState(() {
  53. _selectedCategoria = categoriaSeleccionada;
  54. _categoria.text = categoriaSeleccionada.nombre!;
  55. });
  56. }
  57. }
  58. Provider.of<TopingViewModel>(context, listen: false).setIsLoading(false);
  59. }
  60. @override
  61. void dispose() {
  62. super.dispose();
  63. _descripcion.dispose();
  64. _nombre.dispose();
  65. }
  66. @override
  67. Widget build(BuildContext context) {
  68. final mvm = Provider.of<TopingViewModel>(context);
  69. final modelo = mvm.selectedToping;
  70. final mediavm = Provider.of<MediaViewModel>(context);
  71. final tcv = Provider.of<TopingCategoriaViewModel>(context, listen: false);
  72. if (mvm.isLoading) return const Cargando();
  73. final Toping = mvm.selectedToping;
  74. List<Widget> _registros = [];
  75. if (modelo!.imagenes.isNotEmpty) {
  76. for (int x = 0; x <= modelo.imagenes.length - 1; x++) {
  77. _registros.add(itemMedia(context, x));
  78. }
  79. }
  80. Size s = MediaQuery.of(context).size;
  81. int axiscount = obtenerAxiscount(s);
  82. return Scaffold(
  83. appBar: encabezado(titulo: "Toping"),
  84. body: SingleChildScrollView(
  85. padding: const EdgeInsets.all(8),
  86. child: Column(
  87. children: [
  88. tarjeta(
  89. Padding(
  90. padding: const EdgeInsets.all(8),
  91. child: Column(
  92. children: [
  93. Row(
  94. children: [
  95. Expanded(
  96. child: AppTextField(
  97. maxLength: 100,
  98. etiqueta: 'Clave',
  99. controller: _clave,
  100. hintText: 'Clave Toping',
  101. ),
  102. ),
  103. ],
  104. ),
  105. Row(
  106. children: [
  107. Expanded(
  108. child: AppTextField(
  109. maxLength: 100,
  110. etiqueta: 'Nombre',
  111. controller: _nombre,
  112. hintText: 'Nombre Toping',
  113. ),
  114. ),
  115. ],
  116. ),
  117. Row(
  118. children: [
  119. Expanded(
  120. child: AppDropdownSearch(
  121. etiqueta: 'Categoría',
  122. controller: _categoria,
  123. selectedItem: _selectedCategoria,
  124. onPressedClear: () {
  125. setState(() {
  126. _selectedCategoria = null;
  127. _categoria.text = "";
  128. });
  129. },
  130. itemAsString: (u) => '${u.clave}',
  131. asyncItems: (text) async {
  132. final r = await tcv.fetchRegistros(
  133. q: text, segmentar: true);
  134. return r;
  135. },
  136. onChanged: (e) {
  137. setState(() {
  138. _selectedCategoria = e;
  139. _selectedCategoriaId = e?.id;
  140. _categoria.text = e?.nombre ?? "";
  141. });
  142. },
  143. validator: (value) {
  144. if (value == null) {
  145. return 'Seleccione';
  146. }
  147. return null;
  148. },
  149. )
  150. /*AppTextField(
  151. maxLength: 100,
  152. etiqueta: 'Categoria',
  153. controller: _categoria,
  154. hintText: 'Nombre Categoria',
  155. ),*/
  156. ),
  157. ],
  158. ),
  159. Row(
  160. children: [
  161. Expanded(
  162. child: AppTextField(
  163. maxLength: 100,
  164. etiqueta: 'Precio',
  165. controller: _costo,
  166. hintText: 'Precio Toping',
  167. ),
  168. ),
  169. ],
  170. ),
  171. Row(
  172. children: [
  173. Expanded(
  174. child: AppTextField(
  175. maxLength: 1000,
  176. maxLines: 3,
  177. etiqueta: 'Descripción',
  178. controller: _descripcion,
  179. hintText: 'Descripción de Toping',
  180. ),
  181. ),
  182. ],
  183. ),
  184. Row(
  185. children: [
  186. Expanded(
  187. flex: 0,
  188. child: Column(children: [
  189. const Text("ACTIVO",
  190. style:
  191. TextStyle(fontWeight: FontWeight.bold)),
  192. Switch(
  193. activeColor: Colors.green,
  194. value: activo,
  195. onChanged: (value) {
  196. setState(() {
  197. activo = value;
  198. });
  199. },
  200. )
  201. ]))
  202. ],
  203. ),
  204. ],
  205. ),
  206. ),
  207. ),
  208. const SizedBox(height: 15),
  209. tarjeta(Column(children: [
  210. GridView.count(
  211. key: const Key("contenedor-1"),
  212. physics: const NeverScrollableScrollPhysics(),
  213. shrinkWrap: true,
  214. padding: const EdgeInsets.all(4),
  215. crossAxisCount: axiscount,
  216. crossAxisSpacing: 2,
  217. mainAxisSpacing: 1,
  218. children: [
  219. ..._registros,
  220. agregarMedia(
  221. accion: () async {
  222. FilePickerResult? r = await FilePicker.platform
  223. .pickFiles(
  224. type: FileType.custom,
  225. allowMultiple: true,
  226. allowedExtensions: ['jpg', 'png']);
  227. if (r == null) return;
  228. if (r.files.isEmpty) return;
  229. for (PlatformFile xf in r.files) {
  230. XFile? x =
  231. await mediavm.convertirPlatformFileAXFile(xf);
  232. mediavm.agregarArchivo(x);
  233. }
  234. },
  235. titulo: "Agregar Media"),
  236. ],
  237. ),
  238. const SizedBox(height: 30),
  239. ])),
  240. boton("Guardar", () async {
  241. Provider.of<TopingViewModel>(context, listen: false)
  242. .setIsLoading(true);
  243. await mvm.guardarModelo(
  244. modelo: Toping!,
  245. clave: _clave.text,
  246. nombre: _nombre.text,
  247. descripcion: _descripcion.text,
  248. categoria: _selectedCategoriaId!,
  249. costo: _costo.text,
  250. activo: activo,
  251. imagenes: mediavm.archivos);
  252. Provider.of<TopingViewModel>(context, listen: false)
  253. .setIsLoading(false);
  254. if (context.mounted) {
  255. Navigator.pop(context);
  256. }
  257. }),
  258. ],
  259. ),
  260. ),
  261. );
  262. }
  263. Widget itemMedia(BuildContext context, int index) {
  264. MediaToping mediaTC = Provider.of<TopingViewModel>(context, listen: false)
  265. .selectedToping!
  266. .imagenes[index];
  267. // Asegúrate de que el objeto media no sea nulo
  268. if (mediaTC.media == null || mediaTC.media!.ruta!.isEmpty) {
  269. // Si es nulo, muestra un widget de placeholder
  270. return Container(
  271. alignment: Alignment.center,
  272. padding: EdgeInsets.all(8.0),
  273. child: Text('Imagen no disponible'),
  274. );
  275. }
  276. // Utiliza el objeto media para mostrar la imagen
  277. return Card(
  278. clipBehavior: Clip.antiAlias,
  279. child: Column(
  280. children: [
  281. Expanded(
  282. child: Image.network(
  283. mediaTC.media!.ruta!,
  284. fit: BoxFit.cover,
  285. errorBuilder: (context, error, stackTrace) {
  286. // Muestra un mensaje de error o imagen de placeholder
  287. return Center(child: Text('Error al cargar la imagen'));
  288. },
  289. ),
  290. ),
  291. Padding(
  292. padding: EdgeInsets.all(8.0),
  293. child: Text(mediaTC.media!.nombre ?? 'Sin nombre'),
  294. ),
  295. ],
  296. ),
  297. );
  298. }
  299. }