Andromida/AndromidaWidget/Views/AndromidaWidgetView.swift

157 lines
5.4 KiB
Swift

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
}