El framework TolyUI para Flutter proporciona soluciones robustas para la gestión de mensajes y notificaciones globales, una funcionalidad crucial que no está completamente cubierta por las capacidades nativas de Flutter, más allá de los SnackBar del widget Scaffold. Para abordar esta necesidad en aplicaciones multiplataforma, especialmente en entornos de escritorio, TolyUI introduce dos componentes clave: Mensajes y Notificaciones, facilitando la implementación de avisos informativos y alertas contextuales.
Arquitectura del Sistema de Mensajes y Notificaciones
A pesar de la existencia de algunas bibliotecas de "toast" en pub.dev, estas suelen tener limitaciones, como la superposición de mensajes consecutivos en la misma ubicación, lo cual degrada la experiencia del usuario. TolyUI resuelve esta situación ofreciendo un módulo de notificaciones globales altamente personalizable, que incluye animaciones fluidas y posicionamiento inteligente.
Motivación del Diseño de Mensajes Globales
El sistema de mensajes de TolyUI permite que los avisos se desplieguen desde la parte superior o inferior de la pantalla. Estos elementos incorporan animaciones de opacidad y desplazamiento al aparecer. Cuando un mensaje superior se oculta, los mensajes inferiores se mueven suavemente hacia arriba para ocupar su lugar. De manera similar, los mensajes inferiores se ajustan si un elemento debajo de ellos se cierra.
Un Mensaje en TolyUI está diseñado para:
- Proporcionar retroalimentación concisa sobre operaciones (éxito, advertencia, error).
- Desaparecer automáticamente tras un período configurable.
- Ser una forma de retroalimentación ligera que no interrumpe la interacción del usuario.
Motivación del Diseño de Notificaciones Globales
A diferencia de los mensajes, las Notificaciones suelen contener información más elaborada y, en ocasiones, requieren permanecer en pantalla hasta que el usuario realice una acción. Sus atributos distintivos son:
- Posicionamiento flexible en cualquiera de las cuatro esquinas de la pantalla.
- Capacidad para mostrar contenido más complejo.
- Función como alertas pasivas o recordatorios a nivel de sistema.
- Opción de cierre manual o configuración para no desaparecer automáticamente.
Modularización: el Módulo tolyui_message
Para maximizar la granularidad y la flexibilidad en su uso, TolyUI adopta un modelo de empaquetado modular. El módulo principal de retroalimentación (tolyui\_feedback) se ha subdividido, dando origen a tolyui\_message como un módulo independiente dedicado exclusivamente a los mensajes y notificaciones. Esta estructura jerárquica permite que los módulos padres accedan a las funcionalidades de sus hijos, mientras que estos últimos pueden ser utilizados de forma autónoma. Por ejemplo, un desarrollador interesado únicamente en las notificaciones puede integrar tolyui\_message directamente, sin necesidad de todo el framework TolyUI. Este enfoque modular es fundamental para una construcción de framework robusta y facilita la colaboración.
Uso de Mensajes Globales
Los mensajes y notificaciones globales de TolyUI se construyen sobre una capa flotante que abarca toda la aplicación. Para habilitarlos, es imprescindible envolver el widget raíz de su aplicación con el componente TolyMessage:
void main() {
runApp(TolyMessage(child: MiAplicacion()));
}
Posicionamiento y Contenido Enriquecido
Los mensajes pueden mostrarse desde la parte superior o inferior de la pantalla. TolyUI gestiona automáticamente las animaciones de desplazamiento cuando se activan múltiples mensajes, una característica destacada y optimizada del framework.
Para mostrar un mensaje de información básico, invoque \$message.info y pase el texto:
\$message.info(message: 'Este es un mensaje informativo común.');
Si desea que el mensaje aparezca desde la parte inferior, establezca el parámetro position a MessagePosition.bottom:
\$message.info(
message: 'Este es un mensaje que aparece desde abajo.',
position: MessagePosition.bottom,
);
Para mensajes con formato enriquecido, utilice el parámetro richMessage, que acepta un objeto InlineSpan:
InlineSpan textoEnriquecido = const TextSpan(children: [
TextSpan(text: 'Por favor, contácteme en este correo: '),
TextSpan(style: TextStyle(color: Colors.blue), text: 'contacto@ejemplo.com')
]);
\$message.info(richMessage: textoEnriquecido);
Tipos de Mensajes Predefinidos
El objeto \$message ofrece métodos convenientes para mostrar cuatro tipos estándar de mensajes: success (éxito), warning (advertencia), info (información) y error (error). Además, el parámetro plain:true permite un estilo con fondo blanco y borde sombreado.
// Mensaje de éxito
\$message.success(message: '¡Felicidades, la operación fue exitosa!');
// Mensaje de advertencia
\$message.warning(message: 'Advertencia, se necesita su atención.');
// Mensaje informativo
\$message.info(message: 'Este es un mensaje informativo estándar.');
// Mensaje de error
\$message.error(message: '¡Vaya! Ocurrió un error inesperado.');
Widgets de Contenido Personalizado para Mensajes
Los desarrolladores pueden usar el método \$message.emit para mostrar cualquier widget personalizado como contenido de un mensaje. Los parámetros animaDuration controlan la duración de la animación, duration el tiempo de visualización, y offset el desplazamiento del mensaje.
Por ejemplo, para mostrar un panel de información personalizado:
\$message.emit(
child: const PanelInfoDepuracion(
rutaImagen: 'assets/imagenes/avatar_usuario.webp',
titulo: 'Usuario de Prueba',
dato1: 'ID: usuario1234',
dato2: 'Ubicación: Ciudad Flutter',
),
);
El tiempo de visualización predeterminado es de 3 segundos, con una animación de 250 ms y un desplazamiento vertical de 16 píxeles lógicos. Estos valores son ajustables:
\$message.emit(
position: MessagePosition.bottom,
offset: const Offset(0, 10),
duration: const Duration(seconds: 2),
animaDuration: const Duration(milliseconds: 500),
child: const PanelInfoDepuracion(
rutaImagen: 'assets/imagenes/avatar_usuario.webp',
titulo: 'Usuario de Prueba',
dato1: 'ID: usuario1234',
dato2: 'Ubicación: Ciudad Flutter',
),
);
Mensajes Cerrables por el Usuario
Los mensajes de TolyUI permiten el cierre manual. Al cerrarse, los mensajes inferiores se desplazan automáticamente para rellenar el espacio. Para mensajes estándar, se activa con closeable:true:
\$message.success(
closeable: true,
duration: const Duration(seconds: 5),
message: 'Mensaje de éxito que puede cerrar manualmente.',
);
Para widgets personalizados, la función de cierre se expone a través del parámetro builder, permitiendo asociarla a un evento específico dentro del widget, como un botón:
\$message.emit(
duration: const Duration(seconds: 5),
builder: (_, cerrarNotificacion) => PanelInfoDepuracion(
rutaImagen: 'assets/imagenes/avatar_usuario.webp',
titulo: 'Usuario de Prueba',
dato1: 'ID: usuario1234',
dato2: 'Ubicación: Ciudad Flutter',
alCerrar: cerrarNotificacion,
),
);
Uso de Notificaciones Globales
Las notificaciones globales son paneles de mensaje que pueden ubicarse en las cuatro esquinas de la pantalla. Comparten características como efectos de entrada animados, desplazamiento y la opción de cierre automático.
Control del Cierre Automático
Por defecto, las notificaciones se despliegan desde la esquina superior derecha y se ocultan automáticamente después de 3 segundos. Sin embargo, esta duración es configurable.
Para mostrar una notificación, se utilizan métodos como \$message.infoNotice, donde XXX corresponde al tipo (info, success, etc.). Estos métodos aceptan widgets para title y subtitle:
String tituloNotificacion = 'Título de la Notificación';
String subtituloNotificacion = 'Esta notificación se cerrará automáticamente.';
TextStyle estiloTitulo = const TextStyle(fontSize: 16, fontWeight: FontWeight.bold);
\$message.infoNotice(
title: Text(tituloNotificacion, style: estiloTitulo),
subtitle: Text(subtituloNotificacion),
);
Para que una notificación permanezca abierta hasta que el usuario la cierre manualmente, se establece duration: Duration.zero:
\$message.infoNotice(
duration: Duration.zero, // La notificación no se cierra automáticamente
title: Text(tituloNotificacion, style: estiloTitulo),
subtitle: Text(subtituloNotificacion),
);
Posicionamiento en las Esquinas
Las notificaciones pueden posicionarse en las cuatro esquinas (superior izquierda, superior derecha, inferior izquierda, inferior derecha) usando el enumerado NoticePosition. También soportan los mismos tipos de estilo (éxito, advertencia, información, error).
enum NoticePosition { topLeft, topRight, bottomLeft, bottomRight; }
Para mostrar una notificación de éxito en la esquina inferior izquierda, se utiliza el método successNotice y se ajusta el parámetro position:
\$message.successNotice(
position: NoticePosition.bottomLeft,
title: const Text(
'Notificación de Éxito',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
subtitle: const Text('Este es un aviso exitoso desde la esquina inferior izquierda.'),
);
Contenido Personalizado y Desplazamiento en Notificaciones
El método \$message.emitNotice permite insertar widgets personalizados como contenido de la notificación. La función cerrar, proporcionada por el builder, permite gestionar el cierre desde el widget personalizado. El parámetro offset ajusta el desplazamiento del panel.
\$message.emitNotice(
builder: (_, cerrar) => PanelInfoDepuracion(
rutaImagen: 'assets/imagenes/avatar_usuario.webp',
titulo: 'Usuario Personalizado',
dato1: 'Correo: custom@example.com',
dato2: 'ID: XYZ789',
alCerrar: cerrar,
),
);
Configuración de Temas y Modos Claro/Oscuro
Para mantener una coherencia visual en toda la aplicación, TolyUI permite configurar un tema unificado para mensajes y notificaciones, ofreciendo a los desarrolladores la flexibilidad de adaptar el estilo predeterminado a sus requisitos específicos.
Datos de Tema Configurables
TolyUI organiza la configuración temática en dos aspectos: comportamiento y apariencia.
La configuración de comportamiento, que incluye duraciones, posiciones y dseplazamientos al mostrarse, se define en TolyMessageShowTheme:
final Duration? duracion;
final Duration? duracionAnimacion;
final MessagePosition? posicionMensaje;
final NoticePosition? posicionNotificacion;
final Offset? desplazamientoNotificacion;
final Offset? desplazamientoMensaje;
final double? separacion;
La configuración de apariencia, que abarca los colores para los cuatro tipos de estilo, fondo, iconos, radio de borde y la opción de cierre, se define en TolyMessageStyleTheme:
final MessageStyle estiloExito;
final MessageStyle estiloInfo;
final MessageStyle estiloError;
final MessageStyle estiloAdvertencia;
final BorderRadius? radioBordeMensaje;
final BorderRadius? radioBordeNotificacion;
final bool? esPlano; // Estilo plano
final bool? esCerrable;
class MessageStyle {
final IconData icono;
final Color colorFondo;
final Color colorPrimerPlano;
final Color colorBorde;
}
Aplicación de Temas en TolyUI
Los temas se integran en Flutter utilizando el parámetro extensions de ThemeData. TolyUI proporciona datos de tema predeterminados, pero los desarrolladores pueden construir sus propios objetos TolyMessageShowTheme y TolyMessageStyleTheme.
Para el modo oscuro, TolyUI ofrece TolyMessageStyleTheme.tolyuiDark(). El siguiente ejemplo muestra cómo establecer una duración predeterminada de 5 segundos y cómo integrar los temas:
Dado que TolyMessage se sitúa por encima de MaterialApp para asegurar que los mensajes se visualicen correctamente, su contexto no hereda automáticamente los cambios de tema del MaterialApp. Por ello, es crucial pasar los datos del tema y el modo de tema del MaterialApp directamente a TolyMessage:
@override
Widget build(BuildContext context) {
// Asumiendo que EstadoAplicacion y LogicaAplicacion gestionan el estado del tema
EstadoAplicacion estadoApp = context.watch<LogicaAplicacion>().estado;
ThemeData miTemaClaro = lightTheme; // Reemplazar con tu ThemeData claro
ThemeData miTemaOscuro = darkTheme; // Reemplazar con tu ThemeData oscuro
ThemeMode modoTema = estadoApp.modoTema;
return TolyMessage(
theme: miTemaClaro,
darkTheme: miTemaOscuro,
themeMode: modoTema,
child: MaterialApp.router(
routerConfig: miConfiguracionRutas, // Reemplazar con tu RouterConfig
debugShowCheckedModeBanner: false,
theme: miTemaClaro,
darkTheme: miTemaOscuro,
themeMode: modoTema,
title: 'TolyUI App',
),
);
}
Con esta configuración, tanto los mensajes como los paneles de notificación soportarán correctamente el modo oscuro. Los esquemas de color y estilos pueden personalizarse aún más a través de la configuración del tema.