mirror of
https://github.com/carey314/mio-plugin-worker.git
synced 2026-08-10 07:04:32 +00:00
feat(clockout): weekend "今天不上班" mode
Saturday/Sunday previously kept showing the workday countdown even
though no one's working — UX surfaced friction where there was
nothing to count. Now ClockoutView switches to a purple
weekend-hero card with "🌴 今天是周末 · 去做你想做的事" copy.
Implementation:
- WorkerStore.isWeekend computed (Sun=1, Sat=7)
- ClockoutView.body branches: weekendHero + weekendTipText for
weekend, original countdown+progress+controls for weekday
- Clockout celebration logic still runs in the background — if
someone does work Saturday and crosses their configured clockout
hour, the next-weekday view will see the dedupe key updated;
no spurious extra fire
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d4fea96d17
commit
f0a116ccf7
@ -576,6 +576,14 @@ final class WorkerStore: ObservableObject {
|
|||||||
/// no observable "zero" frame — celebrating the "下班" moment was
|
/// no observable "zero" frame — celebrating the "下班" moment was
|
||||||
/// impossible. Now: hit zero, hold zero until midnight, restart at
|
/// impossible. Now: hit zero, hold zero until midnight, restart at
|
||||||
/// new day's wall-time countdown.
|
/// new day's wall-time countdown.
|
||||||
|
/// True iff today is Saturday or Sunday (local time). Used by
|
||||||
|
/// ClockoutView to switch to a "今天不上班" mode without forcing
|
||||||
|
/// the user to fiddle with their clockout time on the weekend.
|
||||||
|
var isWeekend: Bool {
|
||||||
|
let weekday = calendar.component(.weekday, from: Date())
|
||||||
|
return weekday == 1 || weekday == 7 // Sun = 1, Sat = 7
|
||||||
|
}
|
||||||
|
|
||||||
var clockoutRemainingSec: Int {
|
var clockoutRemainingSec: Int {
|
||||||
let now = Date()
|
let now = Date()
|
||||||
var comps = calendar.dateComponents([.year, .month, .day], from: now)
|
var comps = calendar.dateComponents([.year, .month, .day], from: now)
|
||||||
|
|||||||
@ -16,24 +16,23 @@ struct ClockoutView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .top) {
|
ZStack(alignment: .top) {
|
||||||
VStack(spacing: 18) {
|
VStack(spacing: 18) {
|
||||||
|
if store.isWeekend {
|
||||||
|
weekendHero
|
||||||
|
weekendTipText
|
||||||
|
Spacer(minLength: 0)
|
||||||
|
} else {
|
||||||
statusBadge
|
statusBadge
|
||||||
|
|
||||||
countdownDisplay
|
countdownDisplay
|
||||||
|
|
||||||
progressBar
|
progressBar
|
||||||
|
|
||||||
controls
|
controls
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
.background(WorkerTheme.overlay08)
|
.background(WorkerTheme.overlay08)
|
||||||
.padding(.horizontal, 24)
|
.padding(.horizontal, 24)
|
||||||
|
|
||||||
timeRow
|
timeRow
|
||||||
|
|
||||||
tipText
|
tipText
|
||||||
|
|
||||||
Spacer(minLength: 0)
|
Spacer(minLength: 0)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.padding(.top, 8)
|
.padding(.top, 8)
|
||||||
|
|
||||||
// Celebration banner — overlays the panel for ~5s after the
|
// Celebration banner — overlays the panel for ~5s after the
|
||||||
@ -275,6 +274,72 @@ struct ClockoutView: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Weekend mode
|
||||||
|
|
||||||
|
/// Weekend-mode hero — replaces the countdown card with a purple
|
||||||
|
/// "today's a weekend" panel. The clockout countdown still works
|
||||||
|
/// in the background (anyone working Saturday's edge case), but
|
||||||
|
/// the default UI no longer rubs in the fact that there's
|
||||||
|
/// theoretically a clockout time on a day no one's working.
|
||||||
|
private var weekendHero: some View {
|
||||||
|
VStack(spacing: 8) {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
Circle()
|
||||||
|
.fill(WorkerTheme.weekendPurple)
|
||||||
|
.frame(width: 8, height: 8)
|
||||||
|
.shadow(color: WorkerTheme.weekendPurple.opacity(0.7), radius: 4)
|
||||||
|
Text("今天不上班")
|
||||||
|
.font(.system(size: 12.5, weight: .semibold))
|
||||||
|
.foregroundColor(WorkerTheme.fg85)
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 12)
|
||||||
|
.frame(height: 26)
|
||||||
|
.background(Capsule().fill(WorkerTheme.overlay06))
|
||||||
|
|
||||||
|
Text("🌴")
|
||||||
|
.font(.system(size: 64))
|
||||||
|
.padding(.top, 8)
|
||||||
|
|
||||||
|
Text("今天是周末")
|
||||||
|
.font(.system(size: 22, weight: .bold))
|
||||||
|
.foregroundColor(WorkerTheme.fgPrimary)
|
||||||
|
|
||||||
|
Text("去做你想做的事")
|
||||||
|
.font(.system(size: 13))
|
||||||
|
.foregroundColor(WorkerTheme.fg55)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.padding(.vertical, 28)
|
||||||
|
.background(
|
||||||
|
RoundedRectangle(cornerRadius: 14)
|
||||||
|
.fill(
|
||||||
|
LinearGradient(
|
||||||
|
colors: [
|
||||||
|
WorkerTheme.weekendPurple.opacity(0.18),
|
||||||
|
WorkerTheme.weekendPurple.opacity(0.04)
|
||||||
|
],
|
||||||
|
startPoint: .topLeading, endPoint: .bottomTrailing
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 14)
|
||||||
|
.stroke(WorkerTheme.weekendPurple.opacity(0.35), lineWidth: 0.5)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.padding(.horizontal, 16)
|
||||||
|
.padding(.top, 12)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var weekendTipText: some View {
|
||||||
|
Text("如果你周末也上班,记得在 周末 tab 取消休息时调整设置。\n(暂时还没做这个 toggle — 反正下周一会自动恢复倒计时。)")
|
||||||
|
.font(.system(size: 11))
|
||||||
|
.foregroundColor(WorkerTheme.fg45)
|
||||||
|
.padding(.horizontal, 20)
|
||||||
|
.padding(.top, 8)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
}
|
||||||
|
|
||||||
private var tipText: some View {
|
private var tipText: some View {
|
||||||
Text("到点会有通知 + 一段 Glass 音效庆祝下班\n每日只触发一次,重启插件不会重复响铃。")
|
Text("到点会有通知 + 一段 Glass 音效庆祝下班\n每日只触发一次,重启插件不会重复响铃。")
|
||||||
.font(.system(size: 11))
|
.font(.system(size: 11))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user