Dashboard: quitar títulos duplicados en cards de gráficas (build 81) #33
showsTitle (default true) en HorizontalPerformanceChart, DrawdownChart, VolatilityChartView, PredictionChartView y YearOverYearChartView; el pageContent del Dashboard pasa false porque el header de la card ya nombra la página. La sección Charts no cambia. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L38583J7AYWCVPevkivscj
This commit is contained in:
@@ -541,7 +541,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = PortfolioJournal/PortfolioJournalDebug.entitlements;
|
CODE_SIGN_ENTITLEMENTS = PortfolioJournal/PortfolioJournalDebug.entitlements;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 80;
|
CURRENT_PROJECT_VERSION = 81;
|
||||||
DEVELOPMENT_ASSET_PATHS = PortfolioJournal/Assets.xcassets;
|
DEVELOPMENT_ASSET_PATHS = PortfolioJournal/Assets.xcassets;
|
||||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -582,7 +582,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "porfoliojournal";
|
PROVISIONING_PROFILE_SPECIFIER = "porfoliojournal";
|
||||||
CURRENT_PROJECT_VERSION = 80;
|
CURRENT_PROJECT_VERSION = 81;
|
||||||
DEVELOPMENT_ASSET_PATHS = PortfolioJournal/Assets.xcassets;
|
DEVELOPMENT_ASSET_PATHS = PortfolioJournal/Assets.xcassets;
|
||||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -739,7 +739,7 @@
|
|||||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
CODE_SIGN_ENTITLEMENTS = PortfolioJournalWidgetExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = PortfolioJournalWidgetExtension.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 80;
|
CURRENT_PROJECT_VERSION = 81;
|
||||||
DEVELOPMENT_ASSET_PATHS = PortfolioJournalWidget/Assets.xcassets;
|
DEVELOPMENT_ASSET_PATHS = PortfolioJournalWidget/Assets.xcassets;
|
||||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||||
GENERATE_INFOPLIST_FILE = NO;
|
GENERATE_INFOPLIST_FILE = NO;
|
||||||
@@ -774,7 +774,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "Portfolio Journalwidget";
|
PROVISIONING_PROFILE_SPECIFIER = "Portfolio Journalwidget";
|
||||||
CURRENT_PROJECT_VERSION = 80;
|
CURRENT_PROJECT_VERSION = 81;
|
||||||
DEVELOPMENT_ASSET_PATHS = PortfolioJournalWidget/Assets.xcassets;
|
DEVELOPMENT_ASSET_PATHS = PortfolioJournalWidget/Assets.xcassets;
|
||||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||||
GENERATE_INFOPLIST_FILE = NO;
|
GENERATE_INFOPLIST_FILE = NO;
|
||||||
@@ -805,7 +805,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 80;
|
CURRENT_PROJECT_VERSION = 81;
|
||||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
||||||
@@ -829,7 +829,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 80;
|
CURRENT_PROJECT_VERSION = 81;
|
||||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
||||||
@@ -852,7 +852,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 80;
|
CURRENT_PROJECT_VERSION = 81;
|
||||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
||||||
@@ -875,7 +875,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 80;
|
CURRENT_PROJECT_VERSION = 81;
|
||||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
IPHONEOS_DEPLOYMENT_TARGET = 17.6;
|
||||||
@@ -899,7 +899,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_ENTITLEMENTS = PortfolioJournalQuickUpdateExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = PortfolioJournalQuickUpdateExtension.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 80;
|
CURRENT_PROJECT_VERSION = 81;
|
||||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||||
GENERATE_INFOPLIST_FILE = NO;
|
GENERATE_INFOPLIST_FILE = NO;
|
||||||
INFOPLIST_FILE = PortfolioJournalQuickUpdate/Info.plist;
|
INFOPLIST_FILE = PortfolioJournalQuickUpdate/Info.plist;
|
||||||
@@ -927,7 +927,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = PortfolioJournalQuickUpdateExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = PortfolioJournalQuickUpdateExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 80;
|
CURRENT_PROJECT_VERSION = 81;
|
||||||
DEVELOPMENT_TEAM = 2825Q76T7H;
|
DEVELOPMENT_TEAM = 2825Q76T7H;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "PortfolioJournal QuickUpdate AppStore";
|
PROVISIONING_PROFILE_SPECIFIER = "PortfolioJournal QuickUpdate AppStore";
|
||||||
GENERATE_INFOPLIST_FILE = NO;
|
GENERATE_INFOPLIST_FILE = NO;
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import Charts
|
|||||||
|
|
||||||
struct DrawdownChart: View {
|
struct DrawdownChart: View {
|
||||||
let data: [(date: Date, drawdown: Double)]
|
let data: [(date: Date, drawdown: Double)]
|
||||||
|
/// Hidden when the host (e.g. a dashboard card) already shows a title.
|
||||||
|
var showsTitle: Bool = true
|
||||||
@State private var zoom = ChartZoomModel()
|
@State private var zoom = ChartZoomModel()
|
||||||
@State private var selectedDate: Date?
|
@State private var selectedDate: Date?
|
||||||
@Environment(\.horizontalSizeClass) private var labelsSizeClass
|
@Environment(\.horizontalSizeClass) private var labelsSizeClass
|
||||||
@@ -26,8 +28,10 @@ struct DrawdownChart: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 16) {
|
VStack(alignment: .leading, spacing: 16) {
|
||||||
HStack {
|
HStack {
|
||||||
Text("Drawdown Analysis")
|
if showsTitle {
|
||||||
.font(.headline)
|
Text("Drawdown Analysis")
|
||||||
|
.font(.headline)
|
||||||
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
@@ -207,6 +211,8 @@ struct DrawdownStatView: View {
|
|||||||
|
|
||||||
struct VolatilityChartView: View {
|
struct VolatilityChartView: View {
|
||||||
let data: [(date: Date, volatility: Double)]
|
let data: [(date: Date, volatility: Double)]
|
||||||
|
/// Hidden when the host (e.g. a dashboard card) already shows a title.
|
||||||
|
var showsTitle: Bool = true
|
||||||
@State private var zoom = ChartZoomModel()
|
@State private var zoom = ChartZoomModel()
|
||||||
@State private var selectedDate: Date?
|
@State private var selectedDate: Date?
|
||||||
@Environment(\.horizontalSizeClass) private var labelsSizeClass
|
@Environment(\.horizontalSizeClass) private var labelsSizeClass
|
||||||
@@ -230,11 +236,13 @@ struct VolatilityChartView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 16) {
|
VStack(alignment: .leading, spacing: 16) {
|
||||||
HStack {
|
if showsTitle {
|
||||||
Text("Volatility")
|
HStack {
|
||||||
.font(.headline)
|
Text("Volatility")
|
||||||
|
.font(.headline)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text("Measures price variability over time")
|
Text("Measures price variability over time")
|
||||||
|
|||||||
@@ -185,6 +185,8 @@ struct PerformanceBarChart: View {
|
|||||||
|
|
||||||
struct HorizontalPerformanceChart: View {
|
struct HorizontalPerformanceChart: View {
|
||||||
let data: [(category: String, cagr: Double, color: String)]
|
let data: [(category: String, cagr: Double, color: String)]
|
||||||
|
/// Hidden when the host (e.g. a dashboard card) already shows a title.
|
||||||
|
var showsTitle: Bool = true
|
||||||
|
|
||||||
var sortedData: [(category: String, cagr: Double, color: String)] {
|
var sortedData: [(category: String, cagr: Double, color: String)] {
|
||||||
data.sorted { $0.cagr > $1.cagr }
|
data.sorted { $0.cagr > $1.cagr }
|
||||||
@@ -196,8 +198,10 @@ struct HorizontalPerformanceChart: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 16) {
|
VStack(alignment: .leading, spacing: 16) {
|
||||||
Text("Performance by Category")
|
if showsTitle {
|
||||||
.font(.headline)
|
Text("Performance by Category")
|
||||||
|
.font(.headline)
|
||||||
|
}
|
||||||
|
|
||||||
ForEach(sortedData, id: \.category) { item in
|
ForEach(sortedData, id: \.category) { item in
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import Charts
|
|||||||
struct PredictionChartView: View {
|
struct PredictionChartView: View {
|
||||||
let predictions: [Prediction]
|
let predictions: [Prediction]
|
||||||
let historicalData: [(date: Date, value: Decimal)]
|
let historicalData: [(date: Date, value: Decimal)]
|
||||||
|
/// Hidden when the host (e.g. a dashboard card) already shows a title.
|
||||||
|
var showsTitle: Bool = true
|
||||||
@State private var selectedDate: Date?
|
@State private var selectedDate: Date?
|
||||||
@Environment(\.horizontalSizeClass) private var labelsSizeClass
|
@Environment(\.horizontalSizeClass) private var labelsSizeClass
|
||||||
|
|
||||||
@@ -23,8 +25,10 @@ struct PredictionChartView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 16) {
|
VStack(alignment: .leading, spacing: 16) {
|
||||||
HStack {
|
HStack {
|
||||||
Text(predictions.isEmpty ? "Prediction" : "\(predictions.count)-Month Prediction")
|
if showsTitle {
|
||||||
.font(.headline)
|
Text(predictions.isEmpty ? "Prediction" : "\(predictions.count)-Month Prediction")
|
||||||
|
.font(.headline)
|
||||||
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import Charts
|
|||||||
|
|
||||||
struct YearOverYearChartView: View {
|
struct YearOverYearChartView: View {
|
||||||
@ObservedObject var viewModel: ChartsViewModel
|
@ObservedObject var viewModel: ChartsViewModel
|
||||||
|
/// Hidden when the host (e.g. a dashboard card) already shows a title.
|
||||||
|
var showsTitle: Bool = true
|
||||||
@State private var selectedMonthIdx: Int?
|
@State private var selectedMonthIdx: Int?
|
||||||
|
|
||||||
private let monthAbbreviations = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
private let monthAbbreviations = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||||
@@ -20,8 +22,10 @@ struct YearOverYearChartView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 16) {
|
VStack(alignment: .leading, spacing: 16) {
|
||||||
Text(String(localized: "chart_yoy_title"))
|
if showsTitle {
|
||||||
.font(.headline)
|
Text(String(localized: "chart_yoy_title"))
|
||||||
|
.font(.headline)
|
||||||
|
}
|
||||||
|
|
||||||
if allYears.isEmpty {
|
if allYears.isEmpty {
|
||||||
Text(String(localized: "chart_yoy_empty"))
|
Text(String(localized: "chart_yoy_empty"))
|
||||||
|
|||||||
@@ -177,19 +177,22 @@ struct EvolutionChartCard: View {
|
|||||||
.frame(height: 150)
|
.frame(height: 150)
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
allocationLegend
|
allocationLegend
|
||||||
|
// showsTitle: false — the card header already names the page;
|
||||||
|
// the embedded charts' own titles duplicated it.
|
||||||
case .performance:
|
case .performance:
|
||||||
HorizontalPerformanceChart(data: chartsVM.performanceData)
|
HorizontalPerformanceChart(data: chartsVM.performanceData, showsTitle: false)
|
||||||
case .drawdown:
|
case .drawdown:
|
||||||
DrawdownChart(data: chartsVM.drawdownData)
|
DrawdownChart(data: chartsVM.drawdownData, showsTitle: false)
|
||||||
case .volatility:
|
case .volatility:
|
||||||
VolatilityChartView(data: chartsVM.volatilityData)
|
VolatilityChartView(data: chartsVM.volatilityData, showsTitle: false)
|
||||||
case .prediction:
|
case .prediction:
|
||||||
PredictionChartView(
|
PredictionChartView(
|
||||||
predictions: chartsVM.predictionData,
|
predictions: chartsVM.predictionData,
|
||||||
historicalData: chartsVM.evolutionData
|
historicalData: chartsVM.evolutionData,
|
||||||
|
showsTitle: false
|
||||||
)
|
)
|
||||||
case .yearOverYear:
|
case .yearOverYear:
|
||||||
YearOverYearChartView(viewModel: chartsVM)
|
YearOverYearChartView(viewModel: chartsVM, showsTitle: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user