a049e4f74b
El iPhone marcaba isToday al construir el snapshot y el reloj se creia esa marca para siempre. Como el snapshot sobrevive en el app group, un sabado seguia enseñando la cena del miercoles: el dia que era cuando se genero. Ahora cada dia viaja con su fecha real y el reloj busca hoy cuando dibuja. Si el snapshot es de otra semana no hay "hoy" que enseñar, asi que en vez de colar la comida de otro dia lo dice y pide abrir el iPhone. Para snapshots guardados por versiones anteriores, que no traen fecha, solo se confia en el indice del dia mientras el propio snapshot sea de esta semana. Ademas el reloj pide datos al abrirse y el iPhone, en vez de responder con lo ultimo que cacheo, reconstruye la semana desde el store — que es la otra mitad del "no se actualiza": el cache podia ser de hace dias. Y cuando no hay nada planificado se dice, que antes era un guion indistinguible de una comida marcada como no planificada: "Hoy no hay nada planificado" para el dia entero y "Sin planificar" por comida, en los 6 idiomas (el bundle del reloj no tiene cadenas propias, viajan en el envio). Refs #34, #35 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013su1ttRiMeMYxkZJ1Y3246
84 lines
3.2 KiB
Swift
84 lines
3.2 KiB
Swift
import SwiftUI
|
|
|
|
/// Week page — Calendar-app style: day number in a circle on the left (today
|
|
/// filled in coral), meals with tinted icons on the right.
|
|
struct WeekView: View {
|
|
@EnvironmentObject private var store: WatchWeekStore
|
|
|
|
var body: some View {
|
|
Group {
|
|
if let payload = store.payload {
|
|
ScrollView {
|
|
VStack(alignment: .leading, spacing: 6) {
|
|
Text(payload.weekTitle)
|
|
.font(.system(.footnote, design: .rounded, weight: .bold))
|
|
.foregroundStyle(WatchTheme.coral)
|
|
.padding(.horizontal, 2)
|
|
|
|
ForEach(payload.days, id: \.dayOfWeek) { day in
|
|
// Nothing is "today" in a snapshot that no longer
|
|
// covers today.
|
|
DayRow(day: day, isToday: payload.currentDay()?.dayOfWeek == day.dayOfWeek)
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
EmptySyncView()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct DayRow: View {
|
|
let day: WatchWeekPayload.Day
|
|
/// Resolved by the payload when the view renders, not by the snapshot's own
|
|
/// frozen `isToday`.
|
|
let isToday: Bool
|
|
|
|
/// "Lun 8" → ("Lun", "8")
|
|
private var parts: (name: String, number: String) {
|
|
let pieces = day.title.split(separator: " ", maxSplits: 1)
|
|
guard pieces.count == 2 else { return (day.title, "") }
|
|
return (String(pieces[0]), String(pieces[1]))
|
|
}
|
|
|
|
var body: some View {
|
|
HStack(alignment: .top, spacing: 8) {
|
|
VStack(spacing: 0) {
|
|
Text(parts.name.uppercased())
|
|
.font(.system(size: 9, weight: .bold, design: .rounded))
|
|
.foregroundStyle(isToday ? WatchTheme.coral : .secondary)
|
|
Text(parts.number)
|
|
.font(.system(size: 15, weight: .bold, design: .rounded))
|
|
.foregroundStyle(isToday ? .white : .primary)
|
|
.frame(width: 26, height: 26)
|
|
.background(
|
|
Circle().fill(isToday ? WatchTheme.coral : .clear)
|
|
)
|
|
}
|
|
.frame(width: 32)
|
|
|
|
VStack(alignment: .leading, spacing: 3) {
|
|
ForEach(Array(day.meals.enumerated()), id: \.offset) { _, meal in
|
|
HStack(spacing: 4) {
|
|
Image(systemName: WatchWeekPayload.icon(for: meal.type))
|
|
.font(.system(size: 9, weight: .semibold))
|
|
.foregroundStyle(WatchTheme.accent(for: meal.type))
|
|
.frame(width: 12)
|
|
Text(meal.name ?? "—")
|
|
.font(.system(size: 13, design: .rounded))
|
|
.lineLimit(1)
|
|
}
|
|
}
|
|
}
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.padding(.vertical, 5)
|
|
.padding(.horizontal, 7)
|
|
.background(
|
|
isToday ? WatchTheme.coral.opacity(0.16) : Color.white.opacity(0.07),
|
|
in: RoundedRectangle(cornerRadius: 9)
|
|
)
|
|
}
|
|
}
|
|
}
|