gp_design 0.1.0
gp_design: ^0.1.0 copied to clipboard
Colección de componentes, temas, tokens visuales y utilidades responsivas para construir apps Flutter consistentes con el sistema de diseño GP.
0.1.0 #
-
Nuevo (export):
GpProfilePhotoAvatarFrame— existía ensrc/widgets/profile/pero no estaba en el barrel público (gp_design.dart), así que ninguna app consumidora podía usarlo. Es un avatar circular con anillo de degradé y sombra, pensado como hero de pantallas de perfil; ahora exportado. -
Nuevo:
GpTheme.light/darkpasan a parámetros nombrados (antes 1-2 posicionales opcionales; ningún call site del repo los usaba posicional, así que no rompe nada) y aceptantextSize(GpTextSizeScale, misma idea queGpColorPalettepero para la escala tipográfica — a diferencia deGpSpacing/GpBorderRadius,GpTextSizesolo se usaba adentro degp_theme.dart, así que fue seguro/barato hacerlo inyectable sin tocar el resto de la librería) yfontFamily(String?, hoy sin soporte en absoluto — usa la fuente default de Flutter si no se pasa). -
Fix:
GpText,GpOtpInputyGpPinInputtenían fallbacks de color de último recurso (?? GpColors.grey4/primary/danger/etc.) que ignoraban el theme activo — casi inalcanzables en uso normal (el theme deGpTheme.light/darksiempre los deja resueltos antes), pero si alguna vez se activaban, caían al color fijo de la paleta default en vez de al modo oscuro/paleta custom. Ahora usantheme.colorScheme.xxxcomo último recurso. -
Fix:
GpSnackBarresolvía elThemeDatasolo si le pasabancontextdirecto (context != null ? Theme.of(context) : null) — si se llamaba sincontext(el caso "desde un servicio/interceptor"), el estilo caía a los defaults fijos deGpColors, ignorando modo oscuro y cualquier paleta custom inyectada víaGpTheme.light(colors:)/dark(colors:). Ahora usaGpNavigator.resolve(), igual que el resto de la librería. -
Nuevo:
GpColors/GpDarkColors(los defaults, sin cambios) ahora tienen versión instanciable —GpColorPalette/GpDarkColorPalette— que se le puede pasar aGpTheme.light(colors:)/dark(colors:)para que una app consumidora inyecte su propia paleta de marca sin tocar la librería. Los tonos "container" de banners/badges (éxito, error, warning, info) ahora se derivan del color inyectado (Color.lerphacia blanco/negro) en vez de quedar fijos, para que combinen con cualquier paleta. -
Nuevo:
GpQrCode({data:})— pinta un código QR local a partir de un texto (package:qr_flutter), sin red ni nada asíncrono de por medio. Para el caso inverso (leer un QR con la cámara) seguí usando el scanner depackage:gp_design/scanner.dart— son casos separados,GpQrCodeno depende de cámara ni de permisos. Personalizable: tamaño, colores, radio del borde, nivel de corrección de errores, e imagen embebida centrada (ej. el logo de la app). -
Nuevo:
GpPageScaffold/GpNavigationShellaceptanappBarBackgroundColor/appBarForegroundColor— antesbackgroundColorsolo pintaba elScaffold(el body); no había forma de cambiar el color delAppBaren sí sin salirse deGpAppBardirecto. -
Fix (doc):
GpNavigationShell— documentado que cuando cada tab debodyarma su propia pantalla completa (showAppBar: falseen el shell), también conviene pasaruseSafeArea: falseybodyPadding: EdgeInsets.zero: por defecto el shell agrega su propio safe-area top inset y 16dp de padding genérico alrededor del body, pensados para un body "suelto" sin chrome propio — dejarlos prendidos deja un marco en blanco alrededor de cada tab. -
Nuevo:
GpWebView/GpWebViewScreen/GpWebViewModalaceptanshowLoadingOverlay(bool, defaulttrue) — mientras carga, muestra un overlay conGpProgresscircular (con porcentaje) sobre un fondo sólido, tapando la página en blanco que se ve por default hasta que el sitio pinta su primer frame. Poné esto enfalsepara volver a la barra fina de progreso arriba que había antes. -
Nuevo:
GpWebView/GpWebViewScreen/GpWebViewModalaceptandisableInputZoom(bool, defaulttrue) — fuerza el viewport del sitio amaximum-scale=1, user-scalable=no(creando el<meta name="viewport">si no existe) para que el navegador no haga zoom automático al enfocar un input, sin importar qué viewport traiga el sitio. Como efecto secundario también desactiva el pinch-to-zoom manual — poné esto enfalsesi tu contenido sí necesita zoom (ej. un PDF o una imagen grande). -
Fix:
GpCoachMarks,GpSignatureScreenyGpPopupCarousel(agregados en esta misma tanda) usabanTextButton/IconButtonde Flutter en vez deGpButton/GpIconButtonpropios en un par de botones — quedaba inconsistente con el resto del sistema de diseño (tono/tamaño/estados no salían del theme compartido). Ya usan los widgets GP. -
Nuevo:
GpSignatureScreen— pantalla para capturar una firma a mano alzada; al tocar "Guardar" haceNavigator.popcon el PNG capturado comoUint8List(nullsi se cancela sin guardar). No sube nada a ningún backend ni depende de ningún paquete de terceros (usadart:ui/CustomPainterdirecto) — la app decide qué hacer con los bytes (ej. mandarlos pormultipartconGpHttpClient). Personalizable: color/grosor del trazo, color de fondo de la imagen exportada, textos, resolución (pixelRatio) de la exportación. -
Nuevo:
GpPopupCarousel.show(context:, items:)— carrusel de popups deslizable en un diálogo centrado (víaGpModal.show), pensado para anuncios/promos que se buscan después del login y pueden ser varios. CadaGpPopupCarouselItemes una imagen (GpImage, con loading/error ya resueltos) con su propioonTapopcional — la librería no sabe nada de rutas ni de cómo navegar, solo avisa que se tocó el slide (y cierra el popup antes de avisar); la app decide qué hacer (abrir un link externo, navegar a una pantalla propia, etc.). Puntitos de posición solo si hay más de 1 item, botón de cerrar opcional (dismissible). El tamaño se elige consize: GpPopupCarouselSize(compact/medium/fullscreen, defaultmedium) — cada preset es un % del ancho/alto de pantalla (con un tope en píxeles para que no se vea absurdo en tablet/desktop), no un valor fijo, para que se vea consistente en cualquier dispositivo. -
Nuevo:
GpNavigationShellaceptaitemKeys(List<GlobalKey>?, mismo orden quedestinations) — se adjuntan a cada ítem de la bottom navigation bar (mobile) para que la app pueda medir su posición real en pantalla después del build, por ejemplo para armar un coach mark/tutorial que señale cada tab la primera vez que aparece. No aplica a la variante de rail/drawer (tablet/desktop) todavía. -
Nuevo:
GpCoachMarks.show(context:, steps:)— tutorial de "primera vez" tipo spotlight, recorta un hueco alrededor de un widget ya construido (víaGlobalKey, ej. lasitemKeysdeGpNavigationShellde arriba) con una tarjeta explicando qué es, y avanza paso a paso. Devuelve una función para cerrarlo antes de tiempo. Los textos de los botones (skipLabel/nextLabel/doneLabel) son parámetros con default en español, igual queGpModal.showConfirm— no dependen de ningún mecanismo de i18n de la app consumidora. -
Cambio:
contextpasa a ser opcional (antesrequired) enGpModal.show/showCustomModal/showConfirm/showAlert,GpWebViewModal.show,GpLinkLauncher.openyGpCoachMarks.show— unifica el criterio que ya usabanGpNotification/GpSnackBar: si no lo pasás, se resuelve solo víaGpNavigator.navigatorKey(nuevoGpNavigator.resolve()), para poder llamarlos desde donde no hay unBuildContexta mano (un servicio, un interceptor). Pasarlo explícito sigue siendo lo normal y recomendado al llamar desde dentro de un widget — no cambia el comportamiento de ningún call site existente. No es breaking excepto enGpLinkLauncher.open:contextpasa de ser el primer parámetro posicional a uno nombrado (GpLinkLauncher.open(context: context, url: ...)), para quedar consistente con el resto — antes era el único de esta familia que no usaba nombrado. -
Fix:
GpHttpClientagregaba suErrorInterceptorprimero en la cadena de interceptores. Como usahandler.reject()(que por defecto no deja pasar el error a los interceptores siguientes), elRetryInterceptory elTokenRefreshInterceptornunca llegaban a ejecutarse cuandoenableErrorInterceptorestaba activo (el default):retryOptionsno tenía ningún efecto. Ahora elErrorInterceptorse agrega al final, después de Auth, Retry, TokenRefresh y los interceptores custom. -
network.dartahora re-exporta los tipos dedionecesarios para escribir interceptores propios (Interceptor,DioException,DioExceptionType,RequestOptions,RequestInterceptorHandler,ResponseInterceptorHandler,ErrorInterceptorHandler,Response,Options,CancelToken), para no obligar a los consumidores a declarardiocomo dependencia aparte. -
Fix:
GpNotification.show()reemplazaba de inmediato cualquier notificación visible (_overlayEntry.remove()antes de mostrar la nueva). Si llegaban dos notificaciones seguidas (ej. dos pushes casi al mismo tiempo), la primera desaparecía sin que el usuario llegara a verla. Ahora se encola y se muestra automáticamente cuando la actual termina de cerrarse;hide()también avanza la cola. -
Nuevo:
GpToneIcons.iconFor(GpSemanticTone)centraliza el mapeo tono → ícono que antes vivía duplicado y privado dentro deGpBanner(_iconForTone). Queda público para que apps consumidoras que arman sus propias tarjetas/estados reusen el mismo criterio en vez de reimplementarlo.GpBannerahora delega en este helper. -
Nuevo módulo
package:gp_design/webview.dart(entry point aparte, igual queauth.dart/profile.dart, para no forzarwebview_fluttera quien no lo use):GpWebViewScreen(pantalla completa con el chrome estándar),GpWebViewModal(mismo contenido en un bottom sheet víaGpModal) yGpWebView(el widget base, por si alguna pantalla lo necesita embebido en un layout propio). Los tres resuelven loading (barra de progreso) y error-con-reintento sin que cada pantalla repita ese boilerplate, y exponenonNavigationRequestpara que la app decida qué navegaciones deja seguir dentro del WebView y cuáles bloquea (para, por ejemplo, abrirlas en el navegador del sistema). Usawebview_flutter ^4.14.1(última versión estable, requiere Flutter >=3.38.0 — se subió el mínimo del paquete de ese entorno). -
Nuevo módulo
package:gp_design/permissions.dart:GpPermissions.request(context, permission: ...)pide un permiso del sistema (cámara, ubicación, etc.) mostrando antes una explicación con el diálogo estándar (GpModal.showConfirm) — mismo look sin importar qué módulo lo dispare — y, si el usuario ya lo negó permanentemente, ofrece ir a Ajustes en vez de reintentar un prompt nativo que el SO ya no va a volver a mostrar. Usapermission_handler ^13.0.1y re-exportaPermission/PermissionStatuspara no obligar a declarar esa dependencia aparte. -
Nuevo módulo
package:gp_design/scanner.dart:GpQrScannerScreen, pantalla de escaneo (QR y códigos de barra) con marco de escaneo (esquinas en L), botón de linterna reactivo al estado real de la cámara y mensaje de guía configurable. Pide permiso de cámara víaGpPermissionsantes de encender la cámara (autoStart: false). Usamobile_scanner ^7.4.0. -
Nuevo módulo
package:gp_design/html.dart:GpHtmlViewrenderiza HTML (términos y condiciones, contenido remoto) con la tipografía del tema GP en vez de que cada pantalla arme su propio estilo. Usaflutter_widget_from_html ^0.17.2. -
Nuevo módulo
package:gp_design/launcher.dart:GpLinkLauncher.open(context, url: ..., mode: ...)decide entre navegador externo,GpWebViewScreenoGpWebViewModal(la política de cuál usar la define la app, la librería solo da el mecanismo);GpWhatsApp.open(phone: ..., message: ...)abre un chat de WhatsApp víawa.me. Usaurl_launcher ^6.3.2; los modos internos reusanwebview.darty por lo tanto también carganwebview_fluttersi se usan. -
Fix:
GpProgresscrasheaba ('widget.tween.end != null') en modo indeterminado (sinvalue, ej. un spinner mientras se resuelve un permiso) porque armaba unTween<double?>(end: null)y se lo pasaba aTweenAnimationBuilder, que no acepta unendnulo. Ahora, cuando no hayvalue, se salta la animación y se renderiza el indicador nativo de Flutter convalue: null(que sí soporta el modo indeterminado por su cuenta); la animación conTweenAnimationBuilderse sigue usando solo para transiciones entre valores conocidos (modo determinado). -
GpWebViewScreenahora reenvíatitleWidget,actions,leadingycenterTitleaGpPageScaffold— antes solo aceptaba untitlede texto y no había forma de agregar botones ni cambiar el título por un widget propio. -
Nuevo:
GpWebView/GpWebViewScreen/GpWebViewModalaceptanheaders(Map<String, String>?) para la carga inicial — pensado para SSO, pasando algo como{'Authorization': 'Bearer $token'}a un sitio que valida el mismo token que ya tiene la app. Solo aplica a esa primera petición: si el sitio es una SPA que hace sus propias llamadas después, no las va a heredar automáticamente. También se corrigió_retry()para que re-envíe esos headers (antes usabacontroller.reload(), que no los reenvía). -
Nuevo:
GpWebView/GpWebViewScreen/GpWebViewModaltambién aceptancookies(List<WebViewCookie>?, tipo re-exportado porwebview.dart) — alternativa aheaderspara sitios que arman su sesión leyendo una cookie del dominio en vez de un header. Se setean víaWebViewCookieManagerantes de la carga inicial (y en cada retry). -
Nuevo:
debugLogConsole(bool, defaultfalse) enGpWebView/GpWebViewScreen/GpWebViewModal— si está activo, manda cadaconsole.log/warn/errorde la página pordebugPrint, para poder ver en la consola de Flutter qué está logueando el sitio (útil para diagnosticar librerías como MSAL.js sin acceso a las devtools del navegador). -
Nuevo:
debugLogNetwork(bool, defaultfalse) enGpWebView/GpWebViewScreen/GpWebViewModal— inyecta JS que sobreescribefetch/XMLHttpRequestpara loguear método, URL y respuesta de cada pedido de la página (por el mismo canal quedebugLogConsole, ya quewebview_flutterno expone las llamadas de red de la página nativamente). Útil para diagnosticar un pedido que se queda colgado sin acceso a las devtools del navegador. -
Fix: con
debugLogConsoleactivo, unconsole.error('algo', unError)de la página llegaba como{}— elmessage/stackde unErrorde JS no son propiedades enumerables, así que se pierden al serializar el objeto para pasarlo al puente nativo. Ahora se inyecta un script que sobreescribeconsole.log/warn/error/infopara extraer esos campos (y los de cualquier objeto, víagetOwnPropertyNames) antes de loguear, así el mensaje real llega completo. -
Nuevo:
debugLogStorage(bool, defaultfalse) enGpWebView/GpWebViewScreen/GpWebViewModal— vuelcasessionStorage/localStoragepor el mismo canal quedebugLogConsolecada vez que la página termina de cargar. Útil para confirmar de dónde lee (o no encuentra) datos una página sin acceso a las devtools del navegador. -
Nuevo:
onControllerReady(void Function(WebViewController)?) enGpWebView/GpWebViewScreen/GpWebViewModal— entrega elWebViewControlleruna vez creado, para casos que el widget no cubre de fábrica (recargar desde un botón propio, correr JS custom, limpiarlocalStorage/cookies para reiniciar una sesión de prueba, etc.).
0.0.3 #
- Se amplía el sistema de tematización global con extensiones para inputs y superficies, permitiendo personalizar tipografía, bordes, radios, sombras y estilos de componentes desde
GpTheme. - Se alinean múltiples widgets al tema compartido, incluyendo inputs, badges, banners, mensajes inline, cards, navegación, modal, drawer, floating navigation bar y tabla responsive.
- Se mejora la estrategia responsive separando clase de dispositivo y ancho de layout para evitar clasificaciones incorrectas en teléfonos landscape.
- Se fortalecen componentes adaptativos y de productividad como
GpPageHeader,GpSegmentedControl,GpCommandBar,GpStatsGrid,GpSplitView,GpMasterDetailLayout,GpSectionCard,GpBreadcrumbyGpInlineMessage. - Se añaden primitives reutilizables para notificaciones y navegación, incluyendo modelos y widgets de notification center, presenter, permission card, route metadata y page transitions.
- Se refuerza la capa HTTP basada en
diocon mejor manejo de errores, soporte paraPATCH,CancelToken, requests genéricos y helpers para extraerdatade respuestas.
0.0.2 #
GpButtonahora acepta íconos provenientes de assets medianteiconAssetyiconAssetColor, manteniendo la lógica de estados y loaders integrada.- Nuevo
GpPhoneInputcon selector de país basado encountry_picker, validación integrada y callback para recibir el número y códigos seleccionados.
0.0.1 #
- Primera publicación del sistema de diseño GP.
- Incluye componentes de UI como botones, tipografía, diálogos, tiles, app bar, inputs y loaders.
- Añade temas claro/oscuro, helpers de espaciado, radios y tamaños de texto.
- Proporciona layout responsive con
GpRowyGpResponsive. - Integra interceptores
diopara autenticación y manejo de errores.