/// Build-time configuration, supplied with `--dart-define-from-file=env.json`. /// /// Every value has a working default, so the app builds and runs with no /// `env.json` at all: it starts in demo mode against bundled mock frames, with /// the offline map style and Google's test ad units. That keeps the repository /// free of secrets and keeps a fresh clone runnable. /// /// Values are `const` reads of `String.fromEnvironment` so they are inlined and /// tree-shaken; they cannot be read from a file at run time. library; class Env { const Env._(); /// Which region config to load from `assets/regions/.json`. static const String regionId = String.fromEnvironment( 'REGION_ID', defaultValue: 'piemonte', ); /// MapLibre style URL for the base map. /// /// Empty means no key is configured, and [hasMapStyle] is false: the app /// falls back to a minimal style bundled in assets so development and tests /// work offline. static const String mapStyleUrl = String.fromEnvironment('MAP_STYLE_URL'); static bool get hasMapStyle => mapStyleUrl.isNotEmpty; /// Base URL of the radar `manifest.json` published by our worker. /// /// Empty forces the mock radar source regardless of [radarSource]. static const String radarManifestUrl = String.fromEnvironment( 'RADAR_MANIFEST_URL', ); /// Radar adapter override: `mock`, `dpc` or `arpa`. /// /// Empty means "use whatever the region config says". static const String radarSource = String.fromEnvironment('RADAR_SOURCE'); /// Contact address embedded in the MET Norway User-Agent. /// /// MET Norway blocks generic User-Agent strings, so forecasts are disabled /// rather than attempted when this is empty — see [hasForecastContact]. static const String metnoUserAgentContact = String.fromEnvironment( 'METNO_USER_AGENT_CONTACT', ); static bool get hasForecastContact => metnoUserAgentContact.isNotEmpty; /// AdMob identifiers. Empty means Google's test units are used. static const String admobAppId = String.fromEnvironment('ADMOB_APP_ID'); static const String admobBannerUnitId = String.fromEnvironment( 'ADMOB_BANNER_UNIT_ID', ); static bool get hasAdMobConfig => admobAppId.isNotEmpty && admobBannerUnitId.isNotEmpty; /// True when nothing is configured and the app is running entirely on /// bundled data. Surfaced in the UI so demo frames are never mistaken for a /// real forecast. static bool get isDemoMode => radarManifestUrl.isEmpty; }