From 3a171b163735bac0d497088b8c01b5f94ca5c6e9 Mon Sep 17 00:00:00 2001 From: ivar Date: Mon, 23 Mar 2026 15:18:33 +0100 Subject: Add solstice widget design spec --- .../specs/2026-03-23-solstice-widget-design.md | 223 +++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 docs/superpowers/specs/2026-03-23-solstice-widget-design.md diff --git a/docs/superpowers/specs/2026-03-23-solstice-widget-design.md b/docs/superpowers/specs/2026-03-23-solstice-widget-design.md new file mode 100644 index 0000000..f3b889c --- /dev/null +++ b/docs/superpowers/specs/2026-03-23-solstice-widget-design.md @@ -0,0 +1,223 @@ +# 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 -- cgit v1.3