2.1.0: app de Apple Watch, complicacion y widget semanal en iOS
- Target MealMoodWatch (watchOS 10, SwiftUI): vista de hoy y de la semana en TabView vertical; recibe el snapshot del iPhone por WatchConnectivity (updateApplicationContext) y lo guarda en su app group para la complicacion - Target MealMoodWatchWidget: complicacion accessoryRectangular/ Circular/Inline con las comidas de hoy (heuristica comida/cena por hora); icono del watch generado desde el logo - WatchWeekPayload compartido entre iOS app, widget iOS, watch app y complicacion — llega ya localizado desde el iPhone - Widget iOS nuevo "Semana" (systemMedium/Large) con los 7 dias; el widget de hoy pasa a WidgetBundle - Targets creados via gema xcodeproj (sin abrir Xcode); embed del watch antes del script de Crashlytics para evitar ciclo de build Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013H6bXqGX1ygwib1Dm3n3UG
This commit is contained in:
@@ -332,6 +332,13 @@ struct MealMoodWidgetView: View {
|
||||
// MARK: - Widget definition
|
||||
|
||||
@main
|
||||
struct MealMoodWidgetBundle: WidgetBundle {
|
||||
var body: some Widget {
|
||||
MealMoodWidget()
|
||||
MealMoodWeekWidget()
|
||||
}
|
||||
}
|
||||
|
||||
struct MealMoodWidget: Widget {
|
||||
let kind = "MealMoodWidget"
|
||||
|
||||
@@ -344,3 +351,81 @@ struct MealMoodWidget: Widget {
|
||||
.supportedFamilies([.systemSmall, .systemMedium, .accessoryRectangular, .accessoryInline])
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Week widget (2.1.0)
|
||||
|
||||
struct WeekEntry: TimelineEntry {
|
||||
let date: Date
|
||||
let payload: WatchWeekPayload?
|
||||
}
|
||||
|
||||
struct WeekProvider: TimelineProvider {
|
||||
func placeholder(in context: Context) -> WeekEntry {
|
||||
WeekEntry(date: Date(), payload: WatchWeekPayload.stored())
|
||||
}
|
||||
|
||||
func getSnapshot(in context: Context, completion: @escaping (WeekEntry) -> Void) {
|
||||
completion(WeekEntry(date: Date(), payload: WatchWeekPayload.stored()))
|
||||
}
|
||||
|
||||
func getTimeline(in context: Context, completion: @escaping (Timeline<WeekEntry>) -> Void) {
|
||||
let entry = WeekEntry(date: Date(), payload: WatchWeekPayload.stored())
|
||||
let nextMidnight = Calendar.current.startOfDay(for: Date()).addingTimeInterval(86_400 + 300)
|
||||
completion(Timeline(entries: [entry], policy: .after(nextMidnight)))
|
||||
}
|
||||
}
|
||||
|
||||
struct MealMoodWeekWidget: Widget {
|
||||
let kind = "MealMoodWeekWidget"
|
||||
|
||||
var body: some WidgetConfiguration {
|
||||
StaticConfiguration(kind: kind, provider: WeekProvider()) { entry in
|
||||
WeekWidgetView(entry: entry)
|
||||
.containerBackground(Color(red: 1.0, green: 0.97, blue: 0.94), for: .widget)
|
||||
}
|
||||
.configurationDisplayName("MealMood — Semana")
|
||||
.description("Your whole week at a glance.")
|
||||
.supportedFamilies([.systemMedium, .systemLarge])
|
||||
}
|
||||
}
|
||||
|
||||
struct WeekWidgetView: View {
|
||||
@Environment(\.widgetFamily) private var family
|
||||
let entry: WeekEntry
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if let payload = entry.payload, !payload.days.isEmpty {
|
||||
VStack(alignment: .leading, spacing: family == .systemLarge ? 6 : 3) {
|
||||
ForEach(payload.days, id: \.dayOfWeek) { day in
|
||||
HStack(alignment: .firstTextBaseline, spacing: 6) {
|
||||
Text(day.title)
|
||||
.font(.system(size: family == .systemLarge ? 13 : 10, weight: .bold, design: .rounded))
|
||||
.foregroundStyle(day.isToday ? Color(red: 1.0, green: 0.45, blue: 0.35) : .primary)
|
||||
.frame(width: family == .systemLarge ? 62 : 48, alignment: .leading)
|
||||
Text(mealsLine(day))
|
||||
.font(.system(size: family == .systemLarge ? 12 : 10, design: .rounded))
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(family == .systemLarge ? 2 : 1)
|
||||
Spacer(minLength: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
|
||||
} else {
|
||||
VStack(spacing: 4) {
|
||||
Image(systemName: "calendar")
|
||||
.foregroundStyle(.secondary)
|
||||
Text(verbatim: "MealMood")
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
.widgetURL(URL(string: "mealmood://today"))
|
||||
}
|
||||
|
||||
private func mealsLine(_ day: WatchWeekPayload.Day) -> String {
|
||||
day.meals.compactMap(\.name).joined(separator: " · ")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user