import SwiftUI import WidgetKit import Bedrock struct AndromidaWidgetView: View { var entry: WidgetEntry @Environment(\.widgetFamily) var family var body: some View { switch family { case .systemSmall: SmallWidgetView(entry: entry) .widgetURL(URL(string: "andromida://today")) case .systemMedium: MediumWidgetView(entry: entry) .widgetURL(URL(string: "andromida://today")) case .systemLarge: LargeWidgetView(entry: entry) .widgetURL(URL(string: "andromida://today")) default: SmallWidgetView(entry: entry) .widgetURL(URL(string: "andromida://today")) } } } struct LargeWidgetView: View { let entry: WidgetEntry var body: some View { VStack(alignment: .leading, spacing: Design.Spacing.large) { HStack { VStack(alignment: .leading, spacing: Design.Spacing.xSmall) { Text(String(localized: "Today's Progress")) .styled(.heading, emphasis: .custom(AppTextColors.primary)) Text("\(entry.currentStreak) day streak") .styled(.subheading, emphasis: .custom(AppAccent.primary)) } Spacer() ZStack { Circle() .stroke(AppTextColors.primary.opacity(0.1), lineWidth: 6) Circle() .trim(from: 0, to: entry.completionRate) .stroke(AppAccent.primary, style: StrokeStyle(lineWidth: 6, lineCap: .round)) .rotationEffect(.degrees(-90)) Text("\(Int(entry.completionRate * 100))%") .styled(.captionEmphasis, emphasis: .custom(AppTextColors.primary)) } .frame(width: 50, height: 50) } .padding(.top, Design.Spacing.small) Divider() .background(AppTextColors.primary.opacity(0.2)) if entry.nextHabits.isEmpty { WidgetEmptyStateView( iconSize: .section, title: String(localized: "No rituals scheduled for \(entry.currentTimeOfDay.lowercased())."), subtitle: entry.currentTimeOfDay, symbolName: entry.currentTimeOfDaySymbol, timeRange: entry.currentTimeOfDayRange, nextRitual: entry.nextRitualInfo, isCompact: false ) } else { Text(String(localized: "Habits")) .styled(.captionEmphasis, emphasis: .custom(AppTextColors.secondary)) VStack(spacing: Design.Spacing.medium) { ForEach(entry.nextHabits) { habit in HStack(spacing: Design.Spacing.medium) { Image(systemName: habit.symbolName) .foregroundColor(AppAccent.primary) .font(.system(size: 18)) .frame(width: 24) VStack(alignment: .leading, spacing: Design.Spacing.xSmall) { Text(habit.title) .styled(.subheading, emphasis: .custom(AppTextColors.primary)) Text(habit.ritualTitle) .styled(.caption, emphasis: .custom(AppTextColors.tertiary)) } Spacer() Image(systemName: habit.isCompleted ? "checkmark.circle.fill" : "circle") .foregroundColor(habit.isCompleted ? .green : AppTextColors.primary.opacity(0.2)) .font(.system(size: 20)) } } } } Spacer() } .padding(Design.Spacing.large) .containerBackground(for: .widget) { AppSurface.primary } } } // MARK: - Branding Colors Helper extension Color { static let brandingPrimary = Color(red: 0.12, green: 0.09, blue: 0.08) static let brandingAccent = Color(red: 0.95, green: 0.60, blue: 0.45) // Matches the orange-ish accent in your app } // MARK: - Previews for Testing Time-of-Day Changes #Preview("Morning", as: .systemMedium) { AndromidaWidget() } timeline: { WidgetEntry.morningPreview } #Preview("Midday", as: .systemMedium) { AndromidaWidget() } timeline: { WidgetEntry.middayPreview } #Preview("Afternoon", as: .systemMedium) { AndromidaWidget() } timeline: { WidgetEntry.afternoonPreview } #Preview("Evening", as: .systemMedium) { AndromidaWidget() } timeline: { WidgetEntry.eveningPreview } #Preview("Night", as: .systemMedium) { AndromidaWidget() } timeline: { WidgetEntry.nightPreview } #Preview("Empty State", as: .systemMedium) { AndromidaWidget() } timeline: { WidgetEntry.emptyPreview } #Preview("Large - All Times", as: .systemLarge) { AndromidaWidget() } timeline: { WidgetEntry.morningPreview WidgetEntry.middayPreview WidgetEntry.afternoonPreview WidgetEntry.eveningPreview WidgetEntry.nightPreview }