{"id":37942811,"url":"https://github.com/timbortnik/widget","last_synced_at":"2026-05-31T15:00:30.482Z","repository":{"id":332326731,"uuid":"1126199206","full_name":"timbortnik/widget","owner":"timbortnik","description":"Open-source Android weather widget — home-screen meteogram with 48-hour and 7-day forecasts. No ads, no tracking, no account. Powered by Open-Meteo","archived":false,"fork":false,"pushed_at":"2026-05-31T13:02:21.000Z","size":10543,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-31T14:21:28.686Z","etag":null,"topics":["android","android-widget","flutter","forecast","home-widget","kotlin","material-you","meteogram","no-tracking","open-meteo","open-source","privacy","weather","weather-app","weather-widget"],"latest_commit_sha":null,"homepage":"https://play.google.com/store/apps/details?id=org.bortnik.meteogram","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timbortnik.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-01T11:15:08.000Z","updated_at":"2026-05-31T13:01:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/timbortnik/widget","commit_stats":null,"previous_names":["timbortnik/widget"],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/timbortnik/widget","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timbortnik%2Fwidget","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timbortnik%2Fwidget/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timbortnik%2Fwidget/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timbortnik%2Fwidget/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timbortnik","download_url":"https://codeload.github.com/timbortnik/widget/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timbortnik%2Fwidget/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33735663,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-widget","flutter","forecast","home-widget","kotlin","material-you","meteogram","no-tracking","open-meteo","open-source","privacy","weather","weather-app","weather-widget"],"created_at":"2026-01-16T17:46:25.320Z","updated_at":"2026-05-31T15:00:30.476Z","avatar_url":"https://github.com/timbortnik.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Meteograph\n\nOpen-source Android weather widget that puts a detailed forecast directly on\nyour home screen — no ads, no tracking, no account. Choose a 48-hour or 7-day\nmeteogram with temperature, precipitation, and daylight on a single glanceable\nchart. Powered by the free Open-Meteo API.\n\n\u003ca href=\"https://play.google.com/store/apps/details?id=org.bortnik.meteogram\"\u003e\n  \u003cimg alt=\"Get it on Google Play\" height=\"72\"\n       src=\"https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png\"\u003e\n\u003c/a\u003e\n\n![Flutter](https://img.shields.io/badge/Flutter-3.x-blue.svg)\n![License](https://img.shields.io/badge/License-BSL_1.1-blue.svg)\n![Platform](https://img.shields.io/badge/Platform-Android-brightgreen.svg)\n\n## Features\n\n- **Two home-screen widgets**: 48-hour chart (46h forecast + 6h past) and\n  7-day chart, both rendered natively via AndroidSVG\n- **Meteogram chart** with:\n  - Temperature line with gradient fill\n  - Precipitation bars\n  - Daylight intensity (computed from cloud cover and sun position)\n  - Current time marker\n  - Weekday labels (weekly) / hour labels (48h)\n- **Smart refresh**:\n  - Foreground timer checks every minute for stale data (\u003e15 min) and\n    redraws at half-hour boundaries\n  - AlarmManager (~15 min inexact) catches up on device wake\n  - WorkManager periodic task (~30 min) with network-connected constraint\n  - BOOT_COMPLETED refresh on device restart\n  - Event-driven updates (screen unlock, network change, locale/timezone change)\n- **Flexible location**:\n  - GPS with reverse geocoding (native platform geocoder)\n  - City search via Open-Meteo geocoding API\n  - Recent cities remembered\n  - Berlin default when GPS unavailable\n- **Material You** dynamic color support (Android 12+)\n- **Light/dark theme** following system preference\n- **36 languages** supported\n- **Locale-aware units** (°F for US/Liberia/Myanmar, °C elsewhere; 12/24h time)\n- **Offline support** with smart caching:\n  - Automatic cache fallback when offline\n  - Fibonacci retry backoff (1, 2, 3, 5, 8 min) for background refresh\n  - Visual \"OFFLINE\" watermark on stale data (\u003e1 hour old)\n  - Cached location and city name preserved\n- **No API key required** — uses free Open-Meteo API\n- **No ads, no tracking, no account**\n\n## Screenshots\n\n\u003cp\u003e\n  \u003cimg src=\"store/screenshots/screen1.png\" width=\"22%\" alt=\"Home screen widget\"\u003e\n  \u003cimg src=\"store/screenshots/screen2.png\" width=\"22%\" alt=\"In-app chart\"\u003e\n  \u003cimg src=\"store/screenshots/screen3.png\" width=\"22%\" alt=\"Dark mode\"\u003e\n  \u003cimg src=\"store/screenshots/screen4.png\" width=\"22%\" alt=\"Location picker\"\u003e\n\u003c/p\u003e\n\n## Installation\n\n### Prerequisites\n\n- Flutter 3.x\n- Android SDK\n- Android device or emulator\n\n### Build \u0026 Run\n\n```bash\n# Get dependencies\nflutter pub get\n\n# Generate localizations\nflutter gen-l10n\n\n# Build options (via Makefile)\nmake debug          # x86_64 only (68MB) - for emulator\nmake release        # arm64 only (19MB) - for phones\nmake install        # Build release + install on device\nmake install-debug  # Build debug + install on emulator\n```\n\n### Install Widget\n\n1. Install the app on your device\n2. Open the app and let it load weather data\n3. Long-press on home screen → Widgets\n4. Find \"Meteograph\" and drag to home screen\n5. Tap widget to refresh data\n\n## Project Structure\n\n```\nlib/\n├── main.dart                     # App entry point, edge-to-edge setup\n├── generated/version.dart        # Generated git version info (gitignored)\n├── l10n/                         # Localization files (36 languages)\n│   ├── app_en.arb                # English (template)\n│   └── app_*.arb                 # ar, be, bg, bn, bs, cs, da, de, el, es,\n│                                 # fi, fr, hi, hr, is, it, ja, jv, ka, ko,\n│                                 # mk, nl, no, pa, pl, pt, ro, sk, sq, sv,\n│                                 # ta, tr, uk, vi, zh\n├── screens/\n│   └── home_screen.dart          # Main app screen (both chart panels)\n├── services/\n│   ├── location_service.dart     # GPS + city search + reverse geocoding\n│   ├── widget_service.dart       # Home widget updates via home_widget\n│   ├── native_svg_service.dart   # Method channel to Kotlin (SVG / weather / cache)\n│   ├── units_service.dart        # Temperature unit and 12/24h logic\n│   └── material_you_service.dart # Material You color pass-through\n├── theme/\n│   └── app_theme.dart            # Colors, themes, Material You mapping\n└── widgets/\n    └── native_svg_chart_view.dart # PlatformView wrapper for native SVG\n\nandroid/app/src/main/kotlin/.../\n├── MainActivity.kt                   # Flutter activity + method channel\n├── MeteogramApplication.kt           # Receiver registration, alarm schedule\n├── MeteogramWidgetProvider.kt        # Base widget (48h) — shared logic\n├── MeteogramWeeklyWidgetProvider.kt  # 7-day variant (extends base)\n├── WidgetEventReceiver.kt            # Locale / timezone / network receiver\n├── WidgetAlarmScheduler.kt           # 15-min inexact AlarmManager\n├── WidgetAlarmReceiver.kt            # Alarm broadcast handler\n├── BootCompletedReceiver.kt          # Refresh on device boot\n├── WidgetUtils.kt                    # Shared widget helpers\n├── WidgetChartColors.kt              # Material You color resolver\n├── WeatherUpdateWorker.kt            # WorkManager periodic refresh (~30 min)\n├── WeatherFetcher.kt                 # Native HTTP client for Open-Meteo\n├── WeatherDataParser.kt              # Cached-weather parser + chart views\n├── SvgChartGenerator.kt              # Native SVG generator (single source of truth)\n├── MaterialYouColorExtractor.kt      # Dynamic color extraction\n├── MaterialYouColorWorker.kt         # Background color updates\n├── SvgChartPlatformView.kt           # In-app native SVG rendering\n└── SvgChartViewFactory.kt            # PlatformView factory\n\nandroid/app/src/main/res/\n├── layout/meteogram_widget.xml              # 48h widget layout\n├── layout/meteogram_widget_weekly.xml       # 7-day widget layout\n├── xml/meteogram_widget_info.xml\n├── xml/meteogram_widget_weekly_info.xml\n└── drawable/widget_background.xml\n```\n\n## API\n\nUses [Open-Meteo](https://open-meteo.com/) free APIs (no API key required):\n\n### Weather Forecast\n```\nGET https://api.open-meteo.com/v1/forecast\n  ?latitude={lat}\n  \u0026longitude={lon}\n  \u0026hourly=temperature_2m,precipitation,cloud_cover\n  \u0026timezone=UTC\n  \u0026past_hours=32\n  \u0026forecast_days=7\n```\n\nThe 32-hour past window keeps the weekly chart's \"now\" line at the same\nfraction of width as the 48-hour chart. The 48-hour chart slices a smaller\nwindow (6h past + 46h future) from the same cache.\n\nReturns hourly data for:\n- `temperature_2m` — temperature in Celsius\n- `precipitation` — rain/snow in mm\n- `cloud_cover` — cloud coverage percentage (0-100)\n\nDaylight intensity is computed locally from cloud cover and solar position.\n\n### City Search (Geocoding)\n```\nGET https://geocoding-api.open-meteo.com/v1/search\n  ?name={query}\n  \u0026count=8\n  \u0026language={locale}\n```\n\nThe `language` parameter uses the user's current locale so results come\nback in their preferred language.\n\n## Widget Technical Details\n\n### Android Widget\n\nThe home screen widgets use:\n- `HomeWidgetProvider` from the home_widget package\n- `RemoteViews` for native Android widget rendering\n- SVG chart generated in Kotlin (`SvgChartGenerator.kt`) and rasterised via AndroidSVG\n- AlarmManager (~15 min inexact), WorkManager (~30 min with network constraint),\n  and BOOT_COMPLETED for reliable background refresh\n- Event receivers for unlock / network / locale / timezone changes\n\n**RemoteViews Limitations:**\n- Only supports: TextView, ImageView, LinearLayout, RelativeLayout, FrameLayout\n- Does NOT support: View, Space, custom views\n\n### Data Flow\n\n1. **Foreground**: `home_screen.dart` → `NativeSvgService.fetchWeather()` →\n   Kotlin `WeatherFetcher` pulls from Open-Meteo → caches to SharedPreferences\n2. **SVG generation**: `SvgChartGenerator.kt` reads the cache and produces an\n   SVG string — single source of truth used by both the in-app chart and both widgets\n3. **In-app**: SVG rendered via native PlatformView (AndroidSVG)\n4. **Widget**: SVG rasterised to a bitmap and shown in an ImageView\n5. **Background**: AlarmManager / WorkManager / BOOT_COMPLETED / event receivers\n   trigger a native refresh + widget re-render, Flutter engine stays off\n\n## Customization\n\n### Colors\n\nEdit `lib/theme/app_theme.dart` for the in-app UI and\n`android/app/src/main/kotlin/.../SvgChartGenerator.kt` for the chart itself\n(`SvgChartColors.light` / `SvgChartColors.dark`). Example from the Dart side:\n\n```dart\nstatic const light = MeteogramColors(\n  temperatureLine: Color(0xFFFF6B6B),    // Coral red\n  precipitationBar: Color(0xFF1A9D92),   // Deeper teal (legibility on white)\n  daylightBar: Color(0xFFFF8F00),        // Dark amber\n  nowIndicator: Color(0xFFFFE66D),       // Golden yellow\n  // ...\n);\n```\n\n### Widget Background\n\nEdit `android/app/src/main/res/drawable/widget_background.xml`:\n\n```xml\n\u003cgradient\n    android:startColor=\"#BA1B2838\"\n    android:endColor=\"#BA0D1B2A\"\n    android:angle=\"135\" /\u003e\n\u003ccorners android:radius=\"24dp\" /\u003e\n```\n\n## Adding Languages\n\n1. Create `lib/l10n/app_XX.arb` (copy from app_en.arb)\n2. Translate all strings\n3. Run `flutter gen-l10n`\n\nSupported locales are auto-detected from ARB files.\n\n## Dependencies\n\n| Package | Purpose |\n|---------|---------|\n| home_widget | Android/iOS widget support |\n| geolocator | GPS location |\n| geocoding | Reverse geocoding (city names) |\n| http | API requests |\n| path_provider | File storage |\n| shared_preferences | Settings storage |\n| intl | Locale-aware formatting |\n\nMaterial You theming uses native Android color extraction (`MaterialYouColorExtractor.kt`).\n\n## License\n\nBusiness Source License 1.1 - see [LICENSE](LICENSE)\n\n- Free for non-commercial and personal use\n- Commercial use requires a license\n- Converts to MIT on 2029-01-01\n\n## Contributing\n\nContributions welcome! Please read the existing code style and test your changes.\n\n## Acknowledgments\n\n- Weather data: [Open-Meteo](https://open-meteo.com/)\n- Widget support: [home_widget](https://pub.dev/packages/home_widget)\n- SVG rendering: [AndroidSVG](https://bigbadaboom.github.io/androidsvg/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimbortnik%2Fwidget","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimbortnik%2Fwidget","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimbortnik%2Fwidget/lists"}