#10 Ocultar saldos: BalancePrivacyManager (balancesHidden + requireBiometricToReveal), modifier .hiddenBalance() (blur + máscara de bullets, ancho estable), botón ojo en Dashboard, revelar con Face ID vía AppLockService, sección Privacidad en Settings. Aplicado a total portfolio, forecast, sources, goals, monthly summary. #11 Siri/App Intents: NetWorthIntent ('¿cuál es mi patrimonio?' → 'Tu patrimonio es X'), StreakIntent, 5 AppShortcuts con frases. Widget interactivo iOS 17: botón Refresh (Button(intent:) → reloadAllTimelines, in-process) en medium/large, gated #available(iOS 17). Reader read-only del AppGroup. Dialogs Siri refactorizados a String(localized:). Localización: strings de #10 y de Siri 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:
@@ -7,6 +7,7 @@ struct DashboardView: View {
|
||||
@EnvironmentObject var iapService: IAPService
|
||||
@EnvironmentObject var accountStore: AccountStore
|
||||
@EnvironmentObject var tabSelection: TabSelectionStore
|
||||
@EnvironmentObject var balancePrivacy: BalancePrivacyManager
|
||||
@StateObject private var viewModel: DashboardViewModel
|
||||
@StateObject private var goalsViewModel = GoalsViewModel()
|
||||
@State private var showingImport = false
|
||||
@@ -84,6 +85,14 @@ struct DashboardView: View {
|
||||
}
|
||||
.popoverTip(QuickUpdateTip())
|
||||
}
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button {
|
||||
balancePrivacy.toggleHidden()
|
||||
} label: {
|
||||
Image(systemName: balancePrivacy.balancesHidden ? "eye.slash" : "eye")
|
||||
}
|
||||
.accessibilityLabel(balancePrivacy.balancesHidden ? Text("Show balances") : Text("Hide balances"))
|
||||
}
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
accountFilterMenu
|
||||
}
|
||||
@@ -287,7 +296,7 @@ struct DashboardView: View {
|
||||
switch section {
|
||||
case .totalValue:
|
||||
if config.isCollapsed {
|
||||
CompactCard(title: "Portfolio", subtitle: viewModel.portfolioSummary.formattedTotalValue)
|
||||
CompactCard(title: "Portfolio", subtitle: viewModel.portfolioSummary.formattedTotalValue, subtitleIsBalance: true)
|
||||
} else {
|
||||
TotalValueCard(
|
||||
totalValue: viewModel.portfolioSummary.formattedTotalValue,
|
||||
@@ -312,7 +321,8 @@ struct DashboardView: View {
|
||||
sinceInceptionChange: viewModel.portfolioSummary.formattedAllTimeReturn
|
||||
)
|
||||
},
|
||||
sparklineData: viewModel.evolutionData
|
||||
sparklineData: viewModel.evolutionData,
|
||||
balancesHidden: balancePrivacy.balancesHidden
|
||||
)
|
||||
}
|
||||
case .monthlyCheckIn:
|
||||
@@ -444,6 +454,7 @@ struct TotalValueCard: View {
|
||||
var isSinceInceptionPositive: Bool = true
|
||||
var onShareTap: (() -> Void)?
|
||||
var sparklineData: [(date: Date, value: Decimal)] = []
|
||||
var balancesHidden: Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
@@ -466,6 +477,7 @@ struct TotalValueCard: View {
|
||||
.foregroundColor(.primary)
|
||||
.minimumScaleFactor(0.6)
|
||||
.lineLimit(1)
|
||||
.hiddenBalance(balancesHidden)
|
||||
|
||||
HStack(spacing: 8) {
|
||||
HStack(spacing: 4) {
|
||||
@@ -505,6 +517,7 @@ struct TotalValueCard: View {
|
||||
value: forecast.formattedForecastValue,
|
||||
positive: forecast.isPositiveGrowth
|
||||
)
|
||||
.hiddenBalance(balancesHidden)
|
||||
} else {
|
||||
Button {
|
||||
onUnlockTap?()
|
||||
@@ -1164,6 +1177,7 @@ struct MonthlySummaryCard: View {
|
||||
.foregroundColor(.secondary)
|
||||
Text(summary.formattedContributions)
|
||||
.font(.subheadline.weight(.semibold))
|
||||
.hiddenBalance()
|
||||
}
|
||||
|
||||
Spacer()
|
||||
@@ -1175,6 +1189,7 @@ struct MonthlySummaryCard: View {
|
||||
Text("\(summary.formattedNetPerformance) (\(summary.formattedNetPerformancePercentage))")
|
||||
.font(.subheadline.weight(.semibold))
|
||||
.foregroundColor(summary.netPerformance >= 0 ? .positiveGreen : .negativeRed)
|
||||
.hiddenBalance()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1245,14 +1260,22 @@ struct DashboardCustomizeView: View {
|
||||
struct CompactCard: View {
|
||||
let title: String
|
||||
let subtitle: String
|
||||
var subtitleIsBalance: Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(title)
|
||||
.font(.headline)
|
||||
Text(subtitle)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
if subtitleIsBalance {
|
||||
Text(subtitle)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
.hiddenBalance()
|
||||
} else {
|
||||
Text(subtitle)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
Reference in New Issue
Block a user