1.5.0: aviso de huecos + resumen mensual compartible + import con vista previa
Feature 1 — Aviso de huecos: SnapshotGapDetector detecta huecos internos por source (meses sin datos entre dos snapshots). Banner desechable en Dashboard + DataGapsSheet para rellenar (abre AddSnapshotView con el mes que falta). Complementa la interpolación de gráficas: la línea se ve suave pero el usuario sabe que faltan datos reales. Feature 2 — Resumen mensual compartible: MonthlySummaryShareView (tarjeta con marca: valor, variación desde el check-in, racha, mood/rating) renderizada con ImageRenderer y compartida vía ShareService. Botón en la fila "check-in done" del Dashboard. Feature 3 — Import con vista previa: ImportPreview + previewImportAsync (dry-run READ-ONLY, no muta nada) cuenta qué se creará/actualizará usando los mismos checks de existencia que applyImport. ImportDataView muestra la confirmación antes de importar. El path real de import (applyImport/importDataAsync) NO se toca. Localización en los 7 idiomas. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L2p3gUZRNWW388rWFRjiU7
This commit is contained in:
@@ -25,6 +25,13 @@ class DashboardViewModel: ObservableObject {
|
||||
@Published var evolutionData: [(date: Date, value: Decimal)] = []
|
||||
@Published var updateStreak: Int = 0
|
||||
|
||||
// MARK: - Data Gaps
|
||||
|
||||
/// Internal gaps in per-source snapshot history (missing months between two
|
||||
/// known snapshots). The chart smooths these over; this exposes them so the
|
||||
/// user knows real data is missing and can fill it. See SnapshotGapDetector.
|
||||
@Published var dataGaps: [SnapshotGapDetector.Gap] = []
|
||||
|
||||
// MARK: - Portfolio Forecast
|
||||
|
||||
@Published var portfolioForecast: PortfolioForecast?
|
||||
@@ -209,6 +216,9 @@ class DashboardViewModel: ObservableObject {
|
||||
// Compute update streak
|
||||
updateStreak = computeStreak(from: evolutionData)
|
||||
|
||||
// Detect internal data gaps (missing months between known snapshots)
|
||||
dataGaps = SnapshotGapDetector.detectGaps(sources: sources, snapshots: allSnapshots)
|
||||
|
||||
// Log screen view
|
||||
FirebaseService.shared.logScreenView(screenName: "Dashboard")
|
||||
}
|
||||
@@ -685,6 +695,42 @@ class DashboardViewModel: ObservableObject {
|
||||
sourcesNeedingUpdate.count
|
||||
}
|
||||
|
||||
/// Total number of missing months across all detected internal gaps.
|
||||
var totalMissingMonths: Int {
|
||||
SnapshotGapDetector.totalMissingMonths(dataGaps)
|
||||
}
|
||||
|
||||
/// Resolves an InvestmentSource for a detected gap so the fill flow can open
|
||||
/// the add-snapshot sheet for it.
|
||||
func source(withId id: UUID) -> InvestmentSource? {
|
||||
sourceRepository.sources.first { $0.id == id }
|
||||
}
|
||||
|
||||
/// Builds the data for the shareable monthly summary card from already-computed
|
||||
/// dashboard state. Mood/rating come from the latest completed check-in entry.
|
||||
func monthlySummaryShareData() -> ShareService.MonthlySummaryShareData {
|
||||
let monthLabel: String = {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "MMMM yyyy"
|
||||
let date = MonthlyCheckInStore.latestCompletionDate() ?? Date()
|
||||
return formatter.string(from: date)
|
||||
}()
|
||||
|
||||
let latestEntry = MonthlyCheckInStore.latestCompletionDate()
|
||||
.flatMap { MonthlyCheckInStore.entry(for: $0) }
|
||||
|
||||
return ShareService.MonthlySummaryShareData(
|
||||
monthLabel: monthLabel,
|
||||
totalValue: portfolioSummary.formattedTotalValue,
|
||||
changeAmount: latestPortfolioChange.formattedAbsolute,
|
||||
changePercentage: latestPortfolioChange.formattedPercentage,
|
||||
isPositive: latestPortfolioChange.absolute >= 0,
|
||||
streak: updateStreak,
|
||||
mood: latestEntry?.mood,
|
||||
rating: latestEntry?.rating
|
||||
)
|
||||
}
|
||||
|
||||
var insights: [PortfolioInsight] {
|
||||
var result: [PortfolioInsight] = []
|
||||
guard portfolioSummary.totalValue > 0 else { return result }
|
||||
|
||||
Reference in New Issue
Block a user