f434a68155aabf2f0c30163ec9faa29ec4323e0a
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f434a68155 |
Replace the default Flutter icon with a stylised cloud
The app shipped the Flutter template's blue F, which said nothing about what it does and did not match the interface. The launcher icon is now a white cloud on the same seed blue the app themes itself with, so the two read as one product. The icon is drawn rather than hand-edited: tool/generate_icon.py renders it from signed distance fields — a union of three circles and a rounded box — using only the standard library, so regenerating it needs no image toolchain. The shape's framing is derived from its own bounding box, which is what keeps it centred; maintaining the bounds separately from the shape had it drifting off-centre. Adds the adaptive icon and the Android 13 monochrome layer, which were missing entirely. The generator frames the cloud against the 72dp the launcher mask always keeps and adaptive_icon_foreground_inset is 0, so the layer is not shrunk twice and the icon reads at the same size as its neighbours on a home screen. Verified on the emulator: the cloud appears in the app drawer and holds its shape down to 48px. docs/architecture.md records how to regenerate it, including the flutter_launcher_icons 0.14.4 bug that writes a string into a boolean Xcode setting and needs reverting by hand afterwards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
06ab816ebe |
Add saved places and optional device location
A saved place is a named point the user keeps: it frames the map now, and once the worker publishes station data it is what the nearest-station readings and, later, the rain notifications will hang off. Free points rather than stations, because people think in terms of home and work, not in terms of which weather station happens to represent them. Everything stays on the device. Places live in SharedPreferences under a versioned key, and there is no account to attach them to and no server that would accept them. That is what keeps the Data safety declaration able to say no location is collected, and it must survive the notification work: the device will subscribe to the topic for the cell containing a place, so the link between a person and a place never leaves their phone. Location is coarse only, and that took enforcing. geolocator declares ACCESS_FINE_LOCATION in its own manifest and the merger pulls it in, so the system dialog offered "Precise" despite the app asking for nothing of the sort; the manifest now removes it with tools:node="remove", and the dialog reads "approximate location" with no choice offered. Requests also go through the platform LocationManager rather than the Play Services fused provider, which prompts about Location Accuracy and, when declined, returns no fix at all — an absurd outcome for an app that only ever wanted an approximate one, and one that also tied location to Play Services being present. The prominent disclosure comes before the system dialog, as Play requires, and is repeated in Settings so someone who already answered can still read what the permission is for. Declining leaves the app fully usable. Two more defects found by running it and by a test: - MapLibreMap leaves cameraPosition null unless trackCameraPosition is set, so "save the map centre" silently saved the region default rather than what the user was looking at. - Place ids came straight from the microsecond clock, so two places saved in the same microsecond shared an id and rename, remove and the duplicate-name check all acted on the wrong one. A test caught it on a fast machine. Saving refuses points outside the region rather than accepting them: a place in Rome would look like it worked and then show nothing forever. Also corrects CLAUDE.md, which still said ARPA states no licence, and records the ARPA realtime API there with the property that governs how it may be used — it lags about 4.5 hours, so it is an observation archive and must never sit next to 5-minute radar looking current. Verified: analyze clean, 158 tests passing, and on the emulator the disclosure precedes the system dialog, the dialog asks only for approximate location, a place survives restart and reinstall, and tapping one moves the map onto it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
f3a0e3794a |
Narrow scope to radar, and put the app on a real OpenStreetMap base map
Drops forecasts, lightning, the home-screen widget and advertising. What remains is radar on a map, the official ARPA alert bulletin, and rain notifications. The base map is now OpenFreeMap's Positron style: real OpenStreetMap vector tiles with no API key, no registration, no request limits and commercial use permitted. Every other free tier — MapTiler, Stadia, Jawg, Thunderforest — needs a key, which is a secret to manage, a quota to outgrow and a signup to complete before anyone can build the project, and the map is the one thing the app cannot work without. Positron rather than Liberty or Bright because the radar overlay has to be the loudest thing on screen, and a desaturated grey base is built to sit under data. Its style JSON carries no `attribution` field, so MapLibre displays no credits by itself. The app renders them from the region config instead: the two mandatory credits, OpenStreetMap and OpenMapTiles, go in the always-visible bar, and OpenFreeMap's own credit — optional by their terms — is listed on the Sources screen with the rest. The bundled offline style is still reachable with MAP_STYLE_URL=offline, and still claims no base map attribution, because crediting OpenStreetMap while showing it would be a false claim. Radar-DPC stays the source. ARPA Piemonte's own radar remains a disabled stub for two reasons that belong to the project owner, not to the code: the real-time access link is only issued by email, and the open-data page states the data is "gratuiti" and nothing else. Free of charge is not a licence, and rendering those volumes into frames served from a CDN is redistribution. Both questions go in the same email. An earlier draft of the docs recorded ARPA radar as CC BY 4.0; the source page does not support that, so the claim is removed rather than carried forward. The documentation is updated throughout rather than annotated: CLAUDE.md gains an explicit scope boundary, data-sources drops MET Norway and ISTAT and gains the base map, licenses records that free of charge is not a licence, privacy loses the whole advertising section, and the roadmap is renumbered so the backend worker is next — until it exists, DpcRadarSource has nothing to read. licenses.md keeps Open-Meteo and Blitzortung listed as excluded even though the features that would have used them are gone: both are non-commercial-only, ads are a plausible future, and neither should be adopted on the grounds that there are none today. Verified: analyze clean, 130 tests passing, and on the emulator the radar overlay sits correctly over Piedmont on real OSM tiles with Turin, Milan and Genoa labelled, the age reads "Aggiornato 4 minuti fa", and the Sources screen lists all five credits with their licences. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
3fcbb9f1c4 |
Add monorepo scaffolding and project documentation
Sets up the Nuvolari monorepo layout (app/, backend/, docs/, tool/) with the groundwork that does not depend on the Flutter toolchain: gitignore covering Flutter, Python and every secret file shape; env.example.json as the template for --dart-define-from-file; a verification script that skips stages whose target does not exist yet so it is runnable from day one; and a CI workflow in GitHub Actions syntax so it runs unchanged on Gitea or GitHub. The documentation records facts verified against the live services rather than restated from the brief. Two of them change the design: - DPC VMI rasters are 1200x1400 Float32 on a 1 km grid in a custom projection centred on Italy, not EPSG:4326 or EPSG:3857, and their GeoKeys are internally inconsistent. Reprojection is mandatory and the source CRS must be read from each file rather than hardcoded. - The ARPA CAP feed carries six level values, not four: BIANCO for the avalanche scale out of season and "-" for no data. Collapsing either into VERDE would report "no alert" where the bulletin reports "not assessed". Also documents why the frames we publish inherit CC BY-SA from the DPC source, and why rain notifications subscribe to cell topics from the device so no user location ever reaches a server. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |