Fix stale day/night weather glyph (derive at render time) - #8
Merged
Conversation
… at render time Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The weather glyph showed a moon crescent during the day (observed at 13:44).
nowIsDaywas baked once at fetch time from Open-Meteo'sis_day, cached as a boolean, and merely read back on every minute-tick redraw. Weather refreshes at most every 30 min (network-constrained, Doze-deferrable), so the day/night flag froze between fetches — the moon persisted into daytime and vice-versa.Fix
Fetch and cache today's sunrise/sunset, and derive
nowIsDayat render time from the current clock instead of trusting the stale cached boolean. Self-corrects every minute-tick even with zero daytime fetches (Doze-proof).daily=weather_code,sunrise,sunseton the fetch →DailyDto(sunrise/sunset defaulted toemptyList(), so a custom endpoint that omits them still parses) → carried onWeatherSnapshot→ cached with two new nullable string keys (remove-on-null; no migration — old caches readnull).DayNightResolver.isDay(now, sunriseIso, sunsetIso, fallback)— time-of-day compare over[sunrise, sunset); falls back to the fetch-timeis_daywhen times are absent or unparseable.WidgetStateResolverapplies it using its already-injectednowlambda,copy()-correcting the snapshot.DotGridis untouched — the renderer stays a dumb consumer.Time-of-day comparison (not date-matched) is immune to a missed-midnight cache and is plenty precise for a sun-vs-moon glyph.
Tests
TDD, JUnit5 + injected-lambda clock + hand fakes:
DayNightResolverTest(9) — window, inclusive-sunrise/exclusive-sunset boundaries, null/unparseable fallback, and the 13:44-moon regression.WidgetStateResolverTest— staleis_day=falsesnapshot corrected to day at render; fallback kept when sunrise/sunset absent.WeatherMapperTest,ForecastDtoParseTest,DataStorePersistenceTestextended for sunrise/sunset mapping, parsing (incl. omitted), and cache round-trip (incl. null)../gradlew test spotlessCheck— all green.🤖 Generated with Claude Code