Calm 2.0 Fase 4: TipKit para descubrimiento + aha post-onboarding (build 55)

TipKit (Tips.configure con frecuencia diaria):
- QuickUpdateTip: popover en el '+' del Home — descubre Quick Update
- ScreenshotOCRTip: inline en Quick Update — descubre el OCR por captura
- SiriTip: en el cierre del check-in guiado — descubre el intent de voz
- ChartShareTip: popover en el compartir de Charts
- Se invalidan al ejecutar la acción; máx 1-2 impresiones cada uno
- Strings ×7 idiomas

Onboarding:
- Al completar el onboarding sin datos, se abre Add Source directamente
  (notificación .openAddFirstSource) — el usuario nuevo no aterriza en un
  dashboard vacío

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WoScpmHdVj1aUf4rAp6hbe
This commit is contained in:
alexandrev-tibco
2026-07-10 09:31:03 +02:00
parent 08094483ed
commit 4c0d2af564
16 changed files with 148 additions and 10 deletions
@@ -1,6 +1,7 @@
import SwiftUI
import Charts
import CoreData
import TipKit
struct DashboardView: View {
@EnvironmentObject var iapService: IAPService
@@ -64,10 +65,12 @@ struct DashboardView: View {
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
QuickUpdateTip().invalidate(reason: .actionPerformed)
showingQuickUpdate = true
} label: {
Image(systemName: "plus.circle.fill")
}
.popoverTip(QuickUpdateTip())
}
ToolbarItem(placement: .navigationBarTrailing) {
accountFilterMenu
@@ -120,6 +123,9 @@ struct DashboardView: View {
.onReceive(NotificationCenter.default.publisher(for: .openQuickUpdate)) { _ in
showingQuickUpdate = true
}
.onReceive(NotificationCenter.default.publisher(for: .openAddFirstSource)) { _ in
if !viewModel.hasData { showingAddSource = true }
}
}
}
@@ -1,5 +1,6 @@
import SwiftUI
import CoreData
import TipKit
import UIKit
// MARK: - Guided monthly check-in (Calm 2.0, Fase 2)
@@ -355,6 +356,9 @@ struct GuidedCheckInView: View {
Spacer()
TipView(SiriTip())
.padding(.horizontal, 32)
VStack(spacing: 10) {
if let totals = savedTotals {
Button {
@@ -1,5 +1,6 @@
import SwiftUI
import CoreData
import TipKit
import UIKit
struct QuickUpdateView: View {
@@ -43,6 +44,13 @@ struct QuickUpdateView: View {
)
} else {
List {
Section {
TipView(ScreenshotOCRTip())
.listRowInsets(EdgeInsets())
.listRowBackground(Color.clear)
}
.listSectionSeparator(.hidden)
if let amount = clipboardAmount, let target = nextEmptySource {
Section {
Button {