From 6eb17a18e901e2d7faa219d7e5a79083a5891dc9 Mon Sep 17 00:00:00 2001 From: ivar Date: Thu, 7 May 2026 01:24:28 +0200 Subject: Refactors --- .../2026-03-23-sunrise-sunset-widget-design.md | 152 --------------------- 1 file changed, 152 deletions(-) delete mode 100644 docs/superpowers/specs/2026-03-23-sunrise-sunset-widget-design.md (limited to 'docs/superpowers/specs/2026-03-23-sunrise-sunset-widget-design.md') diff --git a/docs/superpowers/specs/2026-03-23-sunrise-sunset-widget-design.md b/docs/superpowers/specs/2026-03-23-sunrise-sunset-widget-design.md deleted file mode 100644 index 1e4ed54..0000000 --- a/docs/superpowers/specs/2026-03-23-sunrise-sunset-widget-design.md +++ /dev/null @@ -1,152 +0,0 @@ -# Sunrise/Sunset Times Widget Feature - -**Date:** 2026-03-23 -**Status:** Design Approved - -## Overview - -Add sunrise and sunset time display to both small and medium widgets. Times are calculated locally using the existing NOAA solar position algorithm, formatted as HH:mm, and updated daily at midnight based on user location. - -## Requirements - -- Display sunrise/sunset times in HH:mm format on widgets -- Calculate times locally using existing `SunTimes` utility -- Use user's current location for calculations -- Update once daily at midnight (aligned with current refresh policy) -- Show nothing if location permission is denied or unavailable -- Apply to both small and medium widget families - -## Architecture - -### Data Model - -Extend `SolvervDef` to include sunrise/sunset times: -``` -SolvervDef -├── date: Date -├── bg: String -├── sunriseTime: Date? (optional) -├── sunsetTime: Date? (optional) -├── sunriseFormatted: String (computed) -└── sunsetFormatted: String (computed) -``` - -**Constructor signature:** -```swift -init(date: Date, sunriseTime: Date? = nil, sunsetTime: Date? = nil) { - self.date = date - self.sunriseTime = sunriseTime - self.sunsetTime = sunsetTime - self.bg = "smallbg" -} -``` - -The formatted properties extract HH:mm in device local time. - -### Timeline Provider Logic - -Update `Provider.getTimeline()`: - -1. Get user's cached location from `AppGroupManager` (widget must use App Group storage, not LocationManager) -2. Check if location is recent (less than 24 hours old); if stale/unavailable → create entry with nil sunrise/sunset -3. Initialize local `SunTimes(latitude, longitude, date: currentDate)` calculator -4. Extract sunrise and sunset times (already converted to device local time) -5. Create entry with times: `SolvervEntry(def: SolvervDef(date: currentDate, sunriseTime: sr, sunsetTime: ss))` -6. Return timeline refreshing at next midnight - -**Note:** Widget runs in separate process and cannot access main app's LocationManager. Location MUST come from AppGroupManager storage, populated by the main app. - -### Data Calculation Flow - -``` -Location Permission Check - ↓ (if granted) -Get Cached Coordinates - ↓ -SunTimes Calculator - ├─ Input: latitude, longitude, date - ├─ Output: sunrise Date, sunset Date - └─ Fallback: nil (polar regions, edge cases) - ↓ -Format as HH:mm - ↓ -SolvervDef/Entry - ↓ -Widget Display -``` - -### Error Handling - -| Scenario | Behavior | -|----------|----------| -| Location permission denied | No sunrise/sunset displayed | -| Location unavailable in AppGroupManager | No sunrise/sunset displayed | -| Location older than 24 hours | Treat as unavailable; no sunrise/sunset displayed | -| SunTimes returns nil (polar regions, 24h sun/darkness) | No sunrise/sunset displayed | - -### Timezone Handling - -- `SunTimes` internally converts to device's local timezone (uses `TimeZone.current`) -- Sunrise/sunset `Date` objects are in device local time -- Formatted display uses device local time (HH:mm) -- **Edge case:** If user changes timezone between midnight and next refresh, sun times remain valid for the previous timezone. They will update correctly at next midnight refresh (when new location may have different timezone). This is acceptable since widget only refreshes daily. - -## Implementation Details - -### Changes to SolvervDef - -Add properties: -- `sunriseTime: Date?` — raw sunrise time in device local timezone -- `sunsetTime: Date?` — raw sunset time in device local timezone - -Add computed properties for formatted times: -- `sunriseFormatted: String` — returns "HH:mm" format or empty string if nil -- `sunsetFormatted: String` — returns "HH:mm" format or empty string if nil - -Computed properties use device locale and 24-hour format. - -### Changes to Provider - -Modify `getTimeline()` to: -1. Fetch location from `AppGroupManager.getUserLocation()` — widget runs in separate process and must use App Group storage -2. Check timestamp: if location is older than 24 hours, treat as unavailable -3. If available, instantiate sunrise/sunset calculator: `SunTimes(latitude: lat, longitude: lon, date: currentDate)` from `/Solverv/Utilities/SunTimes.swift` -4. Call `calculator.sunrise()` and `calculator.sunset()` to get Date objects -5. Pass times to `SolvervDef(date: currentDate, sunriseTime: sr, sunsetTime: ss)` -6. Create entry and return timeline refreshing at next midnight (unchanged) - -### Widget View Updates - -**SmallWidgetView:** -- If sunrise/sunset available: display as "↑ HH:mm ↓ HH:mm" or similar compact format -- If unavailable: display nothing (no placeholder or empty space) - -**MediumWidgetView:** -- If sunrise/sunset available: display sunrise and sunset times in HH:mm format (exact layout TBD based on available space) -- If unavailable: display nothing (no placeholder or empty space) - -Both views: -- Access times via `entry.def.sunriseFormatted` and `entry.def.sunsetFormatted` -- Only render if both are non-empty strings - -## Timeline & Refresh - -- **Frequency:** Once per day at midnight -- **Rationale:** Sun times change gradually; daily updates are sufficient -- **Alignment:** Matches existing solstice countdown refresh policy - -## Testing - -- Test with various locations (tropics, temperate, near poles) -- Test without location permission -- Test at date boundaries (midnight refresh) -- Verify formatted times display correctly -- Verify nil times result in no display - -## Future Considerations - -- Visualization of sunrise/sunset (charts, gradients) -- Daylight duration calculation and trend -- Multiple locations support -- Custom location override - -- cgit v1.3