Component · Balance Card

Balance Card

El hero del dashboard. Muestra el portafolio del usuario: valorización total en COP (referencia, no saldo gastable) y los saldos cripto reales de BTC, ETH y USDT. En MiCapi no existe "saldo COP" — el peso solo existe en tránsito durante una compra. Este card es donde se decide si la app parece exchange profesional o neobank claro.

Dashboard hero 328dp · w100% − 16dp margins radius 16dp · padding 16dp privacy toggle
Anatomy

Estructura del card

Siete elementos. La jerarquía es deliberada: valorización arriba grande, saldos cripto abajo como la verdad operativa. La COP es referencia; el cripto es lo que el usuario realmente tiene.

Valor estimado en COP
$2.845.320
COP
+2,3% 24h
₿
Bitcoin
BTC
0,01548 BTC
≈ $1.878.640
Ethereum
ETH
0,2156 ETH
≈ $786.180
Tether
USDT
45,0000 USDT
≈ $180.500
1

Label de valorización

"Valor estimado en COP" — el copy es explícito: no es saldo, es una estimación. Ícono trending-up refuerza que es valorización de mercado. Nunca "Saldo COP".

2

Toggle privacy (ojo)

Icono eye / eye-off en la esquina superior derecha. Tap → oculta todos los montos del card. Estado persiste vía SharedPreferences.

3

Valorización total · hero amount

Mono tabular, 32dp, peso 600. Sufijo COP en peso menor. Es lo más grande del card, pero no es saldo gastable — solo referencia.

4

Variación 24h

Chip semántico — verde success si sube, rojo error si baja. Flecha direccional + porcentaje tabular. Sufijo 24h aparte.

5

Divider

Hairline #F0F4F3 separa la valorización (referencia) de los saldos cripto (operativos). Es la frontera conceptual del card.

6

Filas de activo · tappable

Icono 40dp con color de marca · nombre + símbolo · saldo cripto + equivalente COP. Cada fila es InkWell → detalle del activo. Page transition slide+fade.

7

Tipografía tabular en montos

Mono JetBrains Mono con FontFeature.tabularFigures() — los dígitos se alinean verticalmente entre filas para que el ojo compare montos sin ruido.

Variants

Seis estados del card

Galería a ancho real (328dp). Cada variante es el mismo componente; lo que cambia es el contenido y, en algunos casos, el estado de visibilidad.

Dual balance

Saldo total vs. disponible para retiro

La decisión de diseño más importante del card. Cuando el cripto recién comprado todavía está liquidando, el usuario tiene dos saldos. Los mostramos juntos en la misma fila — no en cards separados, no en tabs. El usuario ve ambos de un vistazo.

Iguales

Cuando saldo total = disponible

No mostrar la línea "disponible" — no agregar ruido cuando los dos números son iguales. Solo el saldo principal y su equivalente COP.

Ethereum
ETH
0,2156 ETH
≈ $786.180
Difieren

Cuando hay saldo en liquidación

Mostrar el total arriba (peso 600) y debajo, en caption muted color warning, el disponible con icono clock. Tap → tooltip o bottom sheet.

₿
Bitcoin
BTC
0,01548 BTC
≈ $1.878.640
0,01350 disponible
Al tocar el indicador: bottom sheet con "Parte de tu saldo está en proceso de liquidación. Estará disponible para retiro en máx. 24 horas hábiles."
Interactions

Interacciones

El card como unidad no es tappable. Las filas y los controles internos sí. Cada interacción se conecta a tokens ya definidos en foundations-motion.

Tap en fila de activo

Navega a la pantalla de detalle del activo. PageRouteBuilder con SlideTransition + FadeTransition, duration-slow · ease-standard.

Tap en ícono de ojo

Toggle privacy mode. Crossfade del valor a •••••• en 200ms. Haptic selectionClick(). Persiste vía SharedPreferences.

Tap en indicador de liquidación

Abre showModalBottomSheet con la explicación de los 24 horas hábiles. duration-modal + ease-drawer.

Pull to refresh

En el dashboard (no en el card aislado). RefreshIndicator dispara crossfade a skeletons mientras el provider revalida la data.

Tap "Reintentar" en error

Vuelve a estado loading (skeleton) y dispara el fetch. Si falla otra vez, mantiene el estado de error sin loops infinitos visibles.

Tap en CTA vacío

"Compra tu primer Bitcoin" navega al flujo de compra con BTC preseleccionado. Haptic lightImpact() al iniciar la transición.

Dark mode

Claro y oscuro

Misma jerarquía, misma estructura. En oscuro el card vive sobre --color-surface-dark con su propio fill ligeramente elevado. Los colores de marca de los activos se mantienen — la identidad del BTC es naranja, sí o sí.

