Rediseño Charts iPad, zoom en gráficas, eliminación de Focus Mode y fixes de rendimiento

Charts iPad (rediseño):
- Fila de KPIs sobre el chart: Total Value, Period Return, CAGR, Volatility y Max
  Drawdown del rango activo (nuevo ChartsViewModel.portfolioMetrics, calculado sobre
  los TOTALES MENSUALES AGREGADOS — pasar snapshots multi-source crudos a
  calculateMetrics producía KPIs absurdos)
- Sidebar (248pt) con tiles de chart type en grid 2 col agrupados por sección:
  Overview / Analyze / Risk / Forecast, con candado premium y accesibilidad
- Selector de periodo como Picker segmentado nativo en la cabecera del chart
  (fuera del sidebar); título + descripción del chart visibles
- Eliminado sheet de paywall duplicado del layout iPad

Zoom (todas las series temporales):
- Nuevo ChartZoom.swift: pinch + botones +/- y reset (HIG: el gesto nunca es el
  único camino), chartScrollableAxes + chartXVisibleDomain al hacer zoom
- Integrado en Evolution, Contributions, Rolling 12M, Cashflow, Drawdown y Volatility

Focus Mode eliminado (todo siempre disponible):
- Fuera el toggle de Dashboard/Charts/Settings/Onboarding y los 6 @AppStorage
- Todos los chart types siempre visibles; variantes completas en SourceDetail/SourceList
- Home: Total Portfolio Value muestra SIEMPRE el cambio desde el último check-in
- PeriodReturnsCard siempre visible

Rendimiento y bugs (de la auditoría):
- El cache de snapshots ya no se invalida al cambiar solo de chart type/rango/breakdown
- calculateAnnualizedGrowth y el forecast a 12 meses ahora componen (la aproximación
  lineal sobreestimaba con historiales cortos)
- Drawdown sin force unwrap; simulador: rama muerta reemplazada por preservación
  real de las asignaciones simuladas del usuario
- UITest de captura de Charts con manejo del alert de notificaciones

12 strings nuevas localizadas en los 7 idiomas.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015qUZrBusG82T37R7PeokqJ
This commit is contained in:
alexandrev-tibco
2026-07-03 10:17:10 +02:00
parent d0a51d0162
commit db844d5e80
19 changed files with 557 additions and 230 deletions
@@ -9,7 +9,6 @@ struct OnboardingView: View {
// Default ON: a user who skips onboarding lands on a populated dashboard (instant
// aha moment) instead of an empty screen. Sample data is clearly labeled and removable.
@State private var useSampleData = true
@AppStorage("calmModeEnabled") private var calmModeEnabled = true
@AppStorage("cloudSyncEnabled") private var cloudSyncEnabled = false
@State private var showingImportSheet = false
@State private var showingAddSource = false
@@ -53,7 +52,6 @@ struct OnboardingView: View {
OnboardingQuickStartView(
selectedCurrency: $selectedCurrency,
useSampleData: $useSampleData,
calmModeEnabled: $calmModeEnabled,
cloudSyncEnabled: $cloudSyncEnabled,
onImport: { showingImportSheet = true },
onAddSource: { showingAddSource = true }
@@ -221,7 +219,6 @@ struct OnboardingPageView: View {
struct OnboardingQuickStartView: View {
@Binding var selectedCurrency: String
@Binding var useSampleData: Bool
@Binding var calmModeEnabled: Bool
@Binding var cloudSyncEnabled: Bool
let onImport: () -> Void
let onAddSource: () -> Void
@@ -293,15 +290,6 @@ struct OnboardingQuickStartView: View {
.background(Color.gray.opacity(0.1))
.cornerRadius(12)
VStack(alignment: .leading, spacing: 6) {
Toggle("Focus Mode (recommended)", isOn: $calmModeEnabled)
Text("Shows returns since your last check-in instead of daily noise. You can change this anytime in Settings.")
.font(.caption)
.foregroundColor(.secondary)
}
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(12)
Toggle("Sync with iCloud (optional)", isOn: $cloudSyncEnabled)
.padding()