widgets_components.dart 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. // ignore_for_file: use_build_context_synchronously, prefer_if_null_operators, prefer_conditional_assignment
  2. import 'dart:io';
  3. import 'dart:typed_data';
  4. import 'package:camera/camera.dart';
  5. import 'package:flutter/material.dart';
  6. //import 'package:yoshi_papas_app/viewmodels/media_view_model.dart';
  7. import 'package:intl/intl.dart';
  8. import 'package:omni_datetime_picker/omni_datetime_picker.dart';
  9. import 'package:flutter/material.dart' as d;
  10. import 'package:datetime_picker_formfield/datetime_picker_formfield.dart' as d2;
  11. import 'package:provider/provider.dart';
  12. import 'package:url_launcher/url_launcher.dart';
  13. import 'package:flutter/foundation.dart' show kIsWeb;
  14. import 'package:path_provider/path_provider.dart';
  15. import '../data/session/session_storage.dart';
  16. import '../models/media_model.dart';
  17. import '../themes/themes.dart';
  18. import 'package:timezone/timezone.dart' as tz;
  19. import 'package:http/http.dart' as http;
  20. import "package:universal_html/html.dart" as html;
  21. //import '../viewmodels/ordenes_view_model.dart';
  22. //import 'dart:html';
  23. //import 'dart:html' as html;
  24. encabezado(
  25. {double elevacion = 1,
  26. List<Widget>? acciones,
  27. PreferredSize? bottom,
  28. Color? backgroundColor,
  29. String? nombre,
  30. Widget? leading = null,
  31. String? titulo,
  32. bool centerTitle = true}) {
  33. TextStyle estilo = const TextStyle(fontWeight: FontWeight.bold);
  34. if (acciones == null) {
  35. acciones = [];
  36. }
  37. return AppBar(
  38. leading: leading,
  39. elevation: elevacion,
  40. backgroundColor: backgroundColor,
  41. centerTitle: centerTitle,
  42. title: titulo == null
  43. ? Image.asset("assets/JoshiLogoHorizontal.png", width: 100)
  44. : Text(titulo.toString(), style: estilo),
  45. actions: [
  46. ...acciones,
  47. Image.asset("assets/JoshiLogoHorizontal.png", width: 100),
  48. ],
  49. bottom: bottom);
  50. }
  51. tarjeta(Widget item, {Color color = Colors.white, double padding = 0}) {
  52. if (padding > 0) {
  53. return Padding(
  54. padding: const EdgeInsets.all(0),
  55. child: Card(
  56. color: color,
  57. shape:
  58. RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
  59. margin: const EdgeInsets.only(bottom: 16),
  60. elevation: 0,
  61. borderOnForeground: true,
  62. child: Padding(padding: EdgeInsets.all(padding), child: item)));
  63. }
  64. return Card(
  65. color: color,
  66. shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
  67. margin: const EdgeInsets.only(bottom: 8),
  68. elevation: 0,
  69. borderOnForeground: true,
  70. child: Padding(
  71. padding: const EdgeInsets.all(8),
  72. child: item,
  73. ));
  74. }
  75. class Cargando extends StatelessWidget {
  76. const Cargando({super.key});
  77. @override
  78. Widget build(BuildContext context) {
  79. return Scaffold(
  80. backgroundColor: const Color(0xFFE0E0E0),
  81. body: Center(
  82. child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
  83. Padding(
  84. padding: const EdgeInsets.fromLTRB(16, 0, 16, 10),
  85. child: Image.asset("assets/JoshiLogo.png", height: 200)),
  86. const CircularProgressIndicator(backgroundColor: Colors.grey),
  87. Container(margin: const EdgeInsets.only(bottom: 8.0)),
  88. const Text("Cargando contenido...",
  89. style: TextStyle(
  90. fontWeight: FontWeight.bold,
  91. fontSize: 16,
  92. color: Colors.black)),
  93. const Text("Por favor espere.",
  94. style: TextStyle(
  95. fontWeight: FontWeight.bold,
  96. fontSize: 16,
  97. color: Colors.black),
  98. textAlign: TextAlign.center)
  99. ]),
  100. ));
  101. }
  102. }
  103. boton(String etiqueta, Function()? accion,
  104. {double height = 75, double width = 380}) {
  105. return Align(
  106. alignment: Alignment.topLeft,
  107. child: SizedBox(
  108. height: height,
  109. width: 380,
  110. child: ElevatedButton(
  111. style: ButtonStyle(
  112. shape: MaterialStatePropertyAll(
  113. RoundedRectangleBorder(
  114. borderRadius: BorderRadius.circular(10),
  115. ),
  116. ),
  117. backgroundColor: MaterialStatePropertyAll(AppTheme.primary),
  118. ),
  119. onPressed: accion,
  120. child: Row(
  121. mainAxisAlignment: MainAxisAlignment.center,
  122. children: [
  123. Text(etiqueta,
  124. style: TextStyle(fontSize: 18, color: AppTheme.secondary)),
  125. ],
  126. ),
  127. ),
  128. ),
  129. );
  130. }
  131. Future<DateTime?> showHora(BuildContext context, DateTime? fecha) async {
  132. if (fecha == null) {
  133. return fecha;
  134. }
  135. final tiempo = await showTimePicker(
  136. useRootNavigator: false,
  137. helpText: "CAPTURAR HORA",
  138. confirmText: "ACEPTAR",
  139. cancelText: "CANCELAR",
  140. hourLabelText: "HORA",
  141. minuteLabelText: "MINUTO",
  142. initialEntryMode: TimePickerEntryMode.input,
  143. context: context,
  144. initialTime: TimeOfDay.fromDateTime(fecha),
  145. builder: (context, childs) {
  146. return MediaQuery(
  147. data: MediaQuery.of(context).copyWith(
  148. alwaysUse24HourFormat: true,
  149. padding: const EdgeInsets.all(1),
  150. size: const Size.square(1),
  151. textScaler: const TextScaler.linear(.8)),
  152. child: childs!);
  153. },
  154. );
  155. return d2.DateTimeField.combine(fecha!, tiempo);
  156. }
  157. Future<DateTime?> showDatetimePicker(BuildContext context, DateTime? fecha,
  158. {DateTime? inicia,
  159. DateTime? termina,
  160. OmniDateTimePickerType tipo = OmniDateTimePickerType.dateAndTime,
  161. bool solofecha = false}) async {
  162. if (termina == null) {
  163. termina = DateTime(2030);
  164. }
  165. final f = await d.showDatePicker(
  166. context: context,
  167. initialDate: fecha != null ? DateTime.now() : fecha,
  168. firstDate: inicia == null ? DateTime(2023) : inicia, // DateTime(2023),
  169. lastDate: termina,
  170. cancelText: "CANCELAR", confirmText: "ACEPTAR",
  171. );
  172. if (f == null) {
  173. return fecha;
  174. }
  175. if (solofecha) {
  176. return f;
  177. }
  178. final tiempo = await showTimePicker(
  179. useRootNavigator: false,
  180. helpText: "CAPTURAR HORA",
  181. confirmText: "ACEPTAR",
  182. cancelText: "CANCELAR",
  183. hourLabelText: "HORA",
  184. minuteLabelText: "MINUTO",
  185. initialEntryMode: TimePickerEntryMode.input,
  186. context: context,
  187. initialTime: TimeOfDay.fromDateTime(f),
  188. builder: (context, childs) {
  189. return MediaQuery(
  190. data: MediaQuery.of(context).copyWith(
  191. alwaysUse24HourFormat: true,
  192. padding: const EdgeInsets.all(1),
  193. size: const Size.square(1),
  194. textScaler: const TextScaler.linear(.8)),
  195. child: childs!);
  196. },
  197. );
  198. return d2.DateTimeField.combine(f, tiempo);
  199. }
  200. Widget circulo(Widget item, {Function()? accion, Color? color}) {
  201. color ??= Colors.black;
  202. return InkWell(
  203. onTap: accion,
  204. child: Container(
  205. decoration: BoxDecoration(
  206. border: Border.all(
  207. color: color, // <--- border color
  208. width: 2.0,
  209. ),
  210. borderRadius: const BorderRadius.all(
  211. Radius.circular(50) // <--- border radius here
  212. ),
  213. ),
  214. child: item));
  215. }
  216. alerta(BuildContext context, {String? etiqueta = "Capturar búsqueda"}) {
  217. return showDialog(
  218. context: context,
  219. builder: (context) {
  220. return AlertDialog(
  221. title: Text(etiqueta.toString()),
  222. actions: [
  223. Row(children: [
  224. Expanded(
  225. child: TextButton(
  226. onPressed: () async {
  227. Navigator.pop(context);
  228. },
  229. child: const Text('Continuar'),
  230. ))
  231. ])
  232. ],
  233. );
  234. });
  235. }
  236. botonElevated(
  237. {Function()? accion,
  238. String? titulo = "Buscar",
  239. Color color = Colors.black}) {
  240. return ElevatedButton(
  241. style: ElevatedButton.styleFrom(
  242. backgroundColor: color,
  243. shape: RoundedRectangleBorder(
  244. borderRadius: BorderRadius.circular(12), // <-- Radius
  245. )),
  246. onPressed: accion,
  247. child: Text(
  248. titulo.toString(),
  249. style: const TextStyle(color: Colors.white),
  250. ),
  251. );
  252. }
  253. Widget xMedia(XFile m) {
  254. bool archivo = false;
  255. Widget icono = const Icon(Icons.file_copy, size: 50);
  256. int lastIndex = m.name.lastIndexOf('.');
  257. String extension = "";
  258. if (lastIndex != -1 && lastIndex < m.name.length - 1) {
  259. extension = m.name.substring(lastIndex + 1);
  260. }
  261. switch (extension) {
  262. case "mp4":
  263. archivo = true;
  264. icono = const Icon(Icons.video_file, size: 50);
  265. break;
  266. case "wav":
  267. archivo = true;
  268. icono = Image.asset("assets/audio-file.png");
  269. archivo = true;
  270. break;
  271. case "jpeg":
  272. case "jpg":
  273. case "png":
  274. break;
  275. case "pdf":
  276. icono = Image.asset("assets/pdf-file.png");
  277. archivo = true;
  278. break;
  279. case "csv":
  280. case "docx":
  281. icono = Image.asset("assets/word.png");
  282. archivo = true;
  283. break;
  284. case "xlsx":
  285. icono = Image.asset("assets/excel.png");
  286. archivo = true;
  287. break;
  288. }
  289. String nombre = m.name.toString();
  290. if (nombre.length > 25) {
  291. nombre = "${m.name.toString().substring(0, 24)}...";
  292. }
  293. return InkWell(
  294. onTap: () async {
  295. String url = m.path.toString();
  296. await canLaunch(url)
  297. ? await launch(url, forceSafariVC: false, forceWebView: false)
  298. : print('Could not launch '); //aqui
  299. },
  300. child: Stack(alignment: Alignment.center, children: [
  301. Container(
  302. height: 100.0,
  303. width: 100.0,
  304. clipBehavior: Clip.antiAlias,
  305. decoration: BoxDecoration(
  306. border: Border.all(color: Colors.black, width: 1.0),
  307. borderRadius: const BorderRadius.all(Radius.circular(15.0)),
  308. ),
  309. child: archivo
  310. ? icono
  311. : Image.network(m.path.toString(),
  312. scale:
  313. 1) // _firma == null?const Icon(Icons.pages, size: 30, color: Colors.black): contenedorFirma,
  314. ),
  315. Positioned(
  316. bottom: 0,
  317. child: Container(
  318. width: 200,
  319. height: 40,
  320. color: Colors.grey.shade800,
  321. child: Column(
  322. mainAxisAlignment: MainAxisAlignment.center,
  323. children: [
  324. Text(
  325. nombre,
  326. textAlign: TextAlign.center,
  327. textScaler: const TextScaler.linear(.8),
  328. style: const TextStyle(color: Colors.white),
  329. ),
  330. ]),
  331. )),
  332. ]));
  333. }
  334. Widget wMedia(Media m, {Function()? eliminar}) {
  335. bool archivo = false;
  336. Widget icono = const Icon(Icons.file_copy, size: 50);
  337. switch (m.extension) {
  338. case "mp4":
  339. archivo = true;
  340. icono = const Icon(Icons.video_file, size: 50);
  341. break;
  342. case "wav":
  343. archivo = true;
  344. icono = Image.asset("assets/audio-file.png");
  345. archivo = true;
  346. break;
  347. case "jpeg":
  348. case "jpg":
  349. case "png":
  350. break;
  351. case "pdf":
  352. icono = Image.asset("assets/pdf-file.png");
  353. archivo = true;
  354. break;
  355. case "csv":
  356. case "docx":
  357. icono = Image.asset("assets/word.png");
  358. archivo = true;
  359. break;
  360. case "xlsx":
  361. icono = Image.asset("assets/excel.png");
  362. archivo = true;
  363. break;
  364. }
  365. String fecha = "";
  366. if (m.creado != null) {
  367. String timeZone = 'America/Hermosillo';
  368. fecha = formatFechaConZonaHoraria(m.creado!, timeZone);
  369. }
  370. String nombre = m.nombre.toString();
  371. if (nombre.length > 25) {
  372. nombre = "${m.nombre.toString().substring(0, 24)}...";
  373. }
  374. return InkWell(
  375. onTap: () async {
  376. String url = m.ruta.toString();
  377. await canLaunch(url)
  378. ? await launch(url, forceSafariVC: false, forceWebView: false)
  379. : print('Could not launch '); //aqui
  380. },
  381. child: Stack(alignment: Alignment.center, children: [
  382. Container(
  383. height: 160.0,
  384. width: 160.0,
  385. clipBehavior: Clip.antiAlias,
  386. decoration: BoxDecoration(
  387. border: Border.all(color: Colors.black, width: 1.0),
  388. borderRadius: const BorderRadius.all(Radius.circular(15.0)),
  389. ),
  390. child: archivo
  391. ? icono
  392. : Image.network(m.ruta.toString(),
  393. scale:
  394. 1) // _firma == null?const Icon(Icons.pages, size: 30, color: Colors.black): contenedorFirma,
  395. ),
  396. Positioned(
  397. bottom: 0,
  398. child: Container(
  399. width: 500,
  400. height: 40,
  401. color: Colors.grey.shade800,
  402. child: Column(
  403. mainAxisAlignment: MainAxisAlignment.center,
  404. children: [
  405. Text(
  406. nombre,
  407. textAlign: TextAlign.center,
  408. textScaler: const TextScaler.linear(.8),
  409. style: const TextStyle(color: Colors.white),
  410. ),
  411. Text(
  412. fecha,
  413. textAlign: TextAlign.center,
  414. textScaler: const TextScaler.linear(.8),
  415. style: const TextStyle(color: Colors.white),
  416. ),
  417. ]),
  418. )),
  419. Positioned(
  420. left: 0,
  421. top: 0,
  422. child: ElevatedButton(
  423. onPressed: eliminar,
  424. style: ElevatedButton.styleFrom(
  425. shape: CircleBorder(),
  426. padding: EdgeInsets.all(16),
  427. ),
  428. child: Icon(
  429. Icons.delete,
  430. color: Colors.red.shade800,
  431. ),
  432. ),
  433. ),
  434. ]));
  435. }
  436. Widget agregarMedia(
  437. {Color color = Colors.green,
  438. Function()? accion,
  439. String titulo = "Agregar Media",
  440. Icon? icono,
  441. double tamano = 160}) {
  442. if (icono == null) {
  443. icono = Icon(
  444. Icons.add,
  445. size: tamano < 100 ? 60 : 100,
  446. color: Colors.white,
  447. );
  448. }
  449. return InkWell(
  450. onTap: accion,
  451. child: Stack(alignment: Alignment.center, children: [
  452. // Contenedor con un color de fondo y dimensiones específicas
  453. Container(
  454. width: tamano,
  455. height: tamano,
  456. color: color,
  457. ),
  458. // Texto flotante
  459. Positioned(
  460. child:
  461. Column(mainAxisAlignment: MainAxisAlignment.center, children: [
  462. icono,
  463. titulo.isEmpty
  464. ? Container()
  465. : Text(
  466. titulo,
  467. style: const TextStyle(
  468. color: Colors.white,
  469. fontSize: 16,
  470. ),
  471. ),
  472. ])),
  473. ]));
  474. }
  475. String formatFechaConZonaHoraria(DateTime dateTime, String timeZone) {
  476. // Obtiene la ubicación de la zona horaria
  477. tz.Location location = tz.getLocation(timeZone);
  478. // Convierte la fecha a la zona horaria deseada
  479. tz.TZDateTime fechaConZona = tz.TZDateTime.from(dateTime, location);
  480. // Formatea la fecha con la zona horaria
  481. //String formattedFecha = DateFormat("dd/MM/yyyy HH:mm '($timeZone)'").format(fechaConZona);
  482. String formattedFecha = DateFormat("dd/MM/yyyy HH:mm").format(fechaConZona);
  483. return formattedFecha;
  484. }
  485. html.Location getLocation(String timeZone) {
  486. // Obtiene la ubicación de la zona horaria
  487. return getLocation(timeZone);
  488. }
  489. int obtenerAxiscount(Size s) {
  490. int axiscount = 8;
  491. if (s.width > 1300) {
  492. axiscount = 8;
  493. }
  494. if (s.width > 900 && s.width < 1300) {
  495. axiscount = 5;
  496. }
  497. if (s.width > 700 && s.width < 900) {
  498. axiscount = 4;
  499. }
  500. if (s.width > 600 && s.width < 700) {
  501. axiscount = 3;
  502. }
  503. if (s.width < 600) {
  504. axiscount = 2;
  505. }
  506. return axiscount;
  507. }
  508. imprimirExcel(String url, String nombre) async {
  509. var t = await SessionStorage().getToken();
  510. Map<String, String> headers = {
  511. 'Authorization': 'Bearer $t',
  512. 'Content-Type': 'application/json', // Puedes ajustar según sea necesario
  513. };
  514. http.Response response = await http.get(
  515. Uri.parse(url),
  516. headers: headers,
  517. );
  518. if (response.statusCode == 200) {
  519. // Obtener el contenido del archivo como Uint8List
  520. Uint8List fileBytes = response.bodyBytes;
  521. if (!kIsWeb) {
  522. // Lógica para dispositivos móviles y escritorio
  523. final directory = await getApplicationDocumentsDirectory();
  524. final path = '${directory.path}/$nombre.xlsx';
  525. final file = File(path);
  526. await file.writeAsBytes(fileBytes);
  527. final Uri fileUri = Uri.file(path);
  528. if (await canLaunchUrl(fileUri)) {
  529. await launchUrl(fileUri);
  530. } else {
  531. throw 'No se pudo abrir el archivo';
  532. }
  533. return; // Retorna después de manejar la lógica de dispositivos móviles
  534. }
  535. // Lógica específica para la web sigue aquí
  536. // Asegúrate de que este código solo se ejecute en la web
  537. if (kIsWeb) {
  538. // Crea y descarga el archivo para la web
  539. final blob = html.Blob([fileBytes]);
  540. final url = html.Url.createObjectUrlFromBlob(blob);
  541. final anchor = html.AnchorElement(href: url)
  542. ..setAttribute('download', '$nombre.xlsx')
  543. ..click();
  544. html.Url.revokeObjectUrl(url);
  545. }
  546. } else {
  547. print(
  548. 'Error al descargar el archivo. Código de estado: ${response.statusCode}');
  549. }
  550. }
  551. imprimirPdf(String url, String nombre) async {
  552. var t = await SessionStorage().getToken();
  553. Map<String, String> headers = {
  554. 'Authorization': 'Bearer $t',
  555. 'Content-Type': 'application/json', // Puedes ajustar según sea necesario
  556. };
  557. http.Response response = await http.get(
  558. Uri.parse(url),
  559. headers: headers,
  560. );
  561. if (response.statusCode == 200) {
  562. // Obtener el contenido del archivo como Uint8List
  563. Uint8List fileBytes = response.bodyBytes;
  564. // Crear un blob con los bytes del archivo
  565. final blob = html.Blob([fileBytes]);
  566. // Crear un objeto URL para el blob
  567. final url = html.Url.createObjectUrlFromBlob(blob);
  568. // Crear un enlace de descarga y hacer clic en él para descargar el archivo
  569. final anchor = html.AnchorElement(href: url)
  570. ..target = 'blank'
  571. ..download =
  572. '$nombre.pdf'; // Ajustar el nombre y la extensión del archivo
  573. anchor.click();
  574. // Liberar el objeto URL
  575. html.Url.revokeObjectUrl(url);
  576. } else {
  577. print(
  578. 'Error al descargar el archivo. Código de estado: ${response.statusCode}');
  579. }
  580. }
  581. Widget usuarioHeader(String nombre, String correo) {
  582. return Row(
  583. mainAxisAlignment: MainAxisAlignment.center,
  584. crossAxisAlignment: CrossAxisAlignment.center,
  585. children: [
  586. Column(
  587. mainAxisAlignment: MainAxisAlignment.center,
  588. crossAxisAlignment: CrossAxisAlignment.end,
  589. children: [
  590. Text(nombre,
  591. style: TextStyle(
  592. color: Colors.black, fontWeight: FontWeight.bold),
  593. textAlign: TextAlign.right),
  594. Text(correo,
  595. style: TextStyle(color: Colors.grey.shade700),
  596. textAlign: TextAlign.right),
  597. ]),
  598. Text(" "),
  599. CircleAvatar(
  600. child: Icon(Icons.verified_user, color: Colors.white),
  601. backgroundColor: Colors.black),
  602. Text(" "),
  603. ]);
  604. }
  605. Future eliminarMedia(
  606. BuildContext context, Media m, Function()? confirmacion) async {
  607. return await showDialog(
  608. context: context,
  609. builder: (context) {
  610. return AlertDialog(
  611. surfaceTintColor: AppTheme.secondary,
  612. title: const Text('¿Desea eliminar esta archivo?'),
  613. actions: [
  614. TextButton(
  615. onPressed: () {
  616. Navigator.pop(context);
  617. },
  618. child: const Text('Cancelar'),
  619. ),
  620. TextButton(
  621. onPressed: confirmacion,
  622. child: const Text(
  623. 'Sí, estoy seguro',
  624. style: TextStyle(color: Colors.red),
  625. ),
  626. ),
  627. ],
  628. );
  629. },
  630. );
  631. }