widgets_components.dart 24 KB

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