widgets_components.dart 24 KB

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