import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../theme/app_colors.dart'; /// Función estándar para abrir modales médicos en Hidalyx Med. /// /// Cumple con la regla institucional estricta: /// - barrierDismissible: false (NO se cierra haciendo clic en el exterior). /// - Solamente se cierra mediante la tecla ESC o el botón (X) superior derecho. Future showMedicalModal({ required BuildContext context, required WidgetBuilder builder, bool useRootNavigator = true, }) { return showDialog( context: context, barrierDismissible: false, barrierColor: Colors.black.withValues(alpha: 0.5), useRootNavigator: useRootNavigator, builder: builder, ); } /// Contenedor base estándar para todos los modales de Hidalyx Med. /// /// Implementa: /// 1. Cierre garantizado con tecla [ESC] a nivel hardware y de atajos. /// 2. Botón con icono de cerrar (X) en la esquina superior derecha. /// 3. Bloqueo de cierre al tocar fuera del diálogo. class MedicalModalDialog extends StatefulWidget { final Widget? titleIcon; final String title; final Widget? subtitle; final Widget child; final double maxWidth; final double maxHeight; final VoidCallback? onClose; final Widget? bottomBar; final List? actions; const MedicalModalDialog({ super.key, this.titleIcon, required this.title, this.subtitle, required this.child, this.maxWidth = 740, this.maxHeight = 620, this.onClose, this.bottomBar, this.actions, }); @override State createState() => _MedicalModalDialogState(); } class _MedicalModalDialogState extends State { @override void initState() { super.initState(); HardwareKeyboard.instance.addHandler(_handleHardwareKey); } @override void dispose() { HardwareKeyboard.instance.removeHandler(_handleHardwareKey); super.dispose(); } bool _handleHardwareKey(KeyEvent event) { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.escape) { _close(); return true; } return false; } void _close() { if (!mounted) return; if (widget.onClose != null) { widget.onClose!(); } else { Navigator.of(context).maybePop(); } } @override Widget build(BuildContext context) { return Dialog( backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), child: Container( constraints: BoxConstraints( maxWidth: widget.maxWidth, maxHeight: widget.maxHeight, minWidth: 320, ), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.18), blurRadius: 28, offset: const Offset(0, 10), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(16), child: Column( mainAxisSize: MainAxisSize.min, children: [ // Encabezado Superior con Botón (X) de Cierre Container( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), decoration: const BoxDecoration( color: Colors.white, border: Border( bottom: BorderSide(color: AppColors.border), ), ), child: Row( children: [ if (widget.titleIcon != null) ...[ widget.titleIcon!, const SizedBox(width: 12), ], Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.title, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w700, color: AppColors.textPrimary, ), ), if (widget.subtitle != null) ...[ const SizedBox(height: 2), widget.subtitle!, ], ], ), ), if (widget.actions != null) ...[ ...widget.actions!, const SizedBox(width: 8), ], // Botón oficial de cerrar (X) en esquina superior derecha IconButton( icon: const Icon( Icons.close_rounded, color: AppColors.textSecondary, size: 20, ), tooltip: 'Cerrar (Esc)', splashRadius: 20, onPressed: _close, ), ], ), ), // Contenido Principal Expanded(child: widget.child), // Barra Inferior Informativa (Opcional) if (widget.bottomBar != null) widget.bottomBar!, ], ), ), ), ); } }