Fix compilation errors in ChartsViewModel and AllocationEvolutionChart
- Remove unnecessary optional binding for non-optional source.id - Break up AllocationEvolutionChart body to help Swift type-checker Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -294,8 +294,7 @@ class ChartsViewModel: ObservableObject {
|
|||||||
let sources: [InvestmentSource]
|
let sources: [InvestmentSource]
|
||||||
if !selectedSourceIds.isEmpty {
|
if !selectedSourceIds.isEmpty {
|
||||||
sources = sourceRepository.sources.filter { source in
|
sources = sourceRepository.sources.filter { source in
|
||||||
guard let id = source.id else { return false }
|
selectedSourceIds.contains(source.id) && shouldIncludeSource(source)
|
||||||
return selectedSourceIds.contains(id) && shouldIncludeSource(source)
|
|
||||||
}
|
}
|
||||||
} else if let selectedSource {
|
} else if let selectedSource {
|
||||||
sources = sourceRepository.sources.filter { $0.id == selectedSource.id && shouldIncludeSource($0) }
|
sources = sourceRepository.sources.filter { $0.id == selectedSource.id && shouldIncludeSource($0) }
|
||||||
|
|||||||
@@ -929,46 +929,38 @@ struct CashflowStackedChartView: View {
|
|||||||
|
|
||||||
// MARK: - Allocation Evolution Chart
|
// MARK: - Allocation Evolution Chart
|
||||||
|
|
||||||
|
struct AllocationEvolutionDataPoint: Identifiable {
|
||||||
|
let id: String
|
||||||
|
let date: Date
|
||||||
|
let category: String
|
||||||
|
let percentage: Double
|
||||||
|
let color: String
|
||||||
|
}
|
||||||
|
|
||||||
struct AllocationEvolutionChart: View {
|
struct AllocationEvolutionChart: View {
|
||||||
let data: [(date: Date, category: String, percentage: Double, color: String)]
|
let data: [(date: Date, category: String, percentage: Double, color: String)]
|
||||||
|
|
||||||
|
private var identifiableData: [AllocationEvolutionDataPoint] {
|
||||||
|
data.enumerated().map { index, item in
|
||||||
|
AllocationEvolutionDataPoint(
|
||||||
|
id: "\(index)-\(item.category)",
|
||||||
|
date: item.date,
|
||||||
|
category: item.category,
|
||||||
|
percentage: item.percentage,
|
||||||
|
color: item.color
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
Text("Allocation Over Time")
|
Text("Allocation Over Time")
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
|
|
||||||
if data.isEmpty {
|
if data.isEmpty {
|
||||||
Text("Not enough data to show allocation evolution.")
|
emptyView
|
||||||
.foregroundColor(.secondary)
|
|
||||||
.frame(height: 260)
|
|
||||||
} else {
|
} else {
|
||||||
Chart {
|
chartView
|
||||||
ForEach(data, id: \.date.description + \.category) { item in
|
|
||||||
AreaMark(
|
|
||||||
x: .value("Date", item.date),
|
|
||||||
y: .value("Percentage", item.percentage)
|
|
||||||
)
|
|
||||||
.foregroundStyle(by: .value("Category", item.category))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.chartForegroundStyleScale(domain: categoryNames, range: categoryColors)
|
|
||||||
.chartXAxis {
|
|
||||||
AxisMarks(values: .stride(by: .month, count: 2)) { _ in
|
|
||||||
AxisValueLabel(format: .dateTime.month(.abbreviated).year(.twoDigits))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.chartYAxis {
|
|
||||||
AxisMarks(position: .leading) { value in
|
|
||||||
AxisValueLabel {
|
|
||||||
if let pct = value.as(Double.self) {
|
|
||||||
Text(String(format: "%.0f%%", pct))
|
|
||||||
.font(.caption)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.frame(height: 260)
|
|
||||||
.drawingGroup()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
@@ -977,6 +969,40 @@ struct AllocationEvolutionChart: View {
|
|||||||
.shadow(color: .black.opacity(0.05), radius: 8, y: 2)
|
.shadow(color: .black.opacity(0.05), radius: 8, y: 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var emptyView: some View {
|
||||||
|
Text("Not enough data to show allocation evolution.")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.frame(height: 260)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var chartView: some View {
|
||||||
|
Chart(identifiableData) { item in
|
||||||
|
AreaMark(
|
||||||
|
x: .value("Date", item.date),
|
||||||
|
y: .value("Percentage", item.percentage)
|
||||||
|
)
|
||||||
|
.foregroundStyle(by: .value("Category", item.category))
|
||||||
|
}
|
||||||
|
.chartForegroundStyleScale(domain: categoryNames, range: categoryColors)
|
||||||
|
.chartXAxis {
|
||||||
|
AxisMarks(values: .stride(by: .month, count: 2)) { _ in
|
||||||
|
AxisValueLabel(format: .dateTime.month(.abbreviated).year(.twoDigits))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.chartYAxis {
|
||||||
|
AxisMarks(position: .leading) { value in
|
||||||
|
AxisValueLabel {
|
||||||
|
if let pct = value.as(Double.self) {
|
||||||
|
Text(String(format: "%.0f%%", pct))
|
||||||
|
.font(.caption)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(height: 260)
|
||||||
|
.drawingGroup()
|
||||||
|
}
|
||||||
|
|
||||||
private var categoryNames: [String] {
|
private var categoryNames: [String] {
|
||||||
Array(Set(data.map { $0.category })).sorted()
|
Array(Set(data.map { $0.category })).sorted()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user