mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-17 12:16:59 +00:00
feat(bar-app): inline spend chart bars/line toggle in the Spend header
Move the bars/line choice out of Settings and into the Spend section header's blank space as a small inline toggle, so the user flips the chart style right where the chart is. Persistence unchanged.
This commit is contained in:
@@ -22,6 +22,10 @@ struct BarAnalyticsView: View {
|
||||
/// Controls whether the spend sparkline renders as bars or a line graph.
|
||||
/// Passed in by BarMenuView so it reflects the user's persisted choice live.
|
||||
var spendChartStyle: SpendChartStyle = .bars
|
||||
/// Inline flip for the spend chart style, surfaced as a small toggle in the
|
||||
/// Spend header (using the otherwise-blank space) so the user switches
|
||||
/// bars/line in place rather than digging into Settings. nil for `.breakdown`.
|
||||
var onToggleSpendStyle: (() -> Void)? = nil
|
||||
|
||||
private var lastActive: String? {
|
||||
BarFormatting.lastActiveLabel(
|
||||
@@ -71,7 +75,23 @@ struct BarAnalyticsView: View {
|
||||
/// line, and a thin inline 30-day sparkline when there is real spend.
|
||||
private var spendStrip: some View {
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
SectionLabel("Spend")
|
||||
HStack(spacing: 6) {
|
||||
SectionLabel("Spend")
|
||||
Spacer()
|
||||
// Inline bars/line toggle in the header's blank space — no Settings trip.
|
||||
if let toggle = onToggleSpendStyle, analytics.hasRecentData, !sparklineIsEmpty {
|
||||
Button(action: toggle) {
|
||||
Image(
|
||||
systemName: spendChartStyle == .bars
|
||||
? "chart.line.uptrend.xyaxis" : "chart.bar.fill"
|
||||
)
|
||||
.font(.system(size: 10))
|
||||
}
|
||||
.buttonStyle(.borderless)
|
||||
.foregroundStyle(.tertiary)
|
||||
.help("Spend graph: switch to \(spendChartStyle == .bars ? "line" : "bars")")
|
||||
}
|
||||
}
|
||||
if analytics.hasRecentData {
|
||||
Text(spendCaption)
|
||||
.font(.caption2)
|
||||
|
||||
@@ -50,12 +50,17 @@ struct BarMenuView: View {
|
||||
accountsSection
|
||||
|
||||
// (3) SPEND — demoted to a thin informational strip below the cockpit.
|
||||
// spendChartStyle is threaded from the viewModel so a live change in
|
||||
// Settings immediately updates the chart without a refresh.
|
||||
// spendChartStyle is threaded from the viewModel and toggled inline
|
||||
// from the Spend header, so a change updates the chart immediately.
|
||||
if let analytics = viewModel.analytics {
|
||||
Divider()
|
||||
BarAnalyticsView(analytics: analytics, section: .spend,
|
||||
spendChartStyle: viewModel.spendChartStyle)
|
||||
BarAnalyticsView(
|
||||
analytics: analytics, section: .spend,
|
||||
spendChartStyle: viewModel.spendChartStyle,
|
||||
onToggleSpendStyle: {
|
||||
viewModel.spendChartStyle =
|
||||
viewModel.spendChartStyle == .bars ? .line : .bars
|
||||
})
|
||||
}
|
||||
|
||||
// (4) POOL ACCOUNTS — compact generic rows, subordinate.
|
||||
|
||||
@@ -62,13 +62,8 @@ struct BarPreferencesView: View {
|
||||
Text("Dark").tag(BarAppearance.dark)
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
// Changing this live-updates the spend chart in the open dropdown because
|
||||
// viewModel.spendChartStyle is @Published and SpendChartStyleStore persists it.
|
||||
Picker("Spend graph", selection: $viewModel.spendChartStyle) {
|
||||
Text("Bars").tag(SpendChartStyle.bars)
|
||||
Text("Line").tag(SpendChartStyle.line)
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
// Spend graph bars/line is toggled inline in the dropdown's Spend header,
|
||||
// not here — kept out of Settings so the choice lives where the chart is.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user