Files
InvestmentTrackerApp/PortfolioJournal/Views/Dashboard/InsightsRow.swift
T
alexandrev-tibco be7119f4b9 Calm 2.0 Fase 1: sistema de diseño limpio + Home en 3 zonas (1.5.0 build 51)
Sistema:
- AppBackground: fuera gradiente + formas decorativas → systemGroupedBackground
  plano en toda la app. La profundidad la da la jerarquía, no la decoración.

Home (3 zonas: estado / acción / contexto):
- TotalValueCard: hero tipográfico — número 44pt rounded sobre card limpia,
  chip de delta semántico (verde/rojo), sparkline de evolución 56pt estilo
  Stocks, fila secundaria YoY / inception / forecast. Fuera el gradiente azul.
- MonthlyCheckInCard state-driven: pendiente → protagonista con progreso real
  de fuentes (N de M) y un CTA; completado → fila discreta con checkmark,
  próximo check-in y streak integrado. En iPad va a ancho completo bajo el
  hero (zona de acción), fuera del grid.
- InsightsRow: de carrusel de chips a un insight único rotatorio (tap para
  ciclar, dots de posición).
- Eliminados del top: streak badge (vive en el check-in) y banner de pending
  updates (el progreso del check-in lo comunica).
- Defaults nuevos: momentumStreaks/pendingUpdates/periodReturns/monthlySummary
  ocultos por defecto (siguen disponibles en Customize; configs guardadas de
  usuarios existentes se respetan).
- Strings nuevas en 7 idiomas (checkin_done_*, checkin_sources_progress).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WoScpmHdVj1aUf4rAp6hbe
2026-07-08 23:58:06 +02:00

61 lines
2.2 KiB
Swift

import SwiftUI
// Calm 2.0: one insight at a time instead of a chip carousel a quiet,
// glanceable line under the check-in zone. Tap to cycle through the rest.
struct InsightsRow: View {
let insights: [PortfolioInsight]
@State private var index = 0
private var current: PortfolioInsight? {
guard !insights.isEmpty else { return nil }
return insights[index % insights.count]
}
var body: some View {
if let insight = current {
Button {
withAnimation(.snappy) {
index = (index + 1) % insights.count
}
} label: {
HStack(spacing: 12) {
Image(systemName: insight.systemImage)
.font(.subheadline.weight(.semibold))
.foregroundColor(insight.accentColor)
.frame(width: 30, height: 30)
.background(insight.accentColor.opacity(0.12))
.clipShape(Circle())
VStack(alignment: .leading, spacing: 1) {
Text(insight.title)
.font(.caption)
.foregroundColor(.secondary)
Text(insight.value)
.font(.subheadline.weight(.semibold))
.foregroundColor(.primary)
.lineLimit(1)
}
Spacer()
if insights.count > 1 {
HStack(spacing: 4) {
ForEach(insights.indices, id: \.self) { i in
Circle()
.fill(i == index % insights.count ? Color.secondary : Color.secondary.opacity(0.25))
.frame(width: 5, height: 5)
}
}
}
}
.padding(14)
.background(Color(.secondarySystemGroupedBackground))
.cornerRadius(AppConstants.UI.cornerRadius)
}
.buttonStyle(.plain)
.id(insight.id)
.transition(.opacity)
}
}
}