mirror of
https://github.com/carey314/mio-plugin-worker.git
synced 2026-08-10 07:04:32 +00:00
fix(water): remove vertical scroll — fit toggles + hero in 580pt panel
WaterView added two toggle rows which pushed content past panel
height, so it got wrapped in a ScrollView. That introduced a
vertical scroll bar — visually noisy for a tab that should fit at a
glance.
Compaction strategy:
- VStack spacing 14 → 10 (saves ~24pt across 4 gaps)
- cupShape 130×160 → 100×130 (saves ~30pt + width breathing room)
- Big "X" number font 40 → unchanged (still readable in 100pt cup)
- toggleRows (vertical 2-stack of 32pt pills) → toggleRow
(horizontal 30pt single line with short labels "🍅 +1" / "整点提醒")
- Drop tipText (saves ~30pt) — redundant with the badge text
Net height now fits inside the panel without scroll.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dc0d22700c
commit
5e5540d9b1
@ -11,44 +11,43 @@ struct WaterView: View {
|
|||||||
@ObservedObject var store: WorkerStore
|
@ObservedObject var store: WorkerStore
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
// No ScrollView — panel body sits at ~470pt available and we
|
||||||
VStack(spacing: 14) {
|
// tune everything below to fit: tighter VStack spacing, smaller
|
||||||
statusBadge
|
// cup hero, toggles on a single row, no tipText.
|
||||||
|
VStack(spacing: 10) {
|
||||||
|
statusBadge
|
||||||
|
|
||||||
cupHero
|
cupHero
|
||||||
|
|
||||||
controls
|
controls
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
.background(WorkerTheme.overlay08)
|
.background(WorkerTheme.overlay08)
|
||||||
.padding(.horizontal, 24)
|
.padding(.horizontal, 24)
|
||||||
|
|
||||||
goalRow
|
goalRow
|
||||||
toggleRows
|
toggleRow
|
||||||
|
|
||||||
tipText
|
Spacer(minLength: 0)
|
||||||
|
|
||||||
Spacer(minLength: 0)
|
|
||||||
}
|
|
||||||
.padding(.top, 8)
|
|
||||||
.padding(.bottom, 8)
|
|
||||||
}
|
}
|
||||||
|
.padding(.top, 6)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Toggle rows (auto-from-pomodoro + hourly reminder)
|
// MARK: - Toggle row (compact horizontal layout — saves vertical
|
||||||
|
// space so the whole tab fits without a scroll bar).
|
||||||
|
|
||||||
private var toggleRows: some View {
|
private var toggleRow: some View {
|
||||||
VStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
togglePill(
|
togglePill(
|
||||||
icon: "timer",
|
icon: "timer",
|
||||||
label: "番茄完成 +1 杯",
|
label: "🍅 +1",
|
||||||
isOn: store.waterAutoFromPomodoro,
|
isOn: store.waterAutoFromPomodoro,
|
||||||
tint: WorkerTheme.tomato,
|
tint: WorkerTheme.tomato,
|
||||||
action: { store.waterSetAutoFromPomodoro(!store.waterAutoFromPomodoro) }
|
action: { store.waterSetAutoFromPomodoro(!store.waterAutoFromPomodoro) }
|
||||||
)
|
)
|
||||||
togglePill(
|
togglePill(
|
||||||
icon: "bell.fill",
|
icon: "bell.fill",
|
||||||
label: "整点提醒(9–18 点)",
|
label: "整点提醒",
|
||||||
isOn: store.waterHourlyReminder,
|
isOn: store.waterHourlyReminder,
|
||||||
tint: WorkerTheme.water,
|
tint: WorkerTheme.water,
|
||||||
action: { store.waterSetHourlyReminder(!store.waterHourlyReminder) }
|
action: { store.waterSetHourlyReminder(!store.waterHourlyReminder) }
|
||||||
@ -57,35 +56,38 @@ struct WaterView: View {
|
|||||||
.padding(.horizontal, 16)
|
.padding(.horizontal, 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compact toggle for the horizontal toggleRow. Icon + short label +
|
||||||
|
/// inline slim toggle track inside a single capsule. Sized to fit
|
||||||
|
/// 2 across a 380pt panel with 16pt horizontal padding.
|
||||||
private func togglePill(icon: String, label: String, isOn: Bool, tint: Color, action: @escaping () -> Void) -> some View {
|
private func togglePill(icon: String, label: String, isOn: Bool, tint: Color, action: @escaping () -> Void) -> some View {
|
||||||
Button(action: action) {
|
Button(action: action) {
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 6) {
|
||||||
Image(systemName: icon)
|
Image(systemName: icon)
|
||||||
.font(.system(size: 11, weight: .semibold))
|
.font(.system(size: 10, weight: .semibold))
|
||||||
.foregroundColor(isOn ? tint : WorkerTheme.fg55)
|
.foregroundColor(isOn ? tint : WorkerTheme.fg55)
|
||||||
.frame(width: 18)
|
|
||||||
Text(label)
|
Text(label)
|
||||||
.font(.system(size: 11.5, weight: .medium))
|
.font(.system(size: 11, weight: .medium))
|
||||||
.foregroundColor(isOn ? WorkerTheme.fgPrimary : WorkerTheme.fg70)
|
.foregroundColor(isOn ? WorkerTheme.fgPrimary : WorkerTheme.fg70)
|
||||||
Spacer()
|
.lineLimit(1)
|
||||||
// Slim track-style toggle indicator.
|
Spacer(minLength: 4)
|
||||||
ZStack(alignment: isOn ? .trailing : .leading) {
|
ZStack(alignment: isOn ? .trailing : .leading) {
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(isOn ? tint.opacity(0.35) : WorkerTheme.overlay08)
|
.fill(isOn ? tint.opacity(0.35) : WorkerTheme.overlay08)
|
||||||
.frame(width: 28, height: 16)
|
.frame(width: 24, height: 14)
|
||||||
Circle()
|
Circle()
|
||||||
.fill(isOn ? tint : WorkerTheme.fg55)
|
.fill(isOn ? tint : WorkerTheme.fg55)
|
||||||
.frame(width: 12, height: 12)
|
.frame(width: 10, height: 10)
|
||||||
.padding(2)
|
.padding(2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 12)
|
.padding(.horizontal, 10)
|
||||||
.frame(height: 32)
|
.frame(maxWidth: .infinity)
|
||||||
|
.frame(height: 30)
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 10)
|
RoundedRectangle(cornerRadius: 8)
|
||||||
.fill(WorkerTheme.overlay04)
|
.fill(WorkerTheme.overlay04)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 10)
|
RoundedRectangle(cornerRadius: 8)
|
||||||
.stroke(isOn ? tint.opacity(0.35) : WorkerTheme.overlay08, lineWidth: 0.5)
|
.stroke(isOn ? tint.opacity(0.35) : WorkerTheme.overlay08, lineWidth: 0.5)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -120,23 +122,24 @@ struct WaterView: View {
|
|||||||
// MARK: - Cup hero (tappable)
|
// MARK: - Cup hero (tappable)
|
||||||
|
|
||||||
private var cupHero: some View {
|
private var cupHero: some View {
|
||||||
VStack(spacing: 12) {
|
VStack(spacing: 8) {
|
||||||
Button(action: { store.waterAddCup() }) {
|
Button(action: { store.waterAddCup() }) {
|
||||||
ZStack {
|
ZStack {
|
||||||
// Water-fill cup illustration.
|
// Water-fill cup — sized down from 130×160 to fit
|
||||||
|
// the 380×580 panel without scroll.
|
||||||
cupShape
|
cupShape
|
||||||
.frame(width: 130, height: 160)
|
.frame(width: 100, height: 130)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
.help("点击杯子记录一杯水")
|
.help("点击杯子记录一杯水")
|
||||||
|
|
||||||
// Progress dots
|
// Progress dots
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: 5) {
|
||||||
ForEach(0..<store.waterGoal, id: \.self) { i in
|
ForEach(0..<store.waterGoal, id: \.self) { i in
|
||||||
Circle()
|
Circle()
|
||||||
.fill(i < store.waterCupsToday ? WorkerTheme.water : WorkerTheme.overlay08)
|
.fill(i < store.waterCupsToday ? WorkerTheme.water : WorkerTheme.overlay08)
|
||||||
.frame(width: 9, height: 9)
|
.frame(width: 8, height: 8)
|
||||||
.overlay(
|
.overlay(
|
||||||
Circle()
|
Circle()
|
||||||
.stroke(WorkerTheme.overlay12, lineWidth: 0.5)
|
.stroke(WorkerTheme.overlay12, lineWidth: 0.5)
|
||||||
@ -269,16 +272,6 @@ struct WaterView: View {
|
|||||||
.padding(.horizontal, 16)
|
.padding(.horizontal, 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var tipText: some View {
|
|
||||||
Text(store.waterCupsToday >= store.waterGoal
|
|
||||||
? "今天的水喝够了,给自己鼓个掌 👏"
|
|
||||||
: "保持每小时一杯,工作更高效。")
|
|
||||||
.font(.system(size: 11))
|
|
||||||
.foregroundColor(WorkerTheme.fg45)
|
|
||||||
.padding(.horizontal, 20)
|
|
||||||
.multilineTextAlignment(.center)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Cup outline shape
|
// MARK: - Cup outline shape
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user