Light DEFAULT
Valor estimado en COP
$2.845.320
COP
−1,5% 24h
₿
Bitcoin
BTC
0,01548 BTC
≈ $1.878.640
Ethereum
ETH
0,2156 ETH
≈ $786.180
Tether
USDT
45,0000 USDT
≈ $180.500
Dark DARK MODE
Valor estimado en COP
$2.845.320
COP
−1,5% 24h
₿
Bitcoin
BTC
0,01548 BTC
≈ $1.878.640
Ethereum
ETH
0,2156 ETH
≈ $786.180
Tether
USDT
45,0000 USDT
≈ $180.500
Responsive

Tres anchos de dispositivo

El card debe funcionar desde Android económico (320dp) hasta iPhone 15 Pro Max (428dp). El padding interno y la tipografía se mantienen; lo que cambia es el ancho útil. Saldos cripto muy largos se truncan con ellipsis.

320dpAndroid económico
Valor estimado en COP
$2.845.320
COP
+2,3% 24h
₿
Bitcoin
BTC
0,01548 BTC
≈ $1.878.640
Ethereum
ETH
0,2156 ETH
≈ $786.180
Tether
USDT
45,0000 USDT
≈ $180.500
360dpbaseline · Pixel 8
Valor estimado en COP
$2.845.320
COP
+2,3% 24h
₿
Bitcoin
BTC
0,00000001 BTC
≈ $1.878.640
Ethereum
ETH
0,2156 ETH
≈ $786.180
Tether
USDT
45,0000 USDT
≈ $180.500
428dpiPhone 15 Pro Max
Valor estimado en COP
$2.845.320
COP
+2,3% 24h
₿
Bitcoin
BTC
0,01548 BTC
≈ $1.878.640
Ethereum
ETH
0,2156 ETH
≈ $786.180
Tether
USDT
45,0000 USDT
≈ $180.500

A 320dp el saldo del BTC del primer ejemplo está al límite. Saldos micro como 0,00000001 BTC se truncan con ellipsis (ver Pixel 8) — el valor completo se muestra en el detalle del activo.

In context

El dashboard, canvas-first

El dashboard no usa tarjetas. Aplicando §4.7b (canvas-first): el balance y las transacciones viven directamente sobre el lienzo blanco, separados por hairlines y espacio — no por cajas. El hero gana presencia con peso tipográfico (36dp), no con chrome. El único contenedor en pantalla es el bottom nav flotante, que como componente flotante sí conserva elevación.

9:41
Hola, William
Valor estimado en COP
$2.845.320
COP
+2,3% 24h
₿
Bitcoin
BTC
0,01548 BTC
≈ $1.878.640
Ethereum
ETH
0,2156 ETH
≈ $786.180
Tether
USDT
45,0000 USDT
≈ $180.500
Compra BTC
Hoy · 9:12
+0,00120 BTC
$145.500 COP
Swap ETH → USDT
Ayer · 18:45
+12,5000 USDT
−0,003 ETH
Retiro a Bancolombia
21 may · 11:02
−$320.000
COP · ref. 8741

Observaciones de integración

1

Lienzo blanco continuo. El fondo es --surface-canvas (#FFFFFF). No hay contraste fondo↔tarjeta que crear: el balance es lo primero que el usuario ve, sin caja que lo enmarque.

2

El hero gana con tipografía. Sin borde, sin sombra, sin radio. La valorización sube a 36dp y domina la pantalla por peso y escala, no por chrome.

3

Hairlines en vez de cards. Filas de activo y de transacción se separan con --divider-hairline indentado bajo el ícono — lenguaje de lista densa, no de contenedores apilados.

4

"Recientes" es un label micro-cap. Mismo lenguaje que el label del balance. El grupo se anuncia con tipografía + espacio, no con un contenedor con su propio borde.

5

El bottom nav flotante se queda. Es la única "caja" legítima en pantalla: §4.7b permite a los componentes flotantes conservar elevación y borde para despegarse del lienzo.

Implementation

Notas de implementación Flutter

Construcción del card

Container o Card

Container con BoxDecoration (borderRadius: 16, color: surface, boxShadow: elev.1) — preferible al Card Material para tener control fino sobre el shadow.

Filas de activo

InkWell envolviendo un Row custom (no ListTile — su default padding no encaja). Ripple Material nativo + scale opcional via AnimatedScale si la fila es CTA primaria.

Tipografía tabular

TextStyle(fontFeatures: [FontFeature.tabularFigures()]) en todos los montos. Garantiza que 0,00109 BTC y 0,01548 BTC alineen dígitos verticalmente entre filas.

Privacy mode

ValueNotifier<bool> (o Riverpod provider) que persiste en SharedPreferences. El widget escucha y reemplaza los Text de montos por "••••••" manteniendo todo lo demás.

Skeleton compartido

El skeleton del card usa el mismo AnimationController del SkeletonScope de la pantalla — no crear un controller propio. Misma fuente de verdad que el resto de skeletons visibles.

Pull to refresh

RefreshIndicator envuelve el ListView del dashboard. El onRefresh revalida el provider de portafolio, lo que repinta el card en estado skeleton durante el fetch.