Andromida/Andromida/App/Views/Today/Components/TodayNoRitualsForTimeView.swift

129 lines
5.4 KiB
Swift

import SwiftUI
import Bedrock
/// Shown when there are active rituals but none scheduled for the current time of day.
struct TodayNoRitualsForTimeView: View {
@Bindable var store: RitualStore
private var currentTimePeriod: TimeOfDay {
let hour = Calendar.current.component(.hour, from: Date())
switch hour {
case 0..<11: return .morning
case 11..<14: return .midday
case 14..<17: return .afternoon
case 17..<21: return .evening
default: return .night
}
}
private var nextRituals: [Ritual] {
// Find rituals scheduled for later time periods
store.currentRituals.filter { ritual in
guard let arc = ritual.currentArc, arc.contains(date: Date()) else { return false }
return ritual.timeOfDay != .anytime && ritual.timeOfDay > currentTimePeriod
}
}
private var nextRitualTomorrow: Ritual? {
let calendar = Calendar.current
let tomorrowDate = calendar.startOfDay(
for: calendar.date(byAdding: .day, value: 1, to: Date()) ?? Date()
)
return store.currentRituals
.filter { ritual in
guard let arc = ritual.currentArc, arc.contains(date: tomorrowDate) else { return false }
return ritual.timeOfDay != .anytime
}
.sorted { $0.timeOfDay < $1.timeOfDay }
.first
}
var body: some View {
VStack(alignment: .leading, spacing: Design.Spacing.large) {
SectionHeaderView(
title: String(localized: "All caught up"),
subtitle: currentTimePeriod.displayName
)
VStack(spacing: Design.Spacing.large) {
// Icon
Image(systemName: currentTimePeriod.symbolName)
.font(.system(size: Design.IconSize.hero))
.foregroundStyle(AppAccent.primary.opacity(0.6))
.padding(.top, Design.Spacing.large)
VStack(spacing: Design.Spacing.xSmall) {
Text(String(localized: "No rituals scheduled for \(currentTimePeriod.displayName.lowercased())."))
.font(.subheadline)
.foregroundStyle(AppTextColors.secondary)
.multilineTextAlignment(.center)
Text(currentTimePeriod.timeRange)
.font(.caption)
.foregroundStyle(AppTextColors.tertiary)
}
// Show upcoming rituals if any
if !nextRituals.isEmpty {
VStack(alignment: .leading, spacing: Design.Spacing.medium) {
Text(String(localized: "Coming up later:"))
.font(.caption)
.foregroundStyle(AppTextColors.tertiary)
ForEach(nextRituals) { ritual in
HStack(spacing: Design.Spacing.small) {
Image(systemName: ritual.timeOfDay.symbolName)
.font(.caption)
.foregroundStyle(AppTextColors.secondary)
Text(ritual.title)
.font(.subheadline)
.foregroundStyle(AppTextColors.primary)
Spacer()
Text(ritual.timeOfDay.displayName)
.font(.caption)
.foregroundStyle(AppTextColors.tertiary)
}
.padding(Design.Spacing.small)
.background(AppSurface.secondary)
.clipShape(.rect(cornerRadius: Design.CornerRadius.small))
}
}
.padding(.top, Design.Spacing.small)
} else if let tomorrowRitual = nextRitualTomorrow {
let format = String(localized: "Next ritual: Tomorrow %@ (%@)")
Text(String.localizedStringWithFormat(
format,
tomorrowRitual.timeOfDay.displayName,
tomorrowRitual.timeOfDay.timeRange
))
.font(.caption)
.foregroundStyle(AppTextColors.tertiary)
.multilineTextAlignment(.center)
.padding(.top, Design.Spacing.small)
}
// Motivational message
Text(String(localized: "Enjoy this moment. Your next ritual will appear when it's time."))
.font(.caption)
.foregroundStyle(AppTextColors.tertiary)
.multilineTextAlignment(.center)
.padding(.top, Design.Spacing.small)
}
.padding(Design.Spacing.large)
.frame(maxWidth: .infinity)
.background(AppSurface.card)
.clipShape(.rect(cornerRadius: Design.CornerRadius.large))
}
}
}
#Preview {
TodayNoRitualsForTimeView(store: RitualStore.preview)
.padding()
.background(AppSurface.primary)
}