# Solstice Countdown Widget & App Design **Date:** 2026-03-23 **Project:** Solverv (Solstice Countdown) **Status:** Design Approved --- ## Overview Build an iOS app that displays a countdown to the next solstice or equinox, with season-specific imagery and detailed information. The app includes: - **Widget Extension:** Compact countdown widget in small, medium, and large sizes - **Main App:** Info screen showing expanded details including sunrise/sunset times and upcoming events --- ## Requirements ### Functional Requirements 1. Track all four annual solstices/equinoxes (Spring, Summer, Autumn, Winter) 2. Display countdown to next event in **days only** 3. Show season-specific images that change based on upcoming event 4. Calculate and display sunrise/sunset times for user's current location 5. Show expanded event details in main app (exact times, season descriptions, upcoming event previews) 6. Support multiple widget sizes (small, medium, large) ### Non-Functional Requirements - All calculations happen locally (no external APIs) - Works offline after initial setup - Respects location privacy with explicit permission - Single location permission prompt (shared via AppGroup) - Data synced between app and widget via AppGroup container --- ## Architecture ### Data Models **SolsticeEvent** ``` - name: String (e.g., "Summer Solstice", "Spring Equinox") - date: Date (UTC) - season: Season (enum: spring, summer, autumn, winter) - seasonDescription: String (brief description of the season) ``` **SolsticeData** ``` - events: [SolsticeEvent] (hardcoded data, 2025-2030) - nextEvent() -> SolsticeEvent (returns next upcoming event) - allUpcoming(count: Int) -> [SolsticeEvent] (returns next N events) - daysUntil(_ event: SolsticeEvent) -> Int - progressToEvent(_ event: SolsticeEvent) -> (elapsed: Int, total: Int) ``` **SunTimes** ``` - latitude: Double - longitude: Double - date: Date - sunrise() -> Date - sunset() -> Date ``` ### Data Sharing - **AppGroup Container:** Store user location (lat/lon) and cached sunrise/sunset times - **Widget Timeline:** Update once daily using WidgetKit's `.atEnd` policy - Both app and widget read from the same AppGroup container for consistency --- ## Widget Specification ### Small Widget (169×169) - **Layout:** Vertical stack - Seasonal image (fills most of space) - Event name (small caption) - Countdown in days (large, bold text) - **Refresh:** Daily - **Purpose:** Quick glance at how many days remain ### Medium Widget (364×169) - **Layout:** Horizontal split - Left: Seasonal image (square) - Right: Vertical stack with event name, countdown (large), progress bar - **Refresh:** Daily - **Purpose:** Balance of visual and numeric information ### Large Widget (364×364) - **Layout:** Vertical stack - Top half: Seasonal image - Bottom half: Event name, countdown, progress bar, preview of next 3 upcoming events (mini list) - **Refresh:** Daily - **Purpose:** Comprehensive view with upcoming events preview ### Images - One image per season (spring, summer, autumn, winter) - Sourced from Assets.xcassets - Same image shown for all events in that season --- ## Main App Info Screen ### Top Section - Seasonal image (landscape orientation friendly) - Next event name (large) - Countdown in days (very large, prominent) - Progress bar (days elapsed / total days) ### Middle Section - **Today's Sun Times** - Sunrise time - Sunset time - Calculated from device location - **Season Info** - Season name - Brief description (e.g., "Spring Equinox — Day and night are approximately equal length") ### Bottom Section - **Upcoming Events List** (scrollable) - Shows next 8-12 events - Each row: Event name | Date/Time | Days remaining | Season color indicator - Searchable/filterable by season (optional enhancement) ### Navigation - Tab bar or simple navigation to this screen - Refresh button to manually update sunrise/sunset (in case location changed) --- ## Time Zone & Location Handling ### Location - Request permission on first app launch - Store latitude/longitude in AppGroup container - Fall back to Greenwich/UTC (0°, 0°) if permission denied - User can manually update location in app settings ### Time Zones - All solstice times stored in UTC (as they are now) - Convert to user's local timezone for display - Sunrise/sunset calculated for user's timezone and location ### Sunrise/Sunset Algorithm - Use NOAA solar position algorithm (lightweight, no external API) - Built into iOS or implement a simplified version - Cache results in AppGroup container to avoid recalculation --- ## Error Handling & Edge Cases ### Location Permission - App requests permission on first launch - If denied, use default location (Greenwich) and notify user - User can grant permission later in system Settings ### Time Zone Edge Cases - Solstice at midnight: Display correctly in both UTC and local time - User crosses timezone: Times update automatically on app launch - Widget timezone: Uses device timezone (set by system) ### Data Integrity - Solstice dates are hardcoded and immutable - Sunrise/sunset cached but recalculated daily - Widget syncs with app via AppGroup on launch --- ## Testing Strategy ### Widget Testing - Preview all three widget sizes with mock solstice data - Verify countdown updates correctly across timezone boundaries - Test image display in different iOS versions (iOS 17 fallback) ### App Testing - Verify sunrise/sunset calculations against known values - Test location permission flows (allowed, denied, not yet asked) - Test data sync between app and widget - Verify time zone conversions for various user locations ### Integration Testing - Widget refreshes daily and displays current countdown - App and widget show consistent "next event" data - Location changes update sunrise/sunset in real time --- ## Implementation Notes ### Existing Code - `SolvervDef` already contains solstice dates (2025-2030) - Widget structure (`Solsnu_Widget.swift`) is scaffolded - Main app has basic SwiftUI structure ready for info screen ### New Components to Build - `SunTimes` calculation (sunrise/sunset) - `SolsticeEvent` model - Widget layout variants (small, medium, large) - Info screen UI - AppGroup data sharing ### Dependencies - None (all calculations are built-in or custom) - WidgetKit (already available) - SwiftUI (already used) --- ## Success Criteria ✅ Widget displays countdown in days ✅ Seasonal image changes based on next event ✅ All four solstices/equinoxes tracked ✅ Sunrise/sunset times calculated from location ✅ Info screen shows all requested details ✅ App and widget data stay in sync ✅ Works offline after initial setup ✅ All three widget sizes render correctly