summaryrefslogtreecommitdiffstats
path: root/docs/superpowers/specs/2026-03-23-sunrise-sunset-widget-design.md
blob: 27f7dbd8b7a66ca2daceb2bb73d6aa9d1b11c966 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# 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, time only)
└── sunsetTime: Date? (optional, time only)
```

Extend `SolvervEntry` to propagate the times:
```
SolvervEntry
├── date: Date
├── def: SolvervDef (contains sunrise/sunset)
```

### Timeline Provider Logic

Update `Provider.getTimeline()`:

1. Get user's cached location (latitude, longitude)
2. If location unavailable → create entry with nil sunrise/sunset
3. Initialize `SunTimes(latitude, longitude, date: currentDate)`
4. Extract sunrise and sunset times
5. Create entry with times
6. Refresh at next midnight

### 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/stale | No sunrise/sunset displayed |
| SunTimes returns nil (polar) | No sunrise/sunset displayed |
| Date parsing fails | Widget shows current time's calculation |

## Implementation Details

### Changes to SolvervDef

Add properties and computed properties for formatted times:
- `sunriseTime: Date?` — raw sunrise time
- `sunsetTime: Date?` — raw sunset time
- `sunriseFormatted: String` — "HH:mm" or empty
- `sunsetFormatted: String` — "HH:mm" or empty

### Changes to Provider

Modify `getTimeline()` to:
1. Fetch location from cache (use existing location service)
2. If available, calculate sun times via `SunTimes`
3. Pass times to `SolvervDef` constructor
4. Return timeline refreshing at next midnight

### Widget View Updates

**SmallWidgetView:** Add sunrise/sunset display (layout TBD)
**MediumWidgetView:** Add sunrise/sunset display (layout TBD)

Display format: sunrise time and sunset time as HH:mm when available.

## 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