// ignore_for_file: use_build_context_synchronously, prefer_if_null_operators, prefer_conditional_assignment import 'dart:io'; import 'dart:typed_data'; import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; //import 'package:yoshi_papas_app/viewmodels/media_view_model.dart'; import 'package:intl/intl.dart'; import 'package:omni_datetime_picker/omni_datetime_picker.dart'; import 'package:flutter/material.dart' as d; import 'package:datetime_picker_formfield/datetime_picker_formfield.dart' as d2; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:flutter/foundation.dart' show kIsWeb; import 'package:path_provider/path_provider.dart'; //import '../data/session/session_storage.dart'; import '../models/media_model.dart'; import '../themes/themes.dart'; import 'package:timezone/timezone.dart' as tz; import 'package:http/http.dart' as http; import "package:universal_html/html.dart" as html; //import '../viewmodels/ordenes_view_model.dart'; //import 'dart:html'; //import 'dart:html' as html; encabezado( {double elevacion = 1, List? acciones, PreferredSize? bottom, Color? backgroundColor, String? nombre, Widget? leading = null, String? titulo, bool centerTitle = true}) { TextStyle estilo = const TextStyle(fontWeight: FontWeight.bold); if (acciones == null) { acciones = []; } return AppBar( leading: leading, elevation: elevacion, backgroundColor: backgroundColor, centerTitle: centerTitle, title: titulo == null ? Image.asset("assets/OlivaLogo.png", width: 100) : Text(titulo.toString(), style: estilo), actions: [ ...acciones, Image.asset("assets/OlivaLogo.png", width: 100), ], bottom: bottom); } tarjeta(Widget item, {Color color = Colors.white, double padding = 0}) { if (padding > 0) { return Padding( padding: const EdgeInsets.all(0), child: Card( color: color, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), margin: const EdgeInsets.only(bottom: 16), elevation: 0, borderOnForeground: true, child: Padding(padding: EdgeInsets.all(padding), child: item))); } return Card( color: color, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), margin: const EdgeInsets.only(bottom: 8), elevation: 0, borderOnForeground: true, child: Padding( padding: const EdgeInsets.all(8), child: item, )); } class Cargando extends StatelessWidget { const Cargando({super.key}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFE0E0E0), body: Center( child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( padding: const EdgeInsets.fromLTRB(16, 0, 16, 10), child: Image.asset("assets/OlivaLogo.png", height: 200)), const CircularProgressIndicator(backgroundColor: Colors.grey), Container(margin: const EdgeInsets.only(bottom: 8.0)), const Text("Cargando contenido...", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16, color: Colors.black)), const Text("Por favor espere.", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16, color: Colors.black), textAlign: TextAlign.center) ]), )); } } boton(String etiqueta, Function()? accion, {double height = 75, double width = 380}) { return Align( alignment: Alignment.topLeft, child: SizedBox( height: height, width: 380, child: ElevatedButton( style: ButtonStyle( shape: MaterialStatePropertyAll( RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), backgroundColor: MaterialStatePropertyAll(AppTheme.tertiary), ), onPressed: accion, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(etiqueta, style: TextStyle(fontSize: 18, color: AppTheme.quaternary)), ], ), ), ), ); } Future showHora(BuildContext context, DateTime? fecha) async { if (fecha == null) { return fecha; } final tiempo = await showTimePicker( useRootNavigator: false, helpText: "CAPTURAR HORA", confirmText: "ACEPTAR", cancelText: "CANCELAR", hourLabelText: "HORA", minuteLabelText: "MINUTO", initialEntryMode: TimePickerEntryMode.input, context: context, initialTime: TimeOfDay.fromDateTime(fecha), builder: (context, childs) { return MediaQuery( data: MediaQuery.of(context).copyWith( alwaysUse24HourFormat: true, padding: const EdgeInsets.all(1), size: const Size.square(1), textScaler: const TextScaler.linear(.8)), child: childs!); }, ); return d2.DateTimeField.combine(fecha!, tiempo); } Future showDatetimePicker(BuildContext context, DateTime? fecha, {DateTime? inicia, DateTime? termina, OmniDateTimePickerType tipo = OmniDateTimePickerType.dateAndTime, bool solofecha = false}) async { if (termina == null) { termina = DateTime(2030); } final f = await showDatePicker( context: context, initialDate: fecha ?? DateTime.now(), firstDate: inicia ?? DateTime(2023), lastDate: termina, cancelText: "CANCELAR", confirmText: "ACEPTAR", builder: (context, child) { return Theme( data: Theme.of(context).copyWith( colorScheme: ColorScheme.light( primary: AppTheme.primary, onSurface: AppTheme.secondary, ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( primary: AppTheme.secondary, ), ), ), child: child!, ); }, ); if (f == null || solofecha) { return f; } final tiempo = await showTimePicker( context: context, initialTime: TimeOfDay.fromDateTime(f), helpText: "CAPTURAR HORA", confirmText: "ACEPTAR", cancelText: "CANCELAR", hourLabelText: "HORA", minuteLabelText: "MINUTO", initialEntryMode: TimePickerEntryMode.input, builder: (context, child) { return Theme( data: Theme.of(context).copyWith( colorScheme: ColorScheme.light( primary: AppTheme.primary, onSurface: AppTheme.secondary, ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( primary: AppTheme.secondary, ), ), ), child: child!, ); }, ); return d2.DateTimeField.combine(f, tiempo); } class FechaSelectWidget extends StatelessWidget { final DateTime? fecha; final Function(DateTime) onFechaChanged; final String etiqueta; final BuildContext context; const FechaSelectWidget({ Key? key, required this.fecha, required this.onFechaChanged, required this.etiqueta, required this.context, }) : super(key: key); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( etiqueta, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), const SizedBox(height: 5), InkWell( onTap: () async { DateTime? d = await showDatetimePicker( context, fecha, tipo: OmniDateTimePickerType.date, solofecha: true, ); if (d == null) return; onFechaChanged(d); }, child: Container( decoration: BoxDecoration( border: Border.all(color: Colors.grey[400]!), borderRadius: BorderRadius.circular(10), ), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 15), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( fecha == null ? "Seleccionar" : DateFormat("dd/MM/yyyy").format(fecha!), style: TextStyle( color: fecha == null ? Colors.grey : Colors.black, ), ), const Icon(Icons.calendar_month), ], ), ), ), ], ); } } Widget circulo(Widget item, {Function()? accion, Color? color}) { color ??= Colors.black; return InkWell( onTap: accion, child: Container( decoration: BoxDecoration( border: Border.all( color: color, // <--- border color width: 2.0, ), borderRadius: const BorderRadius.all( Radius.circular(50) // <--- border radius here ), ), child: item)); } alerta(BuildContext context, {String? etiqueta = "Capturar búsqueda"}) { return showDialog( context: context, builder: (context) { return AlertDialog( title: Text(etiqueta.toString()), actions: [ Row(children: [ Expanded( child: TextButton( onPressed: () async { Navigator.pop(context); }, child: const Text('Continuar'), )) ]) ], ); }); } botonElevated( {Function()? accion, String? titulo = "Buscar", Color color = Colors.black}) { return ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: color, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), // <-- Radius )), onPressed: accion, child: Text( titulo.toString(), style: const TextStyle(color: Colors.white), ), ); } Widget xMedia(XFile m) { bool archivo = false; Widget icono = const Icon(Icons.file_copy, size: 50); int lastIndex = m.name.lastIndexOf('.'); String extension = ""; if (lastIndex != -1 && lastIndex < m.name.length - 1) { extension = m.name.substring(lastIndex + 1); } switch (extension) { case "mp4": archivo = true; icono = const Icon(Icons.video_file, size: 50); break; case "wav": archivo = true; icono = Image.asset("assets/audio-file.png"); archivo = true; break; case "jpeg": case "jpg": case "png": break; case "pdf": icono = Image.asset("assets/pdf-file.png"); archivo = true; break; case "csv": case "docx": icono = Image.asset("assets/word.png"); archivo = true; break; case "xlsx": icono = Image.asset("assets/excel.png"); archivo = true; break; } String nombre = m.name.toString(); if (nombre.length > 25) { nombre = "${m.name.toString().substring(0, 24)}..."; } return InkWell( onTap: () async { String url = m.path.toString(); await canLaunch(url) ? await launch(url, forceSafariVC: false, forceWebView: false) : print('Could not launch '); //aqui }, child: Stack(alignment: Alignment.center, children: [ Container( height: 100.0, width: 100.0, clipBehavior: Clip.antiAlias, decoration: BoxDecoration( border: Border.all(color: Colors.black, width: 1.0), borderRadius: const BorderRadius.all(Radius.circular(15.0)), ), child: archivo ? icono : Image.network(m.path.toString(), scale: 1) // _firma == null?const Icon(Icons.pages, size: 30, color: Colors.black): contenedorFirma, ), Positioned( bottom: 0, child: Container( width: 200, height: 40, color: Colors.grey.shade800, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( nombre, textAlign: TextAlign.center, textScaler: const TextScaler.linear(.8), style: const TextStyle(color: Colors.white), ), ]), )), ])); } Widget wMedia(Media m, {Function()? eliminar}) { bool archivo = false; Widget icono = const Icon(Icons.file_copy, size: 50); switch (m.extension) { case "mp4": archivo = true; icono = const Icon(Icons.video_file, size: 50); break; case "wav": archivo = true; icono = Image.asset("assets/audio-file.png"); archivo = true; break; case "jpeg": case "jpg": case "png": break; case "pdf": icono = Image.asset("assets/pdf-file.png"); archivo = true; break; case "csv": case "docx": icono = Image.asset("assets/word.png"); archivo = true; break; case "xlsx": icono = Image.asset("assets/excel.png"); archivo = true; break; } String fecha = ""; if (m.creado != null) { String timeZone = 'America/Hermosillo'; fecha = formatFechaConZonaHoraria(m.creado!, timeZone); } String nombre = m.nombre.toString(); if (nombre.length > 25) { nombre = "${m.nombre.toString().substring(0, 24)}..."; } return InkWell( onTap: () async { String url = m.ruta.toString(); await canLaunch(url) ? await launch(url, forceSafariVC: false, forceWebView: false) : print('Could not launch '); //aqui }, child: Stack(alignment: Alignment.center, children: [ Container( height: 160.0, width: 160.0, clipBehavior: Clip.antiAlias, decoration: BoxDecoration( border: Border.all(color: Colors.black, width: 1.0), borderRadius: const BorderRadius.all(Radius.circular(15.0)), ), child: archivo ? icono : Image.network(m.ruta.toString(), scale: 1) // _firma == null?const Icon(Icons.pages, size: 30, color: Colors.black): contenedorFirma, ), Positioned( bottom: 0, child: Container( width: 500, height: 40, color: Colors.grey.shade800, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( nombre, textAlign: TextAlign.center, textScaler: const TextScaler.linear(.8), style: const TextStyle(color: Colors.white), ), Text( fecha, textAlign: TextAlign.center, textScaler: const TextScaler.linear(.8), style: const TextStyle(color: Colors.white), ), ]), )), Positioned( left: 0, top: 0, child: ElevatedButton( onPressed: eliminar, style: ElevatedButton.styleFrom( shape: CircleBorder(), padding: EdgeInsets.all(16), ), child: Icon( Icons.delete, color: Colors.red.shade800, ), ), ), ])); } Widget agregarMedia( {Color color = Colors.green, Function()? accion, String titulo = "Agregar Media", Icon? icono, double tamano = 160}) { if (icono == null) { icono = Icon( Icons.add, size: tamano < 100 ? 60 : 100, color: Colors.white, ); } return InkWell( onTap: accion, child: Stack(alignment: Alignment.center, children: [ // Contenedor con un color de fondo y dimensiones específicas Container( width: tamano, height: tamano, color: color, ), // Texto flotante Positioned( child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ icono, titulo.isEmpty ? Container() : Text( titulo, style: const TextStyle( color: Colors.white, fontSize: 16, ), ), ])), ])); } String formatFechaConZonaHoraria(DateTime dateTime, String timeZone) { // Obtiene la ubicación de la zona horaria tz.Location location = tz.getLocation(timeZone); // Convierte la fecha a la zona horaria deseada tz.TZDateTime fechaConZona = tz.TZDateTime.from(dateTime, location); // Formatea la fecha con la zona horaria //String formattedFecha = DateFormat("dd/MM/yyyy HH:mm '($timeZone)'").format(fechaConZona); String formattedFecha = DateFormat("dd/MM/yyyy HH:mm").format(fechaConZona); return formattedFecha; } html.Location getLocation(String timeZone) { // Obtiene la ubicación de la zona horaria return getLocation(timeZone); } int obtenerAxiscount(Size s) { int axiscount = 8; if (s.width > 1300) { axiscount = 8; } if (s.width > 900 && s.width < 1300) { axiscount = 5; } if (s.width > 700 && s.width < 900) { axiscount = 4; } if (s.width > 600 && s.width < 700) { axiscount = 3; } if (s.width < 600) { axiscount = 2; } return axiscount; } // imprimirExcel(String url, String nombre) async { // var t = await SessionStorage().getToken(); // Map headers = { // 'Authorization': 'Bearer $t', // 'Content-Type': 'application/json', // Puedes ajustar según sea necesario // }; // http.Response response = await http.get( // Uri.parse(url), // headers: headers, // ); // if (response.statusCode == 200) { // // Obtener el contenido del archivo como Uint8List // Uint8List fileBytes = response.bodyBytes; // if (!kIsWeb) { // // Lógica para dispositivos móviles y escritorio // final directory = await getApplicationDocumentsDirectory(); // final path = '${directory.path}/$nombre.xlsx'; // final file = File(path); // await file.writeAsBytes(fileBytes); // final Uri fileUri = Uri.file(path); // if (await canLaunchUrl(fileUri)) { // await launchUrl(fileUri); // } else { // throw 'No se pudo abrir el archivo'; // } // return; // Retorna después de manejar la lógica de dispositivos móviles // } // // Lógica específica para la web sigue aquí // // Asegúrate de que este código solo se ejecute en la web // if (kIsWeb) { // // Crea y descarga el archivo para la web // final blob = html.Blob([fileBytes]); // final url = html.Url.createObjectUrlFromBlob(blob); // final anchor = html.AnchorElement(href: url) // ..setAttribute('download', '$nombre.xlsx') // ..click(); // html.Url.revokeObjectUrl(url); // } // } else { // print( // 'Error al descargar el archivo. Código de estado: ${response.statusCode}'); // } // } // imprimirPdf(String url, String nombre) async { // var t = await SessionStorage().getToken(); // Map headers = { // 'Authorization': 'Bearer $t', // 'Content-Type': 'application/json', // Puedes ajustar según sea necesario // }; // http.Response response = await http.get( // Uri.parse(url), // headers: headers, // ); // if (response.statusCode == 200) { // // Obtener el contenido del archivo como Uint8List // Uint8List fileBytes = response.bodyBytes; // // Crear un blob con los bytes del archivo // final blob = html.Blob([fileBytes]); // // Crear un objeto URL para el blob // final url = html.Url.createObjectUrlFromBlob(blob); // // Crear un enlace de descarga y hacer clic en él para descargar el archivo // final anchor = html.AnchorElement(href: url) // ..target = 'blank' // ..download = // '$nombre.pdf'; // Ajustar el nombre y la extensión del archivo // anchor.click(); // // Liberar el objeto URL // html.Url.revokeObjectUrl(url); // } else { // print( // 'Error al descargar el archivo. Código de estado: ${response.statusCode}'); // } // } Widget usuarioHeader(String nombre, String correo) { return Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [ Text(nombre, style: TextStyle( color: Colors.black, fontWeight: FontWeight.bold), textAlign: TextAlign.right), Text(correo, style: TextStyle(color: Colors.grey.shade900), textAlign: TextAlign.right), ]), Text(" "), CircleAvatar( child: Icon(Icons.verified_user, color: Colors.white), backgroundColor: Colors.black), Text(" "), ]); } Future eliminarMedia( BuildContext context, Media m, Function()? confirmacion) async { return await showDialog( context: context, builder: (context) { return AlertDialog( surfaceTintColor: AppTheme.secondary, title: const Text('¿Desea eliminar esta archivo?'), actions: [ TextButton( onPressed: () { Navigator.pop(context); }, child: const Text('Cancelar'), ), TextButton( onPressed: confirmacion, child: const Text( 'Sí, estoy seguro', style: TextStyle(color: Colors.red), ), ), ], ); }, ); }