Compare commits

...
2300 Commits
Author SHA1 Message Date
pranshulgg 206a8ab23a update changelog 2026-10-17 16:24:48 +05:30
pranshulgg 042f675ac8 fix location not found crashes 2026-10-17 16:23:33 +05:30
pranshulgg cfff16c57d fix location null crashes 2026-10-17 16:18:38 +05:30
pranshulgg 5f698cab75 fix missing placeholder 2026-10-17 10:04:57 +05:30
pranshulgg 9be4c7eab7 update changelog 2026-10-17 09:27:51 +05:30
Pranshul b196ed6799 Merge pull request #1209 from PranshulGG/l10n_main
New Crowdin updates
2026-10-17 08:33:49 +05:30
pranshulgg 3654d8d630 clean up comments and variable names 2026-10-17 08:33:33 +05:30
pranshulgg 0297ba99bc remove notification sound #1211 2026-10-17 08:26:41 +05:30
Pranshul d30f9b8a66 Merge pull request #1203 from GaijinSystems/fix/eccc-daily-missing-today
ECCC: keep today in daily forecast after its daytime period ends
2026-10-16 20:02:40 +05:30
Pranshul dfa6d89aba New translations strings.xml (Lithuanian)
[ci skip]
2026-10-16 19:29:07 +05:30
Matthew Fisher 1e1b8b2cab ECCC: keep today in daily forecast after its daytime period ends
ECCC drops "Today" once it has passed, so in the evening the forecast
starts with "Tonight". The mapper paired day and night periods by
position, so after an evening refresh:
- today disappeared from the daily list and daily[0] became tomorrow
  (hourly icons fell back to day icons until midnight, and the
  sun/moon blocks and max/min showed tomorrow)
- every day's low came from the previous night
- getMoonTimings added today in front, shifting moon times by a day

Pair day and night periods by date instead, and keep today with only
its night period. A night period left over from yesterday is dropped.
Today's high is the highest of today's observed temperatures (ECCC's
pastHourly), the remaining hourly forecast for today and the current
temperature. A period whose date can't be parsed is skipped, so one
bad entry no longer fails the whole forecast.
2026-10-16 08:09:38 -05:00
pranshulgg f271d32ed9 fix forecast dates around new year #1202 2026-10-16 13:25:24 +05:30
Pranshul cde9f5c55b New translations strings.xml (Ukrainian)
[ci skip]
2026-10-15 22:07:12 +05:30
Pranshul 86dbe0f029 Merge pull request #1197 from PranshulGG/l10n_main
New Crowdin updates
2026-10-13 21:03:23 +05:30
Pranshul 027ab2b18d Merge pull request #1200 from GaijinSystems/fix/nws-daily-missing-today
NWS: keep today in daily forecast after its daytime period ends
2026-10-13 21:01:51 +05:30
pranshulgg 402843a93a add option to disable new version available message 2026-10-13 21:01:00 +05:30
pranshulgg 7f21132013 add option to disable new version available message 2026-10-13 20:57:41 +05:30
pranshulgg f91d9792ce Fix missing return statements in cache resolvers when API key is missing 2026-10-13 19:30:27 +05:30
Matthew Fisher f330a33202 NWS: keep today in daily forecast after its daytime period ends
NWS drops a day's daytime period once it has passed, so in the evening
the forecast starts with "Tonight". The daily list was built from
daytime periods only, so today disappeared from it and daily[0] became
tomorrow. Tonight's hourly icons then fell back to day icons, and the
sun/moon blocks and max/min showed tomorrow's values.

Group periods by local day and use the daytime period, falling back to
the night period for a day without one (today or later only, so a stale
forecast doesn't bring back yesterday).

Fixes #1199
2026-10-13 08:33:36 -05:00
Pranshul 996549b3bc New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-10-13 14:50:10 +05:30
pranshulgg 68656c02a1 bump version 2026-10-12 20:31:30 +05:30
pranshulgg 260cd86527 custom date format closes #1142 2026-10-12 12:16:29 +05:30
Pranshul 7f83896f4a New translations strings.xml (Hebrew)
[ci skip]
2026-10-11 23:00:10 +05:30
pranshulgg aef3869891 Fix OpenWeather API key parsing when missing '&' suffix 2026-10-11 21:56:33 +05:30
pranshulgg 22d51ee63a update comment 2026-10-11 21:34:58 +05:30
pranshulgg b08ea96207 add one call api 2026-10-11 21:27:03 +05:30
pranshulgg 26c535aab3 Inject OpenWeatherOneCallApi into OpenWeatherRepository 2026-10-11 21:19:22 +05:30
pranshulgg 1d3c64ee79 fix suffix 2026-10-11 21:04:14 +05:30
pranshulgg 6bfd46a438 support openweather One Call 4.0 closes #1119 2026-10-11 19:57:45 +05:30
pranshulgg 12ff63f518 support openweather One Call 4.0 #1119 2026-10-11 18:36:16 +05:30
Pranshul ce386c7036 New translations strings.xml (Indonesian)
[ci skip]
2026-10-11 16:37:47 +05:30
Pranshul 04fa01f093 Merge pull request #1195 from PranshulGG/l10n_main
New Crowdin updates
2026-10-11 10:02:51 +05:30
Pranshul f02f68da81 New translations strings.xml (Turkish)
[ci skip]
2026-10-10 23:54:24 +05:30
Pranshul cf2d9a8557 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-10-10 17:41:39 +05:30
Pranshul 1c6096108f New translations strings.xml (Serbian (Latin))
[ci skip]
2026-10-10 17:41:38 +05:30
Pranshul 0f37309dd2 New translations strings.xml (Norwegian Bokmal)
[ci skip]
2026-10-10 17:41:36 +05:30
Pranshul 32b1d3d94f New translations strings.xml (Filipino)
[ci skip]
2026-10-10 17:41:35 +05:30
Pranshul 501955817c New translations strings.xml (Azerbaijani)
[ci skip]
2026-10-10 17:41:34 +05:30
Pranshul 97de9412a9 New translations strings.xml (Kazakh)
[ci skip]
2026-10-10 17:41:32 +05:30
Pranshul c8cd37c9bc New translations strings.xml (Norwegian Nynorsk)
[ci skip]
2026-10-10 17:41:31 +05:30
Pranshul ba6f293017 New translations strings.xml (Thai)
[ci skip]
2026-10-10 17:41:29 +05:30
Pranshul 548127fa2f New translations strings.xml (Persian)
[ci skip]
2026-10-10 17:41:28 +05:30
Pranshul 387f945311 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-10-10 17:41:27 +05:30
Pranshul 17203bdf7a New translations strings.xml (Vietnamese)
[ci skip]
2026-10-10 17:41:25 +05:30
Pranshul 36be536aff New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-10-10 17:41:24 +05:30
Pranshul 3f91b16feb New translations strings.xml (Slovenian)
[ci skip]
2026-10-10 17:41:23 +05:30
Pranshul 3b0370b48c New translations strings.xml (Portuguese)
[ci skip]
2026-10-10 17:41:21 +05:30
Pranshul ee64dedab2 New translations strings.xml (Dutch)
[ci skip]
2026-10-10 17:41:20 +05:30
Pranshul a2cd0500f9 New translations strings.xml (Korean)
[ci skip]
2026-10-10 17:41:19 +05:30
Pranshul dfedb104a9 New translations strings.xml (Japanese)
[ci skip]
2026-10-10 17:41:17 +05:30
Pranshul 33c54ecbfb New translations strings.xml (Italian)
[ci skip]
2026-10-10 17:41:16 +05:30
Pranshul 893ac8beaa New translations strings.xml (Hungarian)
[ci skip]
2026-10-10 17:41:15 +05:30
Pranshul abc4c30151 New translations strings.xml (German)
[ci skip]
2026-10-10 17:41:13 +05:30
Pranshul f651e34a25 New translations strings.xml (Catalan)
[ci skip]
2026-10-10 17:41:12 +05:30
Pranshul 65b2020412 New translations strings.xml (Bulgarian)
[ci skip]
2026-10-10 17:41:10 +05:30
Pranshul c700b649b9 New translations strings.xml (Spanish)
[ci skip]
2026-10-10 17:41:09 +05:30
Pranshul 43f069d904 New translations strings.xml (Romanian)
[ci skip]
2026-10-10 17:41:08 +05:30
Pranshul 6552b9721e New translations strings.xml (Indonesian)
[ci skip]
2026-10-10 17:41:07 +05:30
Pranshul ed9400d2b7 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-10-10 17:41:05 +05:30
Pranshul 63f029be75 New translations strings.xml (Ukrainian)
[ci skip]
2026-10-10 17:41:04 +05:30
Pranshul 8045d6340a New translations strings.xml (Turkish)
[ci skip]
2026-10-10 17:41:02 +05:30
Pranshul c3edf51fb8 New translations strings.xml (Swedish)
[ci skip]
2026-10-10 17:41:01 +05:30
Pranshul 38b0586556 New translations strings.xml (Russian)
[ci skip]
2026-10-10 17:41:00 +05:30
Pranshul 4fa749ebb5 New translations strings.xml (Polish)
[ci skip]
2026-10-10 17:40:58 +05:30
Pranshul 43bf77fe1f New translations strings.xml (Lithuanian)
[ci skip]
2026-10-10 17:40:56 +05:30
Pranshul 15c011b621 New translations strings.xml (Hebrew)
[ci skip]
2026-10-10 17:40:55 +05:30
Pranshul 74f81d2886 New translations strings.xml (Finnish)
[ci skip]
2026-10-10 17:40:53 +05:30
Pranshul 1a8705cac1 New translations strings.xml (Czech)
[ci skip]
2026-10-10 17:40:52 +05:30
Pranshul 899fff4974 New translations strings.xml (French)
[ci skip]
2026-10-10 17:40:51 +05:30
Pranshul d20283bf28 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-10-10 17:40:49 +05:30
Pranshul f4f0abbff9 New translations strings.xml (Greek)
[ci skip]
2026-10-10 17:40:48 +05:30
pranshulgg adedb4631d comments 2026-10-10 11:54:44 +05:30
pranshulgg 9c4708c24a change req code 2026-10-10 11:53:03 +05:30
Pranshul ca31292a60 Merge pull request #1157 from reveler-hub/feature/meteofor-ukraine-source
Add Meteofor (Ukraine) weather source
2026-10-10 11:51:50 +05:30
Pranshul 89c22e23a0 Merge pull request #1192 from PranshulGG/l10n_main
New Crowdin updates
2026-10-10 11:08:10 +05:30
pranshulgg cf4cd505f8 open calendar app 2026-10-10 11:04:12 +05:30
pranshulgg 3d8d2f1450 added weather alert notifications closes #316 2026-10-08 10:15:29 +05:30
Pranshul 8cd7bd07a1 New translations strings.xml (Hebrew)
[ci skip]
2026-10-08 02:44:10 +05:30
pranshulgg 4cc69b43c3 alert notification #316 2026-10-07 21:11:58 +05:30
Pranshul 4f1ec0a295 New translations strings.xml (Turkish)
[ci skip]
2026-10-07 19:59:13 +05:30
Pranshul 19ff66cdec Merge pull request #1191 from PranshulGG/l10n_main
New Crowdin updates
2026-10-06 16:48:54 +05:30
Pranshul 64c253b39f New translations strings.xml (Swedish)
[ci skip]
2026-10-06 15:09:04 +05:30
pranshulgg ed3409ac22 Simplify repository lookup in SourceRepositoryProvider 2026-10-04 16:43:55 +05:30
pranshulgg 6f1bbdf30e add MOENV #1177 @reveler-hub 2026-10-04 11:25:02 +05:30
Pranshul ae85de71f3 Merge pull request #1188 from reveler-hub/fix/gismeteo-location-lookup-param
Fix Gismeteo location lookup sending wrong query parameter
2026-10-03 09:01:26 +05:30
reveler-hub 66f5fb0241 Fix Gismeteo location lookup sending wrong query parameter (#1187)
GismeteoApi.fetchLocations() sent the longitude as "lon", but
Gismeteo's own API expects "lng" and silently ignores unrecognized
parameters. The server fell back to a longitude near 0deg, so the
nearest-city lookup matched locations along the Greenwich meridian
instead of the real coordinates - e.g. a Volgograd, Russia location
resolving to Normandy, France. Since the resolved city ID gets
cached per-location after the first lookup, this mismatch was
permanent until the location was deleted and re-added.

Verified live: before the fix, querying Gismeteo's endpoint for
Volgograd's coordinates returned French cities; after renaming the
parameter, it correctly returns Volgograd and nearby Volgograd
Oblast settlements. Confirmed in-app on an AVD with mock GPS set to
Volgograd - weather source set to Gismeteo now resolves and fetches
successfully for a real nearby Russian city instead of failing
silently into the wrong country.
2026-10-03 15:53:19 +13:00
Pranshul 08e741823d Merge pull request #1183 from PranshulGG/l10n_main
New Crowdin updates
2026-10-02 19:15:57 +05:30
Pranshul 66cb039232 Merge pull request #1186 from nikiosna/fix/smhi-coordinate-precision
Fix SMHI 404 for coordinates with more than 6 decimals
2026-10-02 19:14:17 +05:30
pranshulgg 7a2a101a2e add MOENV 2026-10-02 19:13:59 +05:30
Pranshul efca511021 New translations strings.xml (Ukrainian)
[ci skip]
2026-10-02 18:58:01 +05:30
nikiosnaandClaude Opus 5.5 56908af4ef Fix SMHI 404 for coordinates with more than 6 decimals
The SMHI snow1g point endpoint returns HTTP 404 when latitude or
longitude has more than 6 decimal places. GPS locations usually have
more, so the request failed and the app showed "Network not available".

Format the coordinates with 4 decimals (~10 m, plenty for the 2.5 km
grid) using Locale.ROOT so the decimal separator is always a dot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:10:14 +02:00
Pranshul 4d0da91355 New translations strings.xml (Swedish)
[ci skip]
2026-09-29 18:09:43 +05:30
Pranshul ffc6ffa5e8 New translations strings.xml (Indonesian)
[ci skip]
2026-09-29 03:12:53 +05:30
Pranshul 4e781a44af New translations strings.xml (Greek)
[ci skip]
2026-09-29 03:12:51 +05:30
Pranshul 8bda1ce3e3 New translations strings.xml (Finnish)
[ci skip]
2026-09-28 20:24:01 +05:30
Pranshul adbcffead4 Merge pull request #1180 from PranshulGG/l10n_main
New Crowdin updates
2026-09-28 19:34:27 +05:30
Pranshul 5111d9d9f0 New translations strings.xml (Polish)
[ci skip]
2026-09-27 22:16:20 +05:30
Pranshul 0c625daa33 New translations strings.xml (Swedish)
[ci skip]
2026-09-26 23:27:29 +05:30
Pranshul b14e644fcc New translations strings.xml (Lithuanian)
[ci skip]
2026-09-26 23:27:27 +05:30
Pranshul 73bc232e91 New translations strings.xml (Russian)
[ci skip]
2026-09-26 17:07:16 +05:30
Pranshul 81eb54bad7 New translations strings.xml (Finnish)
[ci skip]
2026-09-26 17:07:15 +05:30
Pranshul 815137eb02 New translations strings.xml (French)
[ci skip]
2026-09-26 17:07:14 +05:30
Pranshul e578bae8a1 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-09-26 17:07:12 +05:30
Pranshul 53e8d8f1ef New translations strings.xml (Chinese Simplified)
[ci skip]
2026-09-26 10:58:02 +05:30
pranshulgg 9a69c4cce6 Fix alert API key lookup using the wrong source 2026-09-26 10:53:16 +05:30
Pranshul 136f4f37a0 Merge pull request #1156 from PranshulGG/l10n_main
New Crowdin updates
2026-09-26 10:52:17 +05:30
Pranshul 10509d8427 Merge pull request #1178 from reveler-hub/fix/airquality-key-lookup
Fix air-quality API key lookup using the wrong source
2026-09-26 10:51:50 +05:30
pranshulgg 910787b056 fix attribution 2026-09-26 10:03:30 +05:30
Pranshul 7cc4e643a4 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-09-26 04:26:59 +05:30
Pranshul cf0ca64199 New translations strings.xml (French)
[ci skip]
2026-09-26 04:26:58 +05:30
Pranshul fac5fe2c59 New translations strings.xml (Catalan)
[ci skip]
2026-09-26 04:26:56 +05:30
Pranshul e7e94d0390 New translations strings.xml (Norwegian Bokmal)
[ci skip]
2026-09-25 22:08:23 +05:30
Pranshul 78ae8da2a8 New translations strings.xml (Azerbaijani)
[ci skip]
2026-09-25 22:08:21 +05:30
Pranshul 469acf95c3 New translations strings.xml (Kazakh)
[ci skip]
2026-09-25 22:08:19 +05:30
Pranshul 8b7564d0fb New translations strings.xml (Norwegian Nynorsk)
[ci skip]
2026-09-25 22:08:17 +05:30
Pranshul 9627cefdd1 New translations strings.xml (Thai)
[ci skip]
2026-09-25 22:08:16 +05:30
Pranshul 5ac3c511cd New translations strings.xml (Persian)
[ci skip]
2026-09-25 22:08:14 +05:30
Pranshul 9a51fec33b New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-09-25 22:08:13 +05:30
Pranshul fcc52ecb5e New translations strings.xml (Filipino)
[ci skip]
2026-09-25 22:08:11 +05:30
Pranshul e7097f081b New translations strings.xml (Serbian (Latin))
[ci skip]
2026-09-25 22:08:10 +05:30
Pranshul 94951173d0 New translations strings.xml (Indonesian)
[ci skip]
2026-09-25 22:08:08 +05:30
Pranshul ae06a0a827 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-09-25 22:08:07 +05:30
Pranshul b9a0cb7d54 New translations strings.xml (Vietnamese)
[ci skip]
2026-09-25 22:08:04 +05:30
Pranshul c20f581c41 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-09-25 22:08:03 +05:30
Pranshul 48314baa0a New translations strings.xml (Ukrainian)
[ci skip]
2026-09-25 22:08:01 +05:30
Pranshul 06ffe45167 New translations strings.xml (Turkish)
[ci skip]
2026-09-25 22:07:59 +05:30
Pranshul 9d74fbbeef New translations strings.xml (Swedish)
[ci skip]
2026-09-25 22:07:57 +05:30
Pranshul 7819fa5323 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-09-25 22:07:55 +05:30
Pranshul ad3531ad33 New translations strings.xml (Slovenian)
[ci skip]
2026-09-25 22:07:54 +05:30
Pranshul 0736a4e9e8 New translations strings.xml (Russian)
[ci skip]
2026-09-25 22:07:52 +05:30
Pranshul 5953f8ffd5 New translations strings.xml (Portuguese)
[ci skip]
2026-09-25 22:07:50 +05:30
Pranshul 0d14513648 New translations strings.xml (Polish)
[ci skip]
2026-09-25 22:07:49 +05:30
Pranshul 83fb2f2911 New translations strings.xml (Dutch)
[ci skip]
2026-09-25 22:07:47 +05:30
Pranshul a09ec9e735 New translations strings.xml (Lithuanian)
[ci skip]
2026-09-25 22:07:45 +05:30
Pranshul bbfafbfdb9 New translations strings.xml (Korean)
[ci skip]
2026-09-25 22:07:44 +05:30
Pranshul 25c5426b4e New translations strings.xml (Japanese)
[ci skip]
2026-09-25 22:07:42 +05:30
Pranshul cebac4681d New translations strings.xml (Italian)
[ci skip]
2026-09-25 22:07:40 +05:30
Pranshul 9304fd4eea New translations strings.xml (Hungarian)
[ci skip]
2026-09-25 22:07:39 +05:30
Pranshul 4299d0e9b4 New translations strings.xml (Hebrew)
[ci skip]
2026-09-25 22:07:37 +05:30
Pranshul a12eb90d14 New translations strings.xml (Finnish)
[ci skip]
2026-09-25 22:07:36 +05:30
Pranshul b3a4dc4bc2 New translations strings.xml (German)
[ci skip]
2026-09-25 22:07:34 +05:30
Pranshul 8cd290105f New translations strings.xml (Czech)
[ci skip]
2026-09-25 22:07:32 +05:30
Pranshul 56251ad992 New translations strings.xml (Bulgarian)
[ci skip]
2026-09-25 22:07:30 +05:30
Pranshul abcb1b460f New translations strings.xml (Spanish)
[ci skip]
2026-09-25 22:07:27 +05:30
Pranshul acd8cfd24f New translations strings.xml (French)
[ci skip]
2026-09-25 22:07:26 +05:30
Pranshul 145809a62c New translations strings.xml (Romanian)
[ci skip]
2026-09-25 22:07:24 +05:30
Pranshul 4e05961df8 New translations strings.xml (Catalan)
[ci skip]
2026-09-25 22:07:23 +05:30
Pranshul ee41bb0380 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-09-25 22:07:21 +05:30
Pranshul bc3e17d8b6 New translations strings.xml (Greek)
[ci skip]
2026-09-25 22:07:19 +05:30
reveler-hub 17ef87f3dd Look up the air-quality source's own API key, not the weather source's
locationRequiresApiKey and the key lookup both used location.source (the
weather source) instead of location.airQualitySource. Every air-quality
source today happens to share a source with its weather counterpart, so
this never surfaced, but it breaks - and currently crashes via !! in
OpenWeatherRepository - whenever they differ and the air-quality source
needs a key the weather source doesn't.
2026-09-26 04:19:06 +12:00
pranshulgg 02ebad26ed add kmi closes #997 closes #381 closes #1122 2026-09-25 21:18:41 +05:30
pranshulgg 40c48a3330 update read me 2026-09-25 20:57:02 +05:30
pranshulgg a550ccee77 add kmi api, repo, and json # 2026-09-24 21:25:50 +05:30
Pranshul c52d61126d New translations strings.xml (Indonesian)
[ci skip]
2026-09-24 12:22:30 +05:30
Pranshul e782c84659 New translations strings.xml (Catalan)
[ci skip]
2026-09-24 06:23:14 +05:30
Pranshul f309a6a1f7 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-09-24 00:24:06 +05:30
Pranshul d191b84956 New translations strings.xml (Russian)
[ci skip]
2026-09-24 00:24:05 +05:30
Pranshul e011dd92ea New translations strings.xml (Korean)
[ci skip]
2026-09-24 00:24:03 +05:30
pranshulgg 7ddeb9c271 add kmi api #997 2026-09-23 20:10:54 +05:30
Pranshul 7d5396626d New translations strings.xml (Chinese Simplified)
[ci skip]
2026-09-23 18:28:29 +05:30
Pranshul 6a874ff3d2 New translations strings.xml (Finnish)
[ci skip]
2026-09-23 18:28:27 +05:30
Pranshul 0e2deed274 New translations strings.xml (French)
[ci skip]
2026-09-23 18:28:26 +05:30
Pranshul f75e1b484e New translations strings.xml (Catalan)
[ci skip]
2026-09-23 18:28:24 +05:30
Pranshul ca13f75055 New translations strings.xml (Norwegian Bokmal)
[ci skip]
2026-09-23 12:34:36 +05:30
Pranshul 0cdeb42136 New translations strings.xml (Azerbaijani)
[ci skip]
2026-09-23 12:34:35 +05:30
Pranshul 7ecce86eba New translations strings.xml (Kazakh)
[ci skip]
2026-09-23 12:34:33 +05:30
Pranshul 9a02b5d149 New translations strings.xml (Norwegian Nynorsk)
[ci skip]
2026-09-23 12:34:31 +05:30
Pranshul 02f55cc56c New translations strings.xml (Thai)
[ci skip]
2026-09-23 12:34:29 +05:30
Pranshul 2c512574c0 New translations strings.xml (Persian)
[ci skip]
2026-09-23 12:34:28 +05:30
Pranshul 4bdcdf1107 New translations strings.xml (Indonesian)
[ci skip]
2026-09-23 12:34:26 +05:30
Pranshul 32191bda80 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-09-23 12:34:24 +05:30
Pranshul 1b0021275d New translations strings.xml (Vietnamese)
[ci skip]
2026-09-23 12:34:23 +05:30
Pranshul 7a2c83517a New translations strings.xml (Chinese Simplified)
[ci skip]
2026-09-23 12:34:21 +05:30
Pranshul 8bff40ccb4 New translations strings.xml (Ukrainian)
[ci skip]
2026-09-23 12:34:19 +05:30
Pranshul cbdc5a902a New translations strings.xml (Turkish)
[ci skip]
2026-09-23 12:34:17 +05:30
Pranshul bd6fbf9bef New translations strings.xml (Swedish)
[ci skip]
2026-09-23 12:34:15 +05:30
Pranshul c31c60cbdc New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-09-23 12:34:13 +05:30
Pranshul 547c05114e New translations strings.xml (Slovenian)
[ci skip]
2026-09-23 12:34:11 +05:30
Pranshul 58e1b54ac2 New translations strings.xml (Russian)
[ci skip]
2026-09-23 12:34:08 +05:30
Pranshul c5803f299a New translations strings.xml (Portuguese)
[ci skip]
2026-09-23 12:34:07 +05:30
Pranshul 998b7aae7f New translations strings.xml (Polish)
[ci skip]
2026-09-23 12:34:04 +05:30
Pranshul c7612b0a8f New translations strings.xml (Dutch)
[ci skip]
2026-09-23 12:33:54 +05:30
Pranshul 6c0a6434af New translations strings.xml (Lithuanian)
[ci skip]
2026-09-23 12:33:43 +05:30
Pranshul 32b3e81842 New translations strings.xml (Korean)
[ci skip]
2026-09-23 12:33:21 +05:30
Pranshul e9a2cadab3 New translations strings.xml (Japanese)
[ci skip]
2026-09-23 12:33:06 +05:30
Pranshul 3c55d45baa New translations strings.xml (Italian)
[ci skip]
2026-09-23 12:32:53 +05:30
Pranshul e0795688a7 New translations strings.xml (Hungarian)
[ci skip]
2026-09-23 12:32:39 +05:30
Pranshul 534dba0971 New translations strings.xml (Hebrew)
[ci skip]
2026-09-23 12:32:25 +05:30
Pranshul 22a01314b3 New translations strings.xml (Finnish)
[ci skip]
2026-09-23 12:32:12 +05:30
Pranshul 05db53929b New translations strings.xml (German)
[ci skip]
2026-09-23 12:31:59 +05:30
Pranshul 9e0a0c7d3e New translations strings.xml (Czech)
[ci skip]
2026-09-23 12:31:48 +05:30
Pranshul 042caed47b New translations strings.xml (Bulgarian)
[ci skip]
2026-09-23 12:31:36 +05:30
Pranshul 03672e9d52 New translations strings.xml (Spanish)
[ci skip]
2026-09-23 12:31:23 +05:30
Pranshul 60b521c725 New translations strings.xml (French)
[ci skip]
2026-09-23 12:31:13 +05:30
Pranshul eaa296464d New translations strings.xml (Romanian)
[ci skip]
2026-09-23 12:31:04 +05:30
Pranshul be27ae93c4 New translations strings.xml (Catalan)
[ci skip]
2026-09-23 12:30:54 +05:30
Pranshul 653a6c672a New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-09-23 12:30:45 +05:30
Pranshul 5cf9a52766 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-09-23 12:30:40 +05:30
Pranshul ab37bfa083 New translations strings.xml (Greek)
[ci skip]
2026-09-23 12:30:37 +05:30
Pranshul f18d874cc2 New translations strings.xml (Filipino)
[ci skip]
2026-09-23 12:30:35 +05:30
Pranshul b353a4c6cd New translations strings.xml (Serbian (Latin))
[ci skip]
2026-09-23 12:30:34 +05:30
pranshulgg 50c16ded25 add country name to MGM source 2026-09-23 12:03:20 +05:30
pranshulgg 07da76f76a add attribution 2026-09-23 12:00:34 +05:30
pranshulgg 06b498f841 add mgm with alerts closes #1079 2026-09-23 11:57:51 +05:30
Pranshul 3c61ddc037 New translations strings.xml (Catalan)
[ci skip]
2026-09-23 01:04:56 +05:30
pranshulgg 197b6177e4 implement mgm source #1081 2026-09-22 20:37:41 +05:30
Pranshul 488034eb9c New translations strings.xml (Catalan)
[ci skip]
2026-09-22 19:08:07 +05:30
pranshulgg aa6cd371bf add mgm alerts 2026-09-22 09:13:22 +05:30
Pranshul c5fb65408b New translations strings.xml (Filipino)
[ci skip]
2026-09-21 06:01:29 +05:30
Pranshul fd83a163f5 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-09-20 22:16:03 +05:30
pranshulgg 2606361bba add mgm 2026-09-20 19:43:24 +05:30
Pranshul c19e30f0db Merge pull request #1166 from fardog/fix-remove-weather1-max-size
fix: remove max width/height for "Weather 1" widget
2026-09-20 19:38:07 +05:30
Pranshul cff2be99e4 Merge pull request #1165 from reveler-hub/fix/metoffice-daily-precip-probability
fix: use the day precipitation probability for Met Office's daily max
2026-09-20 19:37:41 +05:30
Pranshul 783fe3c305 Merge pull request #1163 from fardog/fix-widget-null
fix: handle null temperature values in widget
2026-09-20 19:36:00 +05:30
Pranshul 8d1cb83dbb Merge pull request #1162 from fardog/fix-metoffice-temp
fix: correctly map met office temperature values
2026-09-20 19:35:41 +05:30
fardog fb90527fbf fix: remove max width/height for "Weather 1" widget
Allows setting the widget's max width/height as desired by the user.

Fixes #1164
2026-09-20 14:46:41 +01:00
Pranshul 62055559dc New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-09-20 16:00:39 +05:30
reveler-hub aa98be6c13 Use the day precipitation probability for Met Office's daily max
The daily max was computed over nightProbabilityOfPrecipitation twice, so
the day value from the API was never used. Adds dayProbabilityOfPrecipitation
to the daily JSON model and takes the max of day and night.
2026-09-20 18:05:18 +12:00
Pranshul 231c992b4f New translations strings.xml (Filipino)
[ci skip]
2026-09-20 09:31:39 +05:30
Pranshul e9977e2f71 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-09-19 22:10:43 +05:30
Pranshul 8c2c4314ed New translations strings.xml (Filipino)
[ci skip]
2026-09-19 22:10:41 +05:30
fardog 956163fe9f fix: handle null temperature values in widget 2026-09-19 17:17:48 +01:00
fardog d2c89da024 fix: correctly map met office temperature values 2026-09-19 16:46:30 +01:00
Pranshul b6ef35f80a New translations strings.xml (Filipino)
[ci skip]
2026-09-19 16:02:25 +05:30
Pranshul 7fe2201a63 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-09-19 16:02:23 +05:30
Pranshul 37ff2c6234 New translations strings.xml (Filipino)
[ci skip]
2026-09-19 09:50:54 +05:30
Pranshul 8e0aa56ad8 New translations strings.xml (Filipino)
[ci skip]
2026-09-19 03:55:05 +05:30
Pranshul 2fd30077fa Merge pull request #1158 from reveler-hub/fix/metoffice-api-key-link
Point Met Office's API key link to the right DataHub product
2026-09-18 21:54:38 +05:30
Pranshul 9716bcdbd9 New translations strings.xml (Greek)
[ci skip]
2026-09-18 21:51:59 +05:30
Pranshul f3e6143b7e New translations strings.xml (Filipino)
[ci skip]
2026-09-18 15:51:40 +05:30
reveler-hub 991f74a9f6 Split Met Office's signup link from its general displayLink
displayLink is also used for general 'about this source' info in
WeatherSourcesScreen and the current-source info sheet, so
overwriting it with the DataHub pricing page broke those. Adds a
separate signupLink field used only on the API Keys screen instead,
falling back to displayLink when unset.
2026-09-18 19:31:29 +12:00
Pranshul 644a83dd28 New translations strings.xml (Filipino)
[ci skip]
2026-09-18 08:49:39 +05:30
reveler-hub 2992fe5afb Add a note on the API key screen for which Met Office product to subscribe to 2026-09-18 10:51:46 +12:00
Pranshul 8d1f7434df New translations strings.xml (Filipino)
[ci skip]
2026-09-17 17:42:44 +05:30
reveler-hub f27563de27 Point Met Office's API key link to the right DataHub product
Closes #1155. The link shown above the API key field pointed to
Met Office's general public consumer site, not anywhere related to
getting an API key - a user trying to sign up from that link would
land on the wrong site entirely. Points to DataHub's Site Specific
product page instead, which is the actual product this app's
requests need (confirmed directly with the reporter - their key
started working once subscribed to "Site Specific").
2026-09-17 17:41:11 +12:00
Pranshul bf13576b05 New translations strings.xml (Filipino)
[ci skip]
2026-09-17 10:46:34 +05:30
reveler-hub c47325885b Add Meteofor (Ukraine) weather source
Meteofor is Gismeteo's Ukraine-facing rebrand (same company, same
backend - gismeteo.ua has redirected to meteofor.com since June 2023;
confirmed live that Gismeteo's own API uses the identical internal
city ID for Kyiv that Meteofor uses in its own URLs).

Reuses GismeteoRepository's existing fetch/parse logic as-is under
its own Source identity, so Ukraine gets an appropriately-branded
recommended source instead of "Gismeteo (Russia)". No new API
integration - just a new Source entry, country mapping, and a thin
repository that shares GismeteoApi and the existing XML parsing
helpers.

Closes #1114.

Live-tested on-device: added Kyiv, confirmed "Meteofor (Ukraine)"
shows under Recommended sources and auto-selects, verified real
fetched weather data (temperature/humidity/wind/condition) via
direct DB inspection. Note: during testing, the fetch only
succeeded with a VPN set to Ukraine - Gismeteo's backend appeared
to be rate-limiting/blocking requests from our regular testing IP.
2026-09-17 16:56:33 +12:00
Pranshul 387d022871 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-09-17 03:33:29 +05:30
pranshulgg f78a580bf8 bump version code 2026-09-16 20:14:45 +05:30
pranshulgg 9fb5ce964d bump version to 3.10.6 and add preference check for ongoing notification 2026-09-16 20:07:19 +05:30
pranshulgg d26882e137 update changelog 2026-09-16 14:45:36 +05:30
pranshulgg 8dd8ad1504 implement offline China geocoding and add widget reload button 2026-09-16 14:44:00 +05:30
pranshulgg af230b8970 add default location check for widgets and notifications 2026-09-16 12:50:57 +05:30
pranshulgg 8863b82317 add auto refresh capability for weather data 2026-09-16 12:25:44 +05:30
pranshulgg f3132a772e add platform-tools to android sdk setup 2026-09-16 10:06:53 +05:30
pranshulgg aab31a2809 update changelog 2026-09-16 10:02:27 +05:30
pranshulgg 75562186b9 add font and icon size customization to glance widget configuration 2026-09-16 09:42:00 +05:30
pranshulgg 191fe86e1e refactor notification weather mapper to use findMatchingHourly 2026-09-16 09:06:23 +05:30
pranshulgg 8c2296b602 fix widgets/notifications not updating 2026-09-16 08:58:40 +05:30
pranshulgg 3eb4c4c1f7 remove logs 2026-09-15 21:50:49 +05:30
Pranshul 92495ed55a Merge pull request #1152 from PranshulGG/l10n_main
New Crowdin updates
2026-09-15 21:38:30 +05:30
pranshulgg ae5129778e missing placeholder 2026-09-15 21:34:08 +05:30
pranshulgg 33a8dccd36 update notification setting title to next day forecast 2026-09-15 21:21:37 +05:30
pranshulgg 0475f86e46 update changelog 2026-09-15 21:05:15 +05:30
Pranshul 2c114f83e5 New translations strings.xml (Indonesian)
[ci skip]
2026-09-15 19:46:07 +05:30
pranshulgg 44286fd1ef remove unused background location permission 2026-09-15 15:28:10 +05:30
pranshulgg 79f7b42a3a refactor clock and date click handling using PendingIntents in views 2026-09-15 14:50:43 +05:30
pranshulgg 6ff7528b5e bump version 2026-09-15 13:38:37 +05:30
pranshulgg a09e044ab9 update changelog 2026-09-15 13:38:28 +05:30
pranshulgg 4990819f49 add content intent to ongoing and scheduled notifications 2026-09-15 13:25:12 +05:30
pranshulgg 0634439209 refactor weather blocks saving logic 2026-09-15 13:25:01 +05:30
Pranshul a1ecf07ed1 Merge pull request #1145 from PranshulGG/l10n_main
New Crowdin updates
2026-09-14 22:01:04 +05:30
pranshulgg 38579071f4 schema 2026-09-14 21:59:20 +05:30
pranshulgg cb095feeec use real-time instead of outdated saved timestamp closes #1088 2026-09-14 21:59:20 +05:30
Pranshul 32ac4f4ca2 Merge pull request #1134 from reveler-hub/fix/alerts-only-source-recommendation-bugs
Fix alerts-only country-recommended sources leaking into weather picker
2026-09-14 21:49:42 +05:30
Pranshul 177ade280f New translations strings.xml (Italian)
[ci skip]
2026-09-14 16:08:40 +05:30
Pranshul 30d8fb8bfb New translations strings.xml (Indonesian)
[ci skip]
2026-09-13 22:42:33 +05:30
Pranshul a615652a74 New translations strings.xml (Greek)
[ci skip]
2026-09-12 21:24:08 +05:30
Pranshul 29054b7ebd Merge pull request #1131 from FlammeGamer/gadgetbridge
add support for third-party gadgetbridge receivers
2026-09-12 10:18:12 +05:30
pranshulgg 5d73b6758c fixed unwanted errors 2026-09-11 21:17:14 +05:30
Pranshul 2cd5146b3b Merge pull request #1138 from reveler-hub/fix/pressure-hourly-rounding
Fix unrounded pressure values on hourly detail card
2026-09-11 20:59:50 +05:30
Pranshul 936565c5a6 Merge pull request #1103 from PranshulGG/l10n_main
New Crowdin updates
2026-09-11 20:59:34 +05:30
pranshulgg f7a2b00286 finalize refactor 2026-09-11 20:59:09 +05:30
Pranshul e63a7fef42 New translations strings.xml (Korean)
[ci skip]
2026-09-10 21:00:33 +05:30
Pranshul ca05f102ae New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-09-10 14:57:01 +05:30
Pranshul 9a652e32ab New translations strings.xml (Czech)
[ci skip]
2026-09-09 00:44:14 +05:30
pranshulgg 075aae0e8c refactor open weather 2026-09-08 19:44:16 +05:30
pranshulgg eea42ff074 add airquality layer 2026-09-08 19:26:53 +05:30
pranshulgg d8731ae768 finalize repositories 2026-09-08 15:04:32 +05:30
Pranshul 5c67123290 New translations strings.xml (Norwegian Nynorsk)
[ci skip]
2026-09-08 06:03:27 +05:30
Pranshul f0dc836631 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-09-08 00:03:01 +05:30
Pranshul e8db1e45c1 New translations strings.xml (Lithuanian)
[ci skip]
2026-09-08 00:02:59 +05:30
Pranshul 2721359394 New translations strings.xml (Norwegian Nynorsk)
[ci skip]
2026-09-07 18:05:13 +05:30
reveler-hub 3836e22c5a Fix pressure hourly card showing unrounded decimal values
Closes #1137. The hourly pressure detail card converted hPa to the
selected unit and called .toString() directly on the raw Double,
so non-hPa units (e.g. inHg, which multiplies by ~0.02953) rendered
long floating-point tails instead of a rounded value. Use
formatLocalizedNumber with 1 decimal place, matching the main
pressure block's existing formatting.
2026-09-07 16:55:33 +12:00
Pranshul db378e8efb New translations strings.xml (Greek)
[ci skip]
2026-09-06 19:29:57 +05:30
pranshulgg 81702b7a17 add additional data 2026-09-06 11:45:02 +05:30
Pranshul a8e844dec3 New translations strings.xml (Polish)
[ci skip]
2026-09-06 08:22:22 +05:30
Pranshul cfd606baa5 New translations strings.xml (Turkish)
[ci skip]
2026-09-06 02:21:48 +05:30
Pranshul cf8e9a52df New translations strings.xml (Russian)
[ci skip]
2026-09-05 20:09:56 +05:30
pranshulgg d2e65ef50a add capability layer and remove old implementation 2026-09-05 17:25:04 +05:30
Pranshul 99f332d661 New translations strings.xml (Norwegian Nynorsk)
[ci skip]
2026-09-05 05:41:33 +05:30
Pranshul 9330d02457 New translations strings.xml (Norwegian Bokmal)
[ci skip]
2026-09-04 23:25:33 +05:30
Pranshul fd42c54005 New translations strings.xml (Norwegian Nynorsk)
[ci skip]
2026-09-04 23:25:32 +05:30
Pranshul 7c39e9d402 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-09-04 23:25:31 +05:30
Pranshul e274bf8ee5 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-09-04 23:25:29 +05:30
Pranshul e3377907f4 New translations strings.xml (Filipino)
[ci skip]
2026-09-04 23:25:28 +05:30
Pranshul a834a13420 New translations strings.xml (Azerbaijani)
[ci skip]
2026-09-04 23:25:27 +05:30
Pranshul 8434131c45 New translations strings.xml (Kazakh)
[ci skip]
2026-09-04 23:25:25 +05:30
Pranshul 42efce2adc New translations strings.xml (Thai)
[ci skip]
2026-09-04 23:25:24 +05:30
Pranshul 2dac97769b New translations strings.xml (Persian)
[ci skip]
2026-09-04 23:25:23 +05:30
Pranshul 26b6a45b6a New translations strings.xml (Indonesian)
[ci skip]
2026-09-04 23:25:21 +05:30
Pranshul f16b713e81 New translations strings.xml (Vietnamese)
[ci skip]
2026-09-04 23:25:20 +05:30
Pranshul 4ae3a46cee New translations strings.xml (Chinese Traditional)
[ci skip]
2026-09-04 23:25:19 +05:30
Pranshul 10e7dde828 New translations strings.xml (Swedish)
[ci skip]
2026-09-04 23:25:17 +05:30
Pranshul 70deefc2dd New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-09-04 23:25:16 +05:30
Pranshul e4fea1dcca New translations strings.xml (Slovenian)
[ci skip]
2026-09-04 23:25:15 +05:30
Pranshul 4fe834091c New translations strings.xml (Korean)
[ci skip]
2026-09-04 23:25:13 +05:30
Pranshul b127b237e5 New translations strings.xml (Hungarian)
[ci skip]
2026-09-04 23:25:12 +05:30
Pranshul 5a62a9c598 New translations strings.xml (Greek)
[ci skip]
2026-09-04 23:25:11 +05:30
Pranshul 6820379008 New translations strings.xml (German)
[ci skip]
2026-09-04 23:25:09 +05:30
Pranshul c06e36e206 New translations strings.xml (Catalan)
[ci skip]
2026-09-04 23:25:08 +05:30
Pranshul 5611229508 New translations strings.xml (Bulgarian)
[ci skip]
2026-09-04 23:25:06 +05:30
Pranshul 25a32308b1 New translations strings.xml (Romanian)
[ci skip]
2026-09-04 23:25:05 +05:30
Pranshul c086382c5e New translations strings.xml (Polish)
[ci skip]
2026-09-04 23:25:04 +05:30
Pranshul fa901ff60a New translations strings.xml (Italian)
[ci skip]
2026-09-04 23:25:02 +05:30
Pranshul 097af8d0bb New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-09-04 23:25:01 +05:30
Pranshul d3eeaa5e21 New translations strings.xml (Lithuanian)
[ci skip]
2026-09-04 23:25:00 +05:30
Pranshul 07ee9a04d5 New translations strings.xml (French)
[ci skip]
2026-09-04 23:24:58 +05:30
Pranshul ae21b74622 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-09-04 23:24:57 +05:30
Pranshul c057edc390 New translations strings.xml (Ukrainian)
[ci skip]
2026-09-04 23:24:56 +05:30
Pranshul 790937dc43 New translations strings.xml (Turkish)
[ci skip]
2026-09-04 23:24:54 +05:30
Pranshul 7dff6feef6 New translations strings.xml (Russian)
[ci skip]
2026-09-04 23:24:53 +05:30
Pranshul e19290a517 New translations strings.xml (Portuguese)
[ci skip]
2026-09-04 23:24:52 +05:30
Pranshul 976d243e82 New translations strings.xml (Dutch)
[ci skip]
2026-09-04 23:24:50 +05:30
Pranshul 37b955cc38 New translations strings.xml (Japanese)
[ci skip]
2026-09-04 23:24:49 +05:30
Pranshul d516ba79d8 New translations strings.xml (Hebrew)
[ci skip]
2026-09-04 23:24:48 +05:30
Pranshul 835fa61eaa New translations strings.xml (Finnish)
[ci skip]
2026-09-04 23:24:47 +05:30
Pranshul 512530491f New translations strings.xml (Czech)
[ci skip]
2026-09-04 23:24:45 +05:30
Pranshul 8a0b5fd04d New translations strings.xml (Spanish)
[ci skip]
2026-09-04 23:24:44 +05:30
pranshulgg b37e772882 fix source changes 2026-09-04 21:10:18 +05:30
pranshulgg deff68c6c3 change result type 2026-09-04 20:46:14 +05:30
pranshulgg 8f303a8c55 add alert side refactor 2026-09-04 20:38:18 +05:30
pranshulgg 3186c11d6b refactor weather architecture and state management using managers and stores 2026-09-04 20:34:58 +05:30
pranshulgg 894f32cd14 refactor changes Ui side 2026-09-04 20:33:27 +05:30
pranshulgg df4e116564 refactor changes Ui side 2026-09-04 20:33:17 +05:30
pranshulgg e11459b9c9 remove repo 2026-09-04 20:31:41 +05:30
pranshulgg bba8768952 refactor sources to follow new layer 2026-09-04 20:00:24 +05:30
Pranshul d88c3e0cc2 New translations strings.xml (Korean)
[ci skip]
2026-09-04 17:28:18 +05:30
pranshulgg 8ca8ef7b96 add base repo layer 2026-09-04 16:38:51 +05:30
reveler-hub ee3db85233 Fix alerts-only country-recommended sources leaking into weather picker
WeatherSourcesForLocationSheet's recommendedSources list wasn't
filtered by Capability.WEATHER (unlike its globalSources list),
so an alerts-only source recommended for a country could appear,
and even get auto-selected, as a weather source. Every country's
recommended source has so far also been a weather source, so this
never surfaced until an alerts-only country-recommended source
existed.

Also make new-location alert-source selection fall back to the
country's recommended alerts source when the chosen weather source
isn't itself alerts-capable, instead of only pairing alerts when
the weather source happens to be self-paired.
2026-09-04 17:57:47 +12:00
Pranshul 4a39f5c02c New translations strings.xml (Japanese)
[ci skip]
2026-09-04 11:11:17 +05:30
Pranshul ef8cdb03d2 New translations strings.xml (Czech)
[ci skip]
2026-09-04 05:12:57 +05:30
Flamme Gamer 723eb741b4 add support for third-party gadgetbridge receivers 2026-09-03 21:18:32 +02:00
pranshulgg 466566433f add manager and pending request layer 2026-09-03 22:31:26 +05:30
pranshulgg d3e6a0273f refactor viewmodel 2026-09-03 22:30:32 +05:30
pranshulgg af14e4e440 add stores and managers 2026-09-02 21:33:27 +05:30
Pranshul feed0d847d New translations strings.xml (Finnish)
[ci skip]
2026-09-01 22:16:45 -07:00
Pranshul b2e61968e1 New translations strings.xml (Polish)
[ci skip]
2026-09-01 13:04:42 -07:00
pranshulgg b357572473 add workin managers/stores 2026-09-01 21:55:12 +05:30
Pranshul 145bea15ec New translations strings.xml (Catalan)
[ci skip]
2026-09-01 06:50:28 -07:00
Pranshul be301782cc New translations strings.xml (Polish)
[ci skip]
2026-09-01 06:50:27 -07:00
Pranshul bb9d723a24 New translations strings.xml (Catalan)
[ci skip]
2026-09-01 13:07:03 +05:30
Pranshul af2f127d78 New translations strings.xml (Russian)
[ci skip]
2026-09-01 01:58:21 +05:30
pranshulgg effa4f4a48 fix readme 2026-08-31 11:37:48 +05:30
pranshulgg 0d6bc73fdb improve readme links 2026-08-31 11:36:10 +05:30
pranshulgg ed437164af add play store link 2026-08-31 09:15:52 +05:30
pranshulgg aff6849557 remove comment 2026-08-31 09:03:07 +05:30
Pranshul 5dbbd73152 New translations strings.xml (Spanish)
[ci skip]
2026-08-30 17:22:33 +05:30
Pranshul 9aa6884356 New translations strings.xml (Greek)
[ci skip]
2026-08-29 19:44:14 +05:30
Pranshul b9a123626a New translations strings.xml (Ukrainian)
[ci skip]
2026-08-29 19:44:12 +05:30
Pranshul 2e35367ae9 New translations strings.xml (Vietnamese)
[ci skip]
2026-08-29 13:38:31 +05:30
PranshulGG 14cf35624c color adjustments 2026-08-29 12:37:48 +05:30
PranshulGG b22f3f3b3b add option to disable tablet layout closes #1111 2026-08-29 12:32:52 +05:30
PranshulGG 90ea14b88d add option to disable tablet layout closes #1111 2026-08-29 12:32:39 +05:30
PranshulGG df54f032c5 adjust column weights in TabletLayout and add fixed grid support to WeatherBlocks 2026-08-29 12:25:41 +05:30
Pranshul e325d2bd8e Merge pull request #1110 from reveler-hub/fix/weather-sources-none-entry
Exclude NONE placeholder from Weather Sources attribution list
2026-08-29 11:17:50 +05:30
Pranshul 350358c11f Merge branch 'main' into fix/weather-sources-none-entry
Signed-off-by: Pranshul <pranshul.devmain@gmail.com>
2026-08-29 11:17:14 +05:30
PranshulGG da083bd25d remove pr workflow 2026-08-29 11:14:37 +05:30
PranshulGG c6337a7d05 Fix "None" showing as source in the weather sources screen closes #1109 2026-08-29 11:13:06 +05:30
reveler-hub d782552a7c Exclude NONE placeholder from Weather Sources attribution list 2026-08-29 17:39:04 +12:00
PranshulGG c576b53666 add apk 2026-08-29 10:19:33 +05:30
PranshulGG 6bcd03b14e AnimatedContent scrollable 2026-08-29 10:12:48 +05:30
PranshulGG 8e6bb9d2c3 remove key from scrollState 2026-08-29 10:05:23 +05:30
PranshulGG cc5ee455ee add apk 2026-08-29 09:07:01 +05:30
PranshulGG c30149b84e Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-08-29 08:58:21 +05:30
PranshulGG 8f030ef45d fix scroll state 2026-08-29 08:56:59 +05:30
Pranshul 868d022f62 New translations strings.xml (Czech)
[ci skip]
2026-08-29 07:39:25 +05:30
Pranshul 9208364396 New translations strings.xml (German)
[ci skip]
2026-08-29 01:31:39 +05:30
Pranshul 421077a893 Merge pull request #1107 from RakshithBhat03/feature/air-quality-legend-1106
fix(air-quality): use rounded chips in the legend
2026-08-28 19:32:42 +05:30
Pranshul 26055e2ed0 New translations strings.xml (German)
[ci skip]
2026-08-28 19:08:38 +05:30
Pranshul 8f8c38c31c New translations strings.xml (French)
[ci skip]
2026-08-28 19:08:36 +05:30
Rakshith BhatandOpenAI GPT-5.6 Sol c103a20d67 match air quality legend to chip style
Co-authored-by: OpenAI GPT-5.6 Sol <noreply@openai.com>
2026-08-28 18:54:08 +05:30
PranshulGG 440fe23cb1 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-08-28 18:28:17 +05:30
PranshulGG 54cd8731a4 use map 2026-08-28 18:27:59 +05:30
PranshulGG 60a2451c04 fix moon timings closes #1105 2026-08-28 18:26:58 +05:30
PranshulGG b77dd5cfef fix moon timings closes #1105 2026-08-28 18:26:54 +05:30
Pranshul 6a0d12ca99 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-28 12:51:48 +05:30
Pranshul 50069d5bbf New translations strings.xml (Lithuanian)
[ci skip]
2026-08-28 12:51:46 +05:30
Pranshul cffa79e1a9 New translations strings.xml (Finnish)
[ci skip]
2026-08-28 12:51:45 +05:30
PranshulGG 4f25c0984e fix location services crash closes #1100 2026-08-28 11:48:26 +05:30
Pranshul f13804eee4 Merge pull request #1093 from PranshulGG/l10n_main
New Crowdin updates
2026-08-28 10:00:11 +05:30
Pranshul a8454b5f0f Merge pull request #1094 from VadosG/patch-1
Add missing comma in "EEE d MMMM"
2026-08-28 09:59:48 +05:30
Pranshul 501ab35af7 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-28 06:40:06 +05:30
VadosG aba3ee8eca Add missing comma in "EEE d MMMM"
Signed-off-by: VadosG <132702182+VadosG@users.noreply.github.com>
2026-08-27 21:59:13 +03:00
Pranshul d76abb1f06 New translations strings.xml (Dutch)
[ci skip]
2026-08-28 00:03:31 +05:30
Pranshul 241ab03dd2 New translations strings.xml (Japanese)
[ci skip]
2026-08-28 00:03:29 +05:30
Pranshul 41a2a9abe3 New translations strings.xml (Finnish)
[ci skip]
2026-08-28 00:03:28 +05:30
PranshulGG f1e8707aa1 bump version 2026-08-27 21:49:59 +05:30
PranshulGG 9327b90e9f fix icons 2026-08-27 21:49:35 +05:30
PranshulGG e2c43cd774 bump version 2026-08-27 21:36:18 +05:30
PranshulGG 21d7466d24 fix 24hr format closes #1092 2026-08-27 21:35:52 +05:30
PranshulGG 40a41432ea bump version 2026-08-27 21:23:05 +05:30
PranshulGG bc23098401 fix text overflows 2026-08-27 21:22:40 +05:30
PranshulGG 26b90e2721 bump version 2026-08-27 20:40:09 +05:30
PranshulGG dbf162d92f fix scheduled notification crashes 2026-08-27 20:39:40 +05:30
PranshulGG d99a79d925 add IMET and OpenWeather to weather providers list in README and metadata 2026-08-27 17:51:07 +05:30
PranshulGG 610b2f29e6 bump version 2026-08-27 17:42:12 +05:30
PranshulGG e0fa0374d3 remove logs 2026-08-27 17:28:27 +05:30
PranshulGG 0f63154f84 add froggy widget 2026-08-27 17:16:48 +05:30
PranshulGG 7a799cb24a configurable pill widget closes #1053 2026-08-27 14:19:36 +05:30
PranshulGG 178300a547 null crash 2026-08-27 13:00:50 +05:30
PranshulGG 9baec3bb63 cache handling 2026-08-27 11:36:45 +05:30
Pranshul d417f6b4f1 Merge pull request #1078 from PranshulGG/l10n_main
New Crowdin updates
2026-08-27 09:29:03 +05:30
Pranshul ff60bb41f1 New translations strings.xml (Italian)
[ci skip]
2026-08-27 02:05:00 +05:30
Pranshul f41bd691e9 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-27 02:04:58 +05:30
Pranshul 78450b78a2 Merge pull request #1085 from reveler-hub/fix/moon-rise-set-pairing-1083
fix inverted branches in moonrise/moonset pairing fix
2026-08-26 22:12:01 +05:30
PranshulGG 3bff4f99b8 add widget preview 2026-08-26 22:00:58 +05:30
PranshulGG 2ba49de23f add widget preview 2026-08-26 22:00:53 +05:30
PranshulGG ce14573fa0 add new widget closes #945 2026-08-26 21:56:31 +05:30
PranshulGG 535ad8feb6 fix naming 2026-08-26 21:56:02 +05:30
PranshulGG 0f6b0950ea add missing widget previews 2026-08-26 21:55:52 +05:30
reveler-hubandClaude 0fe4afe5c5 Add attribution comment, per CONTRIBUTING.md
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-27 02:34:10 +12:00
reveler-hubandClaude a3f8ab735f fix moonrise/moonset pairing: branches in the #1077 fix were swapped
The rise>set check correctly detects a stale same-day set left over from
the previous cycle, but the two branches were inverted: the stale value
was kept as-is, and the already-correct case was overwritten with a
next-day set instead. Closes #1083.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-27 02:31:53 +12:00
Pranshul aee884b7cd New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-26 19:29:48 +05:30
Pranshul ee5df57a43 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-26 19:29:46 +05:30
Pranshul b0289561ab New translations strings.xml (Filipino)
[ci skip]
2026-08-26 19:29:45 +05:30
Pranshul 041fdfd605 New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-26 19:29:43 +05:30
Pranshul 4419fef116 New translations strings.xml (Kazakh)
[ci skip]
2026-08-26 19:29:41 +05:30
Pranshul 788354ecea New translations strings.xml (Thai)
[ci skip]
2026-08-26 19:29:39 +05:30
Pranshul 3b55de9785 New translations strings.xml (Persian)
[ci skip]
2026-08-26 19:29:38 +05:30
Pranshul 6b7285f0f4 New translations strings.xml (Indonesian)
[ci skip]
2026-08-26 19:29:36 +05:30
Pranshul d493b6f83d New translations strings.xml (Vietnamese)
[ci skip]
2026-08-26 19:29:35 +05:30
Pranshul 875ab0138a New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-26 19:29:33 +05:30
Pranshul 2bd0ae075d New translations strings.xml (Swedish)
[ci skip]
2026-08-26 19:29:32 +05:30
Pranshul 92db6f7f3c New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-26 19:29:30 +05:30
Pranshul 36406fd803 New translations strings.xml (Slovenian)
[ci skip]
2026-08-26 19:29:28 +05:30
Pranshul 22a69af5d5 New translations strings.xml (Korean)
[ci skip]
2026-08-26 19:29:27 +05:30
Pranshul 140f880973 New translations strings.xml (Hungarian)
[ci skip]
2026-08-26 19:29:25 +05:30
Pranshul df427f4dbc New translations strings.xml (Greek)
[ci skip]
2026-08-26 19:29:24 +05:30
Pranshul 6f0da01b1b New translations strings.xml (German)
[ci skip]
2026-08-26 19:29:22 +05:30
Pranshul 28849dce75 New translations strings.xml (Catalan)
[ci skip]
2026-08-26 19:29:21 +05:30
Pranshul 110fb5cb10 New translations strings.xml (Bulgarian)
[ci skip]
2026-08-26 19:29:19 +05:30
Pranshul 1531eeb2f2 New translations strings.xml (Romanian)
[ci skip]
2026-08-26 19:29:18 +05:30
Pranshul 437fada842 New translations strings.xml (Polish)
[ci skip]
2026-08-26 19:29:16 +05:30
Pranshul 89516df777 New translations strings.xml (Italian)
[ci skip]
2026-08-26 19:29:14 +05:30
Pranshul e5e1dd653a New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-26 19:29:13 +05:30
Pranshul a6efd55267 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-26 19:29:11 +05:30
Pranshul a6d3d150c7 New translations strings.xml (French)
[ci skip]
2026-08-26 19:29:09 +05:30
Pranshul f628a22b45 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-26 19:29:07 +05:30
Pranshul d73020699a New translations strings.xml (Ukrainian)
[ci skip]
2026-08-26 19:29:06 +05:30
Pranshul eb9d91f955 New translations strings.xml (Turkish)
[ci skip]
2026-08-26 19:29:05 +05:30
Pranshul 2df11581d5 New translations strings.xml (Russian)
[ci skip]
2026-08-26 19:29:03 +05:30
Pranshul 08a0753376 New translations strings.xml (Portuguese)
[ci skip]
2026-08-26 19:29:02 +05:30
Pranshul d1590f435f New translations strings.xml (Dutch)
[ci skip]
2026-08-26 19:29:00 +05:30
Pranshul 1fa82c1623 New translations strings.xml (Japanese)
[ci skip]
2026-08-26 19:28:59 +05:30
Pranshul c653127a5f New translations strings.xml (Hebrew)
[ci skip]
2026-08-26 19:28:57 +05:30
Pranshul ee49326a65 New translations strings.xml (Finnish)
[ci skip]
2026-08-26 19:28:56 +05:30
Pranshul 78c46369cc New translations strings.xml (Czech)
[ci skip]
2026-08-26 19:28:55 +05:30
Pranshul c34b6a3fed New translations strings.xml (Spanish)
[ci skip]
2026-08-26 19:28:53 +05:30
PranshulGG 057b171dc5 fix uv index widgets not working 2026-08-26 18:19:39 +05:30
PranshulGG 0a26f51cc1 add BottomNavSpacing and update widget background colors for mixed precipitation, sleet, and hail 2026-08-26 17:57:50 +05:30
PranshulGG 505b23bac4 option to hide the weather 2026-08-26 17:52:03 +05:30
PranshulGG 2693fef706 add more formates closes #1042 2026-08-26 17:46:44 +05:30
PranshulGG 95bd4d51be add more formates closes #1042 2026-08-26 17:41:53 +05:30
PranshulGG f16820d63a Remove unwanted comments 2026-08-26 17:04:50 +05:30
PranshulGG d44f2f6650 Remove unwanted comments 2026-08-26 17:04:37 +05:30
PranshulGG 131c0d422d Remove unwanted comments 2026-08-26 17:03:26 +05:30
Pranshul ee30d3c32c Merge pull request #1082 from PranshulGG/revert-1080-main
Revert "Refactor: moved business logic to Use Cases and added unit test suite"
2026-08-26 16:54:49 +05:30
Pranshul 6d953c1be5 Revert "Refactor: moved business logic to Use Cases and added unit test suite" 2026-08-26 16:54:26 +05:30
Pranshul 6c892dfc7c Merge pull request #1080 from gietabhi10/main
Refactor: moved business logic to Use Cases and added unit test suite
2026-08-26 16:45:37 +05:30
PranshulGG a78fdf7794 add drawables 2026-08-26 16:44:25 +05:30
PranshulGG cf4f20d4e1 move notification channels 2026-08-26 16:44:11 +05:30
PranshulGG eba12e7764 add time picker 2026-08-26 16:43:55 +05:30
PranshulGG 08a376b368 switch tile empty description 2026-08-26 16:43:46 +05:30
PranshulGG 1a5aa6e8bb add notifications closes #1021 2026-08-26 16:43:30 +05:30
Pranshul 94992e2964 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-25 19:44:11 +05:30
Pranshul 55dfa49092 New translations strings.xml (French)
[ci skip]
2026-08-25 19:44:09 +05:30
Pranshul d00bdc6fd2 New translations strings.xml (Japanese)
[ci skip]
2026-08-25 19:44:07 +05:30
ABHISHEK KR. SHARMA 3a0303c7a8 Resolve merge conflict in WeatherViewModel: use WeatherBackgroundUpdateScheduler 2026-08-25 19:33:42 +05:30
ABHISHEK KR. SHARMA cd59a1acbb Final cleanup: removed implementation notes and meta-comments 2026-08-25 19:25:45 +05:30
ABHISHEK KR. SHARMA 908b9ad1f1 Add required attribution to domain layer files and verify behavior 2026-08-25 19:25:44 +05:30
ABHISHEK KR. SHARMA b904ccfda3 Final refactor refinements: fix auto-refresh lifecycle, clarify threading, and add cancellation tests 2026-08-25 19:25:44 +05:30
ABHISHEK KR. SHARMA 1fc1fdbfb3 Address final code review: fix auto-refresh bug, add cancellation tests, and refine threading 2026-08-25 19:25:44 +05:30
ABHISHEK KR. SHARMA af41a68451 Refine tests with MockK slots, add architectural docs, and clean up ViewModel 2026-08-25 19:25:44 +05:30
ABHISHEK KR. SHARMA e3fe505f5b Address critical review items and enhance test coverage 2026-08-25 19:25:43 +05:30
ABHISHEK KR. SHARMA 9f9539ce6f Address code review feedback and fix build configuration 2026-08-25 19:25:37 +05:30
ABHISHEK KR. SHARMA 8d33745d06 Refactor: moved business logic to Use Cases and added unit test suite
# Conflicts:
#	app/src/main/java/com/pranshulgg/weather_master_app/feature/shared/WeatherViewModel.kt
2026-08-25 19:25:26 +05:30
Pranshul 99a9918676 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-25 13:41:56 +05:30
PranshulGG e5f01faf6a increase max height 2026-08-25 09:37:28 +05:30
PranshulGG f21c18c058 Scheduled Notifications #1021 2026-08-25 09:37:13 +05:30
PranshulGG 7ab944e769 Simplify pr-build.yml by removing manual pr_number input and ref checkout logic 2026-08-25 09:09:27 +05:30
PranshulGG 90a80b1e61 remove API secrets from pr-build workflow and update checkout ref logic 2026-08-25 09:04:29 +05:30
PranshulGG 43aeb6d59e add workflow_dispatch to pr-build.yml with pr_number input support 2026-08-25 08:59:08 +05:30
PranshulGG ccf0135932 add GitHub Actions workflow for PR builds 2026-08-25 08:51:19 +05:30
Pranshul c859e43f3e New translations strings.xml (Korean)
[ci skip]
2026-08-25 07:40:01 +05:30
Pranshul a450ec0895 New translations strings.xml (French)
[ci skip]
2026-08-25 07:39:59 +05:30
Pranshul 1bee5cf6c6 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-24 17:06:21 +05:30
Pranshul 6c364f6d10 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-23 23:24:36 +05:30
Pranshul 4c0139c0aa New translations strings.xml (Turkish)
[ci skip]
2026-08-23 23:24:35 +05:30
PranshulGG f3efc3f73a improve null handling of sun/moon block 2026-08-23 20:33:24 +05:30
PranshulGG 1bebbac4ae update db and CONTRIBUTING.md 2026-08-23 20:30:34 +05:30
PranshulGG 1d39ddd941 nullable sun/moon and add attributions 2026-08-23 20:20:12 +05:30
PranshulGG 7303979d93 fix overflow on large font size 2026-08-23 20:00:23 +05:30
PranshulGG 0dda08ec21 fix moon timing closes #1077 closes #1072 2026-08-23 17:16:56 +05:30
Pranshul 84b56ac53f New translations strings.xml (Italian)
[ci skip]
2026-08-23 17:16:11 +05:30
PranshulGG 46d099927e update SunBlock to use timezone-aware time and fix sun progress calculation 2026-08-23 15:05:37 +05:30
Pranshul 442fc8fd4e Merge pull request #1073 from reveler-hub/feature/auto-select-paired-alert-source
Auto-select a self-paired alert source to match the weather source
2026-08-23 13:33:10 +05:30
reveler-hub af80866766 Remove alert-source auto-pairing from Edit Location, per review
Weather source and alert source are meant to be independent choices in
Edit Location - the alert picker already only lists sources with
Capability.ALERTS, so it's up to the user to decide, e.g. AccuWeather
for weather + JMA for alerts. Auto-changing alertSource whenever the
weather source changed would silently override a deliberate pairing
the user may have set earlier (JMA+JMA -> switch weather to AccuWeather
-> forced to AccuWeather+AccuWeather instead of preserving JMA alerts).

The auto-pairing for a brand-new location (SearchScreenViewModel) is
unaffected - there the user has no prior alert-source choice to
override, so defaulting a self-paired source's alerts to match still
makes sense.

Verified live: switching an existing location's weather source
(JMA -> AccuWeather) now leaves the alert source on JMA instead of
forcing it to follow.
2026-08-23 19:56:48 +12:00
PranshulGG 6f8b45ca18 Add CONTRIBUTING.md 2026-08-23 13:19:45 +05:30
Pranshul 47a5b0b1b7 Merge pull request #1057 from PranshulGG/l10n_main
New Crowdin updates
2026-08-23 13:07:06 +05:30
Pranshul 0d70296959 Merge pull request #1070 from reveler-hub/feature/nws-alerts
Add alerts support to NWS
2026-08-23 12:50:22 +05:30
Pranshul 8b52d13b3e New translations strings.xml (Greek)
[ci skip]
2026-08-23 11:20:52 +05:30
Pranshul 28bf02a6fa New translations strings.xml (Italian)
[ci skip]
2026-08-23 11:20:50 +05:30
Pranshul dd8f1f0685 New translations strings.xml (Czech)
[ci skip]
2026-08-23 04:46:16 +05:30
Pranshul 7c4b4027f3 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-22 22:37:05 +05:30
Pranshul 80bcbf43f0 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-22 22:37:04 +05:30
Pranshul 70fe1a8459 New translations strings.xml (Filipino)
[ci skip]
2026-08-22 22:37:03 +05:30
Pranshul 7d2b97173a New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-22 22:37:02 +05:30
Pranshul 2f5cf31a36 New translations strings.xml (Kazakh)
[ci skip]
2026-08-22 22:37:01 +05:30
Pranshul 0fb5d6386e New translations strings.xml (Thai)
[ci skip]
2026-08-22 22:36:59 +05:30
Pranshul 3316760752 New translations strings.xml (Persian)
[ci skip]
2026-08-22 22:36:58 +05:30
Pranshul 4f78b59e4d New translations strings.xml (Indonesian)
[ci skip]
2026-08-22 22:36:57 +05:30
Pranshul 6c29dc1fc8 New translations strings.xml (Vietnamese)
[ci skip]
2026-08-22 22:36:55 +05:30
Pranshul 6b57d3c557 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-22 22:36:54 +05:30
Pranshul b0a9b03ebd New translations strings.xml (Swedish)
[ci skip]
2026-08-22 22:36:53 +05:30
Pranshul 2a848ce478 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-22 22:36:52 +05:30
Pranshul 61a94e1e90 New translations strings.xml (Slovenian)
[ci skip]
2026-08-22 22:36:51 +05:30
Pranshul b910f85bc9 New translations strings.xml (Korean)
[ci skip]
2026-08-22 22:36:49 +05:30
Pranshul ed56bd48e2 New translations strings.xml (Hungarian)
[ci skip]
2026-08-22 22:36:48 +05:30
Pranshul 380c8fceb6 New translations strings.xml (Greek)
[ci skip]
2026-08-22 22:36:47 +05:30
Pranshul 245ec8cafc New translations strings.xml (German)
[ci skip]
2026-08-22 22:36:46 +05:30
Pranshul 130ae9437e New translations strings.xml (Catalan)
[ci skip]
2026-08-22 22:36:44 +05:30
Pranshul 023195386a New translations strings.xml (Bulgarian)
[ci skip]
2026-08-22 22:36:43 +05:30
Pranshul e33cf1e4b7 New translations strings.xml (Romanian)
[ci skip]
2026-08-22 22:36:42 +05:30
Pranshul fafcca97ff New translations strings.xml (Polish)
[ci skip]
2026-08-22 22:36:41 +05:30
Pranshul 83b34568c8 New translations strings.xml (Italian)
[ci skip]
2026-08-22 22:36:40 +05:30
Pranshul 4bfab73ff7 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-22 22:36:38 +05:30
Pranshul 6fe4c4587a New translations strings.xml (Lithuanian)
[ci skip]
2026-08-22 22:36:37 +05:30
Pranshul dee4780980 New translations strings.xml (French)
[ci skip]
2026-08-22 22:36:36 +05:30
Pranshul a179446126 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-22 22:36:35 +05:30
Pranshul bf5468ea04 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-22 22:36:34 +05:30
Pranshul 747527c23c New translations strings.xml (Turkish)
[ci skip]
2026-08-22 22:36:32 +05:30
Pranshul 4b47a9bcf4 New translations strings.xml (Russian)
[ci skip]
2026-08-22 22:36:31 +05:30
Pranshul 291984de32 New translations strings.xml (Portuguese)
[ci skip]
2026-08-22 22:36:30 +05:30
Pranshul b54b17872d New translations strings.xml (Dutch)
[ci skip]
2026-08-22 22:36:29 +05:30
Pranshul 2bb8549a93 New translations strings.xml (Japanese)
[ci skip]
2026-08-22 22:36:27 +05:30
Pranshul f3ae6d5563 New translations strings.xml (Hebrew)
[ci skip]
2026-08-22 22:36:26 +05:30
Pranshul 4479c43182 New translations strings.xml (Finnish)
[ci skip]
2026-08-22 22:36:25 +05:30
Pranshul 2dac241237 New translations strings.xml (Czech)
[ci skip]
2026-08-22 22:36:24 +05:30
Pranshul e9fb0ab462 New translations strings.xml (Spanish)
[ci skip]
2026-08-22 22:36:22 +05:30
reveler-hub fa651168f6 Auto-select a self-paired alert source to match the weather source
Sources like JMA, AccuWeather, Pirate Weather, and INMET (soon NWS)
serve both weather and alerts from the same provider, but alertSource
stayed NONE unless a user separately opened the alert-source picker
and picked it manually. Now, whenever a location's weather source is
set or changed to one with Capability.ALERTS, alertSource follows it
automatically - for a brand-new location and when editing an existing
one. Picking a non-self-paired weather source leaves the current
alert-source choice untouched rather than clearing it, so deliberately
mixed pairings (e.g. AccuWeather for weather, WMO for alerts) still
work.

Verified live on device: a new Japan location auto-pairs JMA for both;
switching an existing location's weather source to AccuWeather
auto-follows the alert-source tile before saving; switching back to a
non-self-paired source leaves the prior alert-source pick intact.
2026-08-23 00:34:43 +12:00
reveler-hub d59b4b7a4b Add NWS alerts (self-paired)
NWS is the recommended weather source for the US but had no alerts
capability, so US locations got zero recommended alert sources in the
Edit Location picker. NwsRepository now also implements AlertRepository
using the free, keyless /alerts/active endpoint on the same host
NwsRepository already talks to.
2026-08-22 23:58:37 +12:00
Pranshul d852fbbeea Merge pull request #1065 from reveler-hub/feature/backup-restore
Add Backup & Restore (export/import locations and settings)
2026-08-22 17:11:52 +05:30
PranshulGG d7a062edd8 remove redundant modifiers in feature sheets 2026-08-22 17:11:22 +05:30
Pranshul 90f331b824 New translations strings.xml (French)
[ci skip]
2026-08-22 16:34:12 +05:30
Pranshul dd84612797 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-22 16:34:10 +05:30
Pranshul 61ce0712a5 New translations strings.xml (Russian)
[ci skip]
2026-08-22 16:34:09 +05:30
reveler-hubandClaude Sonnet 5 312df078c6 Reject backups without a default location, add intro-screen import
Addresses PranshulGG's review comment on #1065:
- restoreBackup() now rejects a backup with no default location instead
  of silently importing a state the app never expects.
- New "Import a backup" option on the intro screen, reusing the same
  restore path, so a fresh install can skip manual location setup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeA5SoK1dsP8uxkMi2qEGu
2026-08-22 17:00:45 +12:00
reveler-hubandClaude Sonnet 5 4977ff7a70 Add Backup & Restore (export/import locations and settings)
Closes #848. Lets users export their locations, units, weather block
layout, and app settings to a JSON file, and restore from one - the
old Flutter version had this and it was never ported to the Kotlin
rewrite. API keys are opt-in on export (off by default); import is a
full replace of everything except keys, which are left alone when the
file doesn't include any.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeA5SoK1dsP8uxkMi2qEGu
2026-08-22 17:00:45 +12:00
Pranshul 0fd4423d9e New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-22 10:11:01 +05:30
Pranshul ba1108a681 New translations strings.xml (Spanish)
[ci skip]
2026-08-22 10:10:59 +05:30
Pranshul eb9e6bae8c New translations strings.xml (Finnish)
[ci skip]
2026-08-22 03:43:52 +05:30
Pranshul 4b363fc70c New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-21 21:42:07 +05:30
Pranshul b589268359 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-21 21:42:05 +05:30
Pranshul 56f6167059 New translations strings.xml (Filipino)
[ci skip]
2026-08-21 21:42:04 +05:30
Pranshul 822647ad9d New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-21 21:42:02 +05:30
Pranshul a483367254 New translations strings.xml (Kazakh)
[ci skip]
2026-08-21 21:42:00 +05:30
Pranshul fb9a8418bb New translations strings.xml (Thai)
[ci skip]
2026-08-21 21:41:59 +05:30
Pranshul 996c4d0da7 New translations strings.xml (Persian)
[ci skip]
2026-08-21 21:41:57 +05:30
Pranshul 556d0c17a3 New translations strings.xml (Indonesian)
[ci skip]
2026-08-21 21:41:56 +05:30
Pranshul 77a3c2b447 New translations strings.xml (Vietnamese)
[ci skip]
2026-08-21 21:41:55 +05:30
Pranshul 8ea3391834 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-21 21:41:53 +05:30
Pranshul 7763842e3f New translations strings.xml (Swedish)
[ci skip]
2026-08-21 21:41:52 +05:30
Pranshul 2681b5f79c New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-21 21:41:50 +05:30
Pranshul 8b63311f27 New translations strings.xml (Slovenian)
[ci skip]
2026-08-21 21:41:48 +05:30
Pranshul a9ccd31878 New translations strings.xml (Korean)
[ci skip]
2026-08-21 21:41:47 +05:30
Pranshul ec379303df New translations strings.xml (Hungarian)
[ci skip]
2026-08-21 21:41:45 +05:30
Pranshul 197d7f289e New translations strings.xml (Greek)
[ci skip]
2026-08-21 21:41:43 +05:30
Pranshul d6ffaa6296 New translations strings.xml (German)
[ci skip]
2026-08-21 21:41:42 +05:30
Pranshul a712aa5cf3 New translations strings.xml (Catalan)
[ci skip]
2026-08-21 21:41:41 +05:30
Pranshul 67aecfb801 New translations strings.xml (Bulgarian)
[ci skip]
2026-08-21 21:41:39 +05:30
Pranshul c906608949 New translations strings.xml (Romanian)
[ci skip]
2026-08-21 21:41:38 +05:30
Pranshul 0250de39da New translations strings.xml (Polish)
[ci skip]
2026-08-21 21:41:36 +05:30
Pranshul f8eaf46410 New translations strings.xml (Italian)
[ci skip]
2026-08-21 21:41:35 +05:30
Pranshul de0edc1a5a New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-21 21:41:33 +05:30
Pranshul b0978fcc59 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-21 21:41:32 +05:30
Pranshul 494baa735e New translations strings.xml (French)
[ci skip]
2026-08-21 21:41:30 +05:30
Pranshul 9b45954b3e New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-21 21:41:28 +05:30
Pranshul d643ac0824 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-21 21:41:27 +05:30
Pranshul 8735ae3c91 New translations strings.xml (Turkish)
[ci skip]
2026-08-21 21:41:26 +05:30
Pranshul 9a8b7dc039 New translations strings.xml (Russian)
[ci skip]
2026-08-21 21:41:24 +05:30
Pranshul eb08b049b6 New translations strings.xml (Portuguese)
[ci skip]
2026-08-21 21:41:23 +05:30
Pranshul adf707b05e New translations strings.xml (Dutch)
[ci skip]
2026-08-21 21:41:21 +05:30
Pranshul c63300147d New translations strings.xml (Japanese)
[ci skip]
2026-08-21 21:41:20 +05:30
Pranshul 30ed7e5ecc New translations strings.xml (Hebrew)
[ci skip]
2026-08-21 21:41:18 +05:30
Pranshul 8d76519371 New translations strings.xml (Finnish)
[ci skip]
2026-08-21 21:41:17 +05:30
Pranshul 8224eee33e New translations strings.xml (Czech)
[ci skip]
2026-08-21 21:41:15 +05:30
Pranshul 2fcf6d505f New translations strings.xml (Spanish)
[ci skip]
2026-08-21 21:41:13 +05:30
Pranshul c8303d1c30 Merge pull request #1059 from reveler-hub/feature/amoled-dark-theme
Add AMOLED (pure black) dark theme option
2026-08-21 21:12:30 +05:30
PranshulGG 9eb21ed44d improve source pickers 2026-08-21 21:11:05 +05:30
PranshulGG fd4487e8ef add missing froggy images 2026-08-21 21:02:21 +05:30
PranshulGG d6dd1cef95 new conditions and froggy images 2026-08-21 20:09:33 +05:30
PranshulGG 708b50d8dd add openweather source close #155 2026-08-21 20:00:39 +05:30
PranshulGG 75d1b310cd add WeatherUtils with helper functions for weather data processing 2026-08-21 16:45:39 +05:30
PranshulGG 39c7195910 refactor MetNorwayJsonMapper to use WeatherUtils for safe weather calculations and dominant value logic 2026-08-21 16:45:29 +05:30
PranshulGG 101a58c302 calculate dominant wind direction instead of average in MetNorwayJsonMapper 2026-08-21 15:40:08 +05:30
Pranshul 4f1ca5e81e New translations strings.xml (Indonesian)
[ci skip]
2026-08-21 15:36:34 +05:30
Pranshul 57bc9940eb New translations strings.xml (French)
[ci skip]
2026-08-21 07:18:59 +05:30
PranshulGG c3b3948a84 add comments 2026-08-20 21:31:58 +05:30
PranshulGG fa0259251c use getSourcesGlobal for source selection and filter by relevant capabilities 2026-08-20 21:31:49 +05:30
Pranshul b1e00eb18b New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-20 21:10:58 +05:30
Pranshul 47597f5eda New translations strings.xml (Catalan)
[ci skip]
2026-08-20 21:10:56 +05:30
PranshulGG 3dcfff12b8 fix spacing 2026-08-20 20:59:13 +05:30
PranshulGG caf008ff4b add tablet layout closes #768 closes #934 closes #877 2026-08-20 20:55:39 +05:30
reveler-hub b2786768e5 Add AMOLED (pure black) dark theme option
Closes #245.
2026-08-21 03:15:09 +12:00
PranshulGG a00c0dedeb fixed missing inmet conditions and made humidity nullable 2026-08-20 18:18:58 +05:30
PranshulGG 08bd6aeb58 keep only the previous 24 hours 2026-08-20 17:56:20 +05:30
Pranshul d95b1e7238 Merge pull request #1052 from reveler-hub/fix/device-location-cache-not-invalidated
Fix device location's weather staying pinned to the old city after moving
2026-08-20 16:29:56 +05:30
Pranshul 0c1a483dd8 Merge pull request #1056 from reveler-hub/fix/bmkg-forecast-403-referer
Fix BMKG forecast endpoint returning 403 Forbidden
2026-08-20 16:25:12 +05:30
PranshulGG 564b469af2 add fallback for dewPoint in HumidityBlock and allow null humidity in InmetJsonMapper 2026-08-20 16:24:50 +05:30
Pranshul c774f38b75 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-20 14:40:13 +05:30
Pranshul 5d592d37f4 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-20 14:40:12 +05:30
Pranshul e6da014ec8 New translations strings.xml (Filipino)
[ci skip]
2026-08-20 14:40:10 +05:30
Pranshul f328401991 New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-20 14:40:09 +05:30
Pranshul a3efc52b6c New translations strings.xml (Kazakh)
[ci skip]
2026-08-20 14:40:07 +05:30
Pranshul da4b9429ba New translations strings.xml (Thai)
[ci skip]
2026-08-20 14:40:06 +05:30
Pranshul 2aa8918eca New translations strings.xml (Persian)
[ci skip]
2026-08-20 14:40:05 +05:30
Pranshul 4e7587cac5 New translations strings.xml (Indonesian)
[ci skip]
2026-08-20 14:40:03 +05:30
Pranshul b8133ea7ab New translations strings.xml (Vietnamese)
[ci skip]
2026-08-20 14:40:02 +05:30
Pranshul 5753ff235d New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-20 14:40:00 +05:30
Pranshul b94021f6b4 New translations strings.xml (Swedish)
[ci skip]
2026-08-20 14:39:59 +05:30
Pranshul 65bdc3597a New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-20 14:39:57 +05:30
Pranshul d5e8c1153a New translations strings.xml (Slovenian)
[ci skip]
2026-08-20 14:39:56 +05:30
Pranshul 5063572e8e New translations strings.xml (Korean)
[ci skip]
2026-08-20 14:39:54 +05:30
Pranshul 0e33eb45b4 New translations strings.xml (Hungarian)
[ci skip]
2026-08-20 14:39:53 +05:30
Pranshul c3c10c32df New translations strings.xml (Greek)
[ci skip]
2026-08-20 14:39:52 +05:30
Pranshul a6308fe77e New translations strings.xml (German)
[ci skip]
2026-08-20 14:39:50 +05:30
Pranshul 580b0fafbc New translations strings.xml (Catalan)
[ci skip]
2026-08-20 14:39:49 +05:30
Pranshul d8cc015f1e New translations strings.xml (Bulgarian)
[ci skip]
2026-08-20 14:39:48 +05:30
Pranshul 22c46cdfe2 New translations strings.xml (Romanian)
[ci skip]
2026-08-20 14:39:46 +05:30
Pranshul 6da01ba665 New translations strings.xml (Polish)
[ci skip]
2026-08-20 14:39:45 +05:30
Pranshul 1c66ab3ea5 New translations strings.xml (Italian)
[ci skip]
2026-08-20 14:39:44 +05:30
Pranshul a6073fea32 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-20 14:39:42 +05:30
Pranshul 85728b1125 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-20 14:39:40 +05:30
Pranshul 24a6f127cd New translations strings.xml (French)
[ci skip]
2026-08-20 14:39:39 +05:30
Pranshul 9a8155dd6a New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-20 14:39:38 +05:30
Pranshul 476bd06bd3 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-20 14:39:36 +05:30
Pranshul f1d1671b24 New translations strings.xml (Turkish)
[ci skip]
2026-08-20 14:39:35 +05:30
Pranshul a472202580 New translations strings.xml (Russian)
[ci skip]
2026-08-20 14:39:33 +05:30
Pranshul a05427d32c New translations strings.xml (Portuguese)
[ci skip]
2026-08-20 14:39:32 +05:30
Pranshul c15119949b New translations strings.xml (Dutch)
[ci skip]
2026-08-20 14:39:31 +05:30
Pranshul d939a097c9 New translations strings.xml (Japanese)
[ci skip]
2026-08-20 14:39:29 +05:30
Pranshul c3388f152e New translations strings.xml (Hebrew)
[ci skip]
2026-08-20 14:39:28 +05:30
Pranshul f749eb43ce New translations strings.xml (Finnish)
[ci skip]
2026-08-20 14:39:26 +05:30
Pranshul ecac8de460 New translations strings.xml (Czech)
[ci skip]
2026-08-20 14:39:25 +05:30
Pranshul 41bd1ebcf3 New translations strings.xml (Spanish)
[ci skip]
2026-08-20 14:39:23 +05:30
reveler-hub 965cfc17da Fix BMKG forecast endpoint returning 403 Forbidden
BMKG's Cloudflare WAF rejects api/df/v1/forecast/coord unless the
request carries a same-origin Referer header, matching what their
own frontend sends. Confirmed live: the exact same request succeeds
with the header and fails without it, regardless of User-Agent.

api/presentwx/coord (current conditions) isn't affected either way,
so the header is applied to all BMKG requests for simplicity.

Closes #1037, #1054
2026-08-20 20:23:57 +12:00
reveler-hub 39d597df20 Fix spurious weather refresh on every in-app navigation
Moving the ON_START refresh trigger into MainScreen's composition
meant Compose disposed and recreated its LifecycleEventObserver on
every navigation away and back, and Android replays a synthetic
ON_START to a freshly-added observer when the Activity is already
started - firing getWeather() on every nav, not just a real resume.

Moved the trigger into WeatherViewModel, observing ProcessLifecycleOwner
once in init{} (same pattern AppVisibility already uses), so the
observer is only ever added once for the ViewModel's lifetime.

Also switches LocationsRepository over to cleanLocationExtras.
2026-08-20 17:43:05 +12:00
reveler-hub d05660faa2 Fix weather not refreshing on a normal app resume (only worked on cold start)
Two separate things needed fixing for #1048 to actually resolve for a
user who doesn't force-kill the app between opens:

1. WeatherAutoRefreshForeground's ON_START handler used to call
   getWeather() immediately on every resume (added by PR #1043,
   closes #1035) - a later refactor (9c901ef2c) commented that call
   out entirely, leaving only a 45-minute-delayed auto-refresh loop.
   Restored it.

2. Restoring #1 alone re-exposed a real race: the device-location
   branch in getWeather() updates activeLocation mid-fetch after
   detecting a move, which changed the `location` parameter this
   composable's DisposableEffect was keyed on. Compose replays a
   synthetic ON_START when an effect resubscribes, which fired a
   second getWeather() call whose weatherJob?.cancel() killed the
   first call's in-flight fetch before it could write the real
   data - leaving the location name/coordinates updated but the
   weather itself still stale, i.e. exactly #1048's symptom.
   Fixed by reading the location via rememberUpdatedState instead
   of keying the effect on it, so a location mutation no longer
   restarts the effect.

Found and confirmed via debug logging on-device: two ON_START events
~1.2s apart, the second cancelling the first's active coroutine.
Verified fixed the same way - moved a device location from Pittsburgh
to Myrtle Beach via a background/foreground cycle (not a cold start),
confirmed real Myrtle Beach data (not stale Pittsburgh data) loads
correctly.
2026-08-20 17:22:32 +12:00
reveler-hub f86217bc7b Fix weather staying pinned to the old location after the device moves
updateDeviceLocationPosition() updates the device location's lat/lon
and display name atomically, but never invalidated any per-source
"resolve coordinates once, cache by locationId" layer - NWS's grid
points, and the composite location-key cache several other sources
use (CWA/AEMET/JMA/Gismeteo/IPMA/MetOffice/Accu). Since the device
location keeps the same id forever while its coordinates change, a
big move left the display name/coordinates updating correctly while
the actual weather stayed pinned to wherever it was last resolved -
e.g. still showing the old city's weather under the new city's name
after traveling (closes #1048).

WeatherDataReconcilerRepository.reconcileSourceChange() doesn't cover
this case: it only clears these caches on an explicit source switch
(NWS -> OpenMeteo), not on a coordinate change while staying on the
same source, which is exactly what a moving device location does.

Verified on-device: seeded a real NWS grid-point cache entry for
Pittsburgh, mock-moved to Myrtle Beach, confirmed (pre-fix, by code
reading) the stale grid point would persist; post-fix, confirmed via
a cold start that the cache correctly flips to Myrtle Beach's real
grid point and real weather replaces the stale data.
2026-08-20 17:22:32 +12:00
PranshulGG 1229bc792f add cleanLocationExtras function to WeatherDataReconcilerRepository 2026-08-20 09:53:36 +05:30
Pranshul e4355b9b93 Merge pull request #1045 from PranshulGG/l10n_main
New Crowdin updates
2026-08-20 09:48:52 +05:30
Pranshul 282d3ba501 Merge pull request #1049 from reveler-hub/fix/weather-screen-crossfade-jitter
Fix a visible stutter/flash on every weather refresh
2026-08-20 09:47:13 +05:30
Pranshul 8b2f80ddc8 Merge pull request #1046 from altendorfme/main
Add IMET (Brazil Coverage) source
2026-08-20 09:42:30 +05:30
Pranshul 26dee72ce7 New translations strings.xml (Italian)
[ci skip]
2026-08-20 08:20:57 +05:30
Pranshul 4abbcabf12 New translations strings.xml (French)
[ci skip]
2026-08-20 08:20:56 +05:30
Pranshul d2b0314c63 New translations strings.xml (Russian)
[ci skip]
2026-08-20 08:20:54 +05:30
Pranshul 9dc685fbf8 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-20 02:10:09 +05:30
Pranshul 64885f5b6d New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-20 02:10:07 +05:30
Pranshul f2eb7d2f70 New translations strings.xml (Filipino)
[ci skip]
2026-08-20 02:10:06 +05:30
Pranshul 53812e94ce New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-20 02:10:04 +05:30
Pranshul b4e7c67e62 New translations strings.xml (Kazakh)
[ci skip]
2026-08-20 02:10:03 +05:30
Pranshul 99bd0ba8aa New translations strings.xml (Thai)
[ci skip]
2026-08-20 02:10:02 +05:30
Pranshul ba692433e3 New translations strings.xml (Persian)
[ci skip]
2026-08-20 02:10:00 +05:30
Pranshul 78c36087ab New translations strings.xml (Indonesian)
[ci skip]
2026-08-20 02:09:59 +05:30
Pranshul 1c1dad0e5d New translations strings.xml (Vietnamese)
[ci skip]
2026-08-20 02:09:58 +05:30
Pranshul 71607b1313 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-20 02:09:56 +05:30
Pranshul 971e2c42d8 New translations strings.xml (Swedish)
[ci skip]
2026-08-20 02:09:55 +05:30
Pranshul 1644a212df New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-20 02:09:54 +05:30
Pranshul 3c372d3109 New translations strings.xml (Slovenian)
[ci skip]
2026-08-20 02:09:53 +05:30
Pranshul 8fd490d781 New translations strings.xml (Korean)
[ci skip]
2026-08-20 02:09:51 +05:30
Pranshul f3b71b4845 New translations strings.xml (Hungarian)
[ci skip]
2026-08-20 02:09:50 +05:30
Pranshul b9519e22b7 New translations strings.xml (Greek)
[ci skip]
2026-08-20 02:09:49 +05:30
Pranshul 6f16ae6d10 New translations strings.xml (German)
[ci skip]
2026-08-20 02:09:47 +05:30
Pranshul 122bf1f4f0 New translations strings.xml (Catalan)
[ci skip]
2026-08-20 02:09:46 +05:30
Pranshul dc9fca7d59 New translations strings.xml (Bulgarian)
[ci skip]
2026-08-20 02:09:44 +05:30
Pranshul 0d8bc25b4e New translations strings.xml (Romanian)
[ci skip]
2026-08-20 02:09:43 +05:30
Pranshul f965e2c2cc New translations strings.xml (Polish)
[ci skip]
2026-08-20 02:09:41 +05:30
Pranshul a97213e99b New translations strings.xml (Italian)
[ci skip]
2026-08-20 02:09:40 +05:30
Pranshul f5a68f2881 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-20 02:09:39 +05:30
Pranshul d0dc74c34b New translations strings.xml (Lithuanian)
[ci skip]
2026-08-20 02:09:37 +05:30
Pranshul 5b4991983f New translations strings.xml (French)
[ci skip]
2026-08-20 02:09:36 +05:30
Pranshul 737beffb50 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-20 02:09:35 +05:30
Pranshul d60eddc4c5 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-20 02:09:33 +05:30
Pranshul bdfc1350f7 New translations strings.xml (Turkish)
[ci skip]
2026-08-20 02:09:32 +05:30
Pranshul 59a10e71e3 New translations strings.xml (Russian)
[ci skip]
2026-08-20 02:09:30 +05:30
Pranshul 9d3cdc5df9 New translations strings.xml (Portuguese)
[ci skip]
2026-08-20 02:09:29 +05:30
Pranshul 9a3aab06f6 New translations strings.xml (Dutch)
[ci skip]
2026-08-20 02:09:28 +05:30
Pranshul a69233a026 New translations strings.xml (Japanese)
[ci skip]
2026-08-20 02:09:27 +05:30
Pranshul 2f66a4a0fd New translations strings.xml (Hebrew)
[ci skip]
2026-08-20 02:09:25 +05:30
Pranshul a7d1b8d959 New translations strings.xml (Finnish)
[ci skip]
2026-08-20 02:09:24 +05:30
Pranshul 5b85adc07d New translations strings.xml (Czech)
[ci skip]
2026-08-20 02:09:23 +05:30
Pranshul f8bf501fb3 New translations strings.xml (Spanish)
[ci skip]
2026-08-20 02:09:21 +05:30
Renan Bernordi c7660b6d62 fix duplicated merge string 2026-08-19 15:11:57 -03:00
Renan Bernordi 20ebd7b17e Merge branch 'inmet-capabilities'
# Conflicts:
#	app/src/main/java/com/pranshulgg/weather_master_app/core/di/network/ApiModule.kt
#	app/src/main/java/com/pranshulgg/weather_master_app/core/di/weather/WeatherRepositoryModule.kt
#	app/src/main/java/com/pranshulgg/weather_master_app/core/model/sources/WeatherSource.kt
#	app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/inmet/InmetApi.kt
#	app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/inmet/InmetRepository.kt
#	app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/inmet/json/InmetIbgeJson.kt
#	app/src/main/java/com/pranshulgg/weather_master_app/data/provider/SourceRepositoryProvider.kt
2026-08-19 15:10:11 -03:00
Renan Bernordi e4d3339694 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster into inmet-capabilities 2026-08-19 15:08:30 -03:00
Renan Bernordi 2ed989b619 update imet ingration 2026-08-19 15:08:28 -03:00
PranshulGG a4857fc516 fix air quality source display name in EditLocationScreen 2026-08-19 23:01:30 +05:30
PranshulGG 700c64bbfa update alert and air quality source display strings and adjust recommended source filtering logic 2026-08-19 23:00:08 +05:30
PranshulGG 9c3e5dbb97 filter recommended sources from global sources in EditLocationBottomSheet 2026-08-19 22:50:59 +05:30
PranshulGG f5db93222f update weather sources in README and metadata 2026-08-19 22:44:09 +05:30
reveler-hub dd7b5f2bc2 Only crossfade the weather screen on an actual location switch
AnimatedContent wrapping the whole screen was keyed on the full
Weather object, so every plain data refresh (a new Weather instance
every time, e.g. a changed lastUpdatedInMilli) triggered the same
full-screen fade-out/fade-in as switching to a different location -
producing a visible stutter/flash on every successful refresh, even
when nothing on screen actually needed to change.

Keyed the transition on the location id instead via AnimatedContent's
contentKey parameter: a same-location refresh now just recomposes the
changed values in place with no animation, while switching locations
still gets the intentional crossfade.
2026-08-20 05:12:51 +12:00
Pranshul 0a31a25250 Merge pull request #1047 from reveler-hub/feature/jma-weather-source
Add JMA (Japan) as a weather forecast source
2026-08-19 22:40:28 +05:30
PranshulGG c6c68c8202 remove todo comment 2026-08-19 22:40:09 +05:30
reveler-hub a252e9ac2e Compute JMA's current "feels like" temperature
AMeDAS doesn't report apparent temperature directly, so this was
hardcoded null - "Feels like -°" on every location. Wired through the
app's existing computeApparentTemperature() fallback (same convention
FMI/DWD/NWS/SMHI/etc already use for this exact gap) using AMeDAS's
own real temp/humidity/wind, since those are all genuine live
observations, not derived/forecast values.
2026-08-20 04:58:51 +12:00
reveler-hub eb4b6eff0d Address review: clear alerts/AQ via an explicit null result instead of eagerly on every fetch
PranshulGG pointed out the previous fix (resetting alerts/airQuality at
the top of every getWeather() call) caused a visible flash on every
refresh, not just a location switch, since it cleared state before
knowing whether real data was coming back.

Per his suggested approach: onAlerts/onAirQuality now always fire
(never skipped), passing null when no repository resolves for the
location's alertSource/airQualitySource instead of skipping the
callback. handleAlerts/handleAirQuality treat a null result as an
explicit "clear" signal, while a real Success/Error updates normally
exactly as before - so a location with real alerts is never touched
until the actual result arrives (no flash), and a location with no
alert source now correctly clears once that's determined, without
ever clearing eagerly beforehand.
2026-08-20 04:58:51 +12:00
PranshulGG 33d44e540b try everything to get the country code 2026-08-19 22:09:01 +05:30
PranshulGG cf124b8fe8 try everything to get the country code 2026-08-19 21:58:59 +05:30
PranshulGG ffd0e121f5 implement alert fetching logic in PirateWeatherRepository and improve null handling in HumidityBlock 2026-08-19 20:58:58 +05:30
reveler-hub 634ba26bbd Fix alerts/air quality carrying over when switching to a location with no source configured
WeatherViewModel.getWeather() reset isError/isUnsupportedSource/
isAirQualityLoading on every fetch, but never alerts or airQuality.
SourceDataRepository.getData() only invokes onAlerts/onAirQuality when
the location's alertSource/airQualitySource resolves to a real
repository - a location with alertSource == NONE (the default for
every location right now, since none of it is auto-selected on
creation) never gets a callback at all, so the previous location's
alerts/air quality stayed on screen indefinitely after switching.

Found while testing JMA's new alerts capability: switching from a
Japan location with real active alerts to one with no alert source
configured kept showing the old alerts. Reproduced and confirmed fixed
on-device.
2026-08-20 03:09:44 +12:00
reveler-hub 41b681f571 Add JMA alerts capability
JMA has its own alerts endpoint (warning/data/warning/{officeCode}.json),
keyed by the same officeCode/class10Code already resolved and cached for
the weather source, so no extra location lookup is needed. Filters out
"no warnings issued"/"cleared" statuses, maps JMA's warning-code enum to
severity (~26 codes across advisory/warning/emergency-warning tiers,
transcribed via Breezy Weather's JmaService.kt, same technique used to
find the hourly-forecast endpoint).

Tested live: Wakkanai, Japan currently has 3 active advisories
(thunderstorm, gale, dense fog), confirmed rendering correctly.
2026-08-20 03:07:11 +12:00
Pranshul d6e576d45c New translations strings.xml (Italian)
[ci skip]
2026-08-19 20:04:05 +05:30
PranshulGG 11b2755c09 implement alert fetching logic in PirateWeatherRepository and improve null handling in HumidityBlock 2026-08-19 19:56:31 +05:30
reveler-hub a7b77cc985 Add JMA (Japan Meteorological Agency) as a weather forecast source
Closes #979. Resolves each location to the nearest of JMA's 142
class10 regions and pulls real numeric hourly temp/wind from the
undocumented jmatile/data/wdist/VPFD endpoint, daily data from the
weekly forecast block, and current conditions from live AMeDAS
station observations. No API key required.
2026-08-20 00:47:12 +12:00
PranshulGG 79f61bee20 fix readme 2026-08-19 17:50:05 +05:30
PranshulGG 7b1098d936 fix readme 2026-08-19 17:49:21 +05:30
PranshulGG 5da6ab4690 humidity nullable 2026-08-19 17:42:21 +05:30
PranshulGG 74dd449600 humidity nullable 2026-08-19 17:39:48 +05:30
PranshulGG 6af2cbb3cb text field dialog ui adjustments 2026-08-19 17:29:08 +05:30
PranshulGG 987168b1e4 fix pirate Weather wind speed not being converted to canonical units 2026-08-19 17:28:45 +05:30
PranshulGG 8ac8300f29 refactor: update source architecture to support multiple capabilities from the same API 2026-08-19 16:34:04 +05:30
PranshulGG 8cd993e3d5 refactor: update source architecture to support multiple capabilities from the same API 2026-08-19 16:34:00 +05:30
PranshulGG 9c901ef2cd refactor: update source architecture to support multiple capabilities from the same API 2026-08-19 16:33:53 +05:30
PranshulGG b30c4e7418 refactor sources architecture 2026-08-19 16:31:23 +05:30
PranshulGG 149dabd82c refactor sources architecture 2026-08-19 16:31:11 +05:30
Pranshul 88f97b8980 New translations strings.xml (Italian)
[ci skip]
2026-08-19 14:00:52 +05:30
Pranshul 06626f72f0 Merge pull request #1043 from reveler-hub/fix/device-location-not-updating
Update device location on app-open and fix a leftover single-provider gate
2026-08-19 09:47:29 +05:30
Pranshul 2dc819e94c New translations strings.xml (French)
[ci skip]
2026-08-19 08:03:08 +05:30
Renan Bernordi 72c4ffbbf0 add imet integration 2026-08-18 16:10:39 -03:00
Pranshul e983fcea6e New translations strings.xml (Italian)
[ci skip]
2026-08-18 23:39:31 +05:30
Pranshul 799dc84edb New translations strings.xml (Lithuanian)
[ci skip]
2026-08-18 23:39:30 +05:30
Pranshul 3e8ee4d05e New translations strings.xml (Dutch)
[ci skip]
2026-08-18 23:39:29 +05:30
PranshulGG b229b37e93 fix secondary weather condition selection and clustering 2026-08-18 21:47:08 +05:30
reveler-hub aa69f912d6 Shorten the isInitialized guard comment 2026-08-19 03:45:17 +12:00
reveler-hub b2d7b10470 Guard ON_START refetch against duplicating the initial cold-start load
PranshulGG flagged in review that ON_START now also calling getWeather()
could duplicate the fetch setActiveLocation() already triggers during
initial VM setup. Confirmed the concern is real: DisposableEffect(location)
re-subscribes when `location` goes from null to non-null right after cold
start, and Android replays a synthetic ON_START on subscribe when the
lifecycle is already started - so that resubscription does refire ON_START.

Guarded the getWeather() call on uiState.isInitialized (only true after the
first successful fetch completes), so it now only fires on a genuine
resume-from-background, not the cold-start race. Retested both cases on
the AVD: cold start no longer double-fetches, and #1035 still resolves
correctly on reopen after moving.
2026-08-19 03:36:24 +12:00
reveler-hub b288db34f4 Update device location on app-open and fix a leftover single-provider gate closes #1035
Two related device-location bugs found while investigating #1035:

- WeatherViewModel only checked/refreshed the device location on manual
  pull-to-refresh (isManualRefresh gate), never on app-open, the 45-min
  auto-refresh timer, or app-resume from background. Decoupled the check
  from isManualRefresh so it always runs for a device-location entry, and
  forces a real refetch (via isForceRefresh, not isManualRefresh, which
  would still hit the 15-min throttle) only when the position actually
  moved. Also wired an immediate check into WeatherAutoRefreshForeground's
  existing ON_START observer, since that's the only hook that already
  fires on every foreground-resume, not just cold start.

- DeviceLocationProvider.getDeviceLocation() still gated on the old
  single-provider selection (getProvider(), preferring NETWORK_PROVIDER)
  before ever reaching the dual-provider live-request logic added in the
  #938 fix. If that one provider happened to be present-but-disabled
  (e.g. "Device only" location mode, or no GMS/network-location backend),
  it failed instantly without ever trying GPS. Removed the stale gate.

Tested on an AVD: reproduced #1035 (background app, move >1000m, reopen
without refreshing -> location stayed stale), then confirmed the fix
resolves it end-to-end (name, coordinates, and weather data all update
on reopen, no manual refresh needed). Also confirmed the provider-gate
fix resolves an instant "Current location not found" on a device with
NETWORK_PROVIDER disabled but GPS enabled.
2026-08-19 02:56:09 +12:00
PranshulGG a08f76c261 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-08-18 20:23:46 +05:30
Pranshul 204c10c1d0 Merge pull request #1033 from PranshulGG/l10n_main
New Crowdin updates
2026-08-18 20:23:28 +05:30
Pranshul 3c0d720441 Merge branch 'main' into l10n_main
Signed-off-by: Pranshul <pranshul.devmain@gmail.com>
2026-08-18 20:23:18 +05:30
PranshulGG 69daeab654 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-08-18 20:17:30 +05:30
PranshulGG 8cb340127a add TODO for safeApiCall 2026-08-18 20:17:01 +05:30
Pranshul 1754f87005 Merge pull request #1041 from altendorfme/main
Add Pirate Weather (Global Coverage) source
2026-08-18 20:16:23 +05:30
Renan Bernordi 7ae657049d remove pirate weather alert api 2026-08-18 11:33:10 -03:00
Renan Bernordi 7f3dc42fbb Merge remote-tracking branch 'upstream/main'
# Conflicts:
#	app/src/main/java/com/pranshulgg/weather_master_app/core/di/network/ApiModule.kt
#	app/src/main/java/com/pranshulgg/weather_master_app/core/di/weather/WeatherRepositoryModule.kt
#	app/src/main/java/com/pranshulgg/weather_master_app/data/provider/WeatherRepositoryProvider.kt
2026-08-18 11:26:35 -03:00
Renan Bernordi 4c3f453e02 add pirate weather integration 2026-08-18 10:57:04 -03:00
Pranshul b05419b6a7 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-18 17:38:47 +05:30
Pranshul 933c194fce New translations strings.xml (German)
[ci skip]
2026-08-18 17:38:46 +05:30
Pranshul 74dc479417 New translations strings.xml (French)
[ci skip]
2026-08-18 17:38:44 +05:30
Pranshul 8dd4807e34 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-18 17:38:43 +05:30
Pranshul 336ae18f11 New translations strings.xml (Russian)
[ci skip]
2026-08-18 17:38:42 +05:30
Pranshul f6d084382e New translations strings.xml (Spanish)
[ci skip]
2026-08-18 17:38:40 +05:30
PranshulGG 47fa36dbe5 fix Pressure screen shows wrong values closes #1040 2026-08-18 13:07:41 +05:30
PranshulGG 635f1fa239 fix open-meteo errors on some models closes #1039 2026-08-18 12:26:56 +05:30
Pranshul c051980c9f New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-18 11:37:41 +05:30
Pranshul e15c44a98a New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-18 11:37:40 +05:30
Pranshul 12f8d2bb40 New translations strings.xml (Filipino)
[ci skip]
2026-08-18 11:37:38 +05:30
Pranshul eeb4e0b81e New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-18 11:37:37 +05:30
Pranshul 30415e3bf3 New translations strings.xml (Kazakh)
[ci skip]
2026-08-18 11:37:36 +05:30
Pranshul b0ea149de3 New translations strings.xml (Thai)
[ci skip]
2026-08-18 11:37:35 +05:30
Pranshul 761528e7fd New translations strings.xml (Persian)
[ci skip]
2026-08-18 11:37:33 +05:30
Pranshul 9b83b2f48b New translations strings.xml (Indonesian)
[ci skip]
2026-08-18 11:37:32 +05:30
Pranshul ca5819bffe New translations strings.xml (Vietnamese)
[ci skip]
2026-08-18 11:37:30 +05:30
Pranshul b4d322a62e New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-18 11:37:29 +05:30
Pranshul 24fcc6b80c New translations strings.xml (Swedish)
[ci skip]
2026-08-18 11:37:28 +05:30
Pranshul 3a33ae0e4d New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-18 11:37:26 +05:30
Pranshul a33890777a New translations strings.xml (Slovenian)
[ci skip]
2026-08-18 11:37:25 +05:30
Pranshul 8a204a7630 New translations strings.xml (Korean)
[ci skip]
2026-08-18 11:37:24 +05:30
Pranshul e3404a0740 New translations strings.xml (Hungarian)
[ci skip]
2026-08-18 11:37:23 +05:30
Pranshul fb04e7d55c New translations strings.xml (Greek)
[ci skip]
2026-08-18 11:37:21 +05:30
Pranshul 021e3159f0 New translations strings.xml (German)
[ci skip]
2026-08-18 11:37:20 +05:30
Pranshul 987251e1eb New translations strings.xml (Catalan)
[ci skip]
2026-08-18 11:37:19 +05:30
Pranshul de85bd83f8 New translations strings.xml (Bulgarian)
[ci skip]
2026-08-18 11:37:17 +05:30
Pranshul ac757c0ff6 New translations strings.xml (Romanian)
[ci skip]
2026-08-18 11:37:16 +05:30
Pranshul 92a701947e New translations strings.xml (Polish)
[ci skip]
2026-08-18 11:37:15 +05:30
Pranshul 49af5f20ad New translations strings.xml (Italian)
[ci skip]
2026-08-18 11:37:13 +05:30
Pranshul 93a023a3ee New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-18 11:37:12 +05:30
Pranshul 6131b8de09 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-18 11:37:11 +05:30
Pranshul d712175d7f New translations strings.xml (French)
[ci skip]
2026-08-18 11:37:09 +05:30
Pranshul aa43bdd420 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-18 11:37:08 +05:30
Pranshul 07bc22d669 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-18 11:37:07 +05:30
Pranshul 99d0f0aa6e New translations strings.xml (Turkish)
[ci skip]
2026-08-18 11:37:05 +05:30
Pranshul 49c4977fbf New translations strings.xml (Russian)
[ci skip]
2026-08-18 11:37:04 +05:30
Pranshul 34578f67a4 New translations strings.xml (Portuguese)
[ci skip]
2026-08-18 11:37:03 +05:30
Pranshul 3cdebbfec1 New translations strings.xml (Dutch)
[ci skip]
2026-08-18 11:37:01 +05:30
Pranshul 6e1166d0c3 New translations strings.xml (Japanese)
[ci skip]
2026-08-18 11:37:00 +05:30
Pranshul ab647903d5 New translations strings.xml (Hebrew)
[ci skip]
2026-08-18 11:36:59 +05:30
Pranshul eddd7607d9 New translations strings.xml (Finnish)
[ci skip]
2026-08-18 11:36:57 +05:30
Pranshul 975d44eecc New translations strings.xml (Czech)
[ci skip]
2026-08-18 11:36:56 +05:30
Pranshul 2554c234b8 New translations strings.xml (Spanish)
[ci skip]
2026-08-18 11:36:55 +05:30
PranshulGG 6886eb193e Fix app not being able to find current location closes #938 2026-08-18 09:51:56 +05:30
Pranshul ca0b887444 Merge pull request #1038 from reveler-hub/fix/onboarding-nominatim-crash
Guard onboarding location lookup against Nominatim failures
2026-08-18 09:38:56 +05:30
Pranshul b956d53cb6 Merge pull request #1036 from reveler-hub/feature/cwa-weather-source
Add CWA (Taiwan) as a weather forecast source
2026-08-18 09:38:04 +05:30
PranshulGG 2179d265b1 remove error_server from strings.xml 2026-08-18 08:16:11 +05:30
PranshulGG 117f441329 update MeteoFrance condition mapping for hail and sleet 2026-08-18 08:15:41 +05:30
Pranshul 5958c621fd New translations strings.xml (Hebrew)
[ci skip]
2026-08-18 05:19:20 +05:30
Pranshul 40e32687f9 New translations strings.xml (Italian)
[ci skip]
2026-08-17 23:07:56 +05:30
Pranshul c64b79e63a New translations strings.xml (Finnish)
[ci skip]
2026-08-17 23:07:54 +05:30
PranshulGG 1f805b96a0 refactor error handling for all sources #1037 2026-08-17 21:33:43 +05:30
reveler-hub d38b18eab0 Guard onboarding location lookup against Nominatim failures closes #986 closes #968
The location setup screen's reverse-geocoding call had no fallback,
so an unreachable Nominatim request crashed the screen instead of
falling back to the coordinates, same failure mode already fixed for
two other call sites in #960.
2026-08-17 23:51:46 +12:00
Pranshul 3dfa6fe17d New translations strings.xml (Polish)
[ci skip]
2026-08-17 16:20:58 +05:30
Pranshul f16b9b57bc New translations strings.xml (Italian)
[ci skip]
2026-08-17 16:20:57 +05:30
Pranshul 576695095f New translations strings.xml (Finnish)
[ci skip]
2026-08-17 16:20:55 +05:30
Pranshul 691ff5939c New translations strings.xml (Czech)
[ci skip]
2026-08-17 16:20:54 +05:30
reveler-hub 46a7cef502 Merge remote-tracking branch 'origin/main' 2026-08-17 22:33:20 +12:00
PranshulGG ff8e76d004 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-08-17 16:00:15 +05:30
PranshulGG c3a394470b Update isApiKeyAvailable to handle weather sources not requiring user API keys 2026-08-17 16:00:03 +05:30
Pranshul 9be2dcb168 Merge pull request #1034 from hydrielax/main
Localize AccuWeather Alerts and date/times
2026-08-17 15:59:59 +05:30
Pranshul c7d8077c65 New translations strings.xml (Finnish)
[ci skip]
2026-08-17 10:04:30 +05:30
Pranshul 808967c66a New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-17 03:24:24 +05:30
Pranshul a179ab884d New translations strings.xml (Lithuanian)
[ci skip]
2026-08-17 03:24:23 +05:30
Pranshul 6d5bcb79a9 New translations strings.xml (French)
[ci skip]
2026-08-17 03:24:21 +05:30
Pranshul 122d2be099 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-17 03:24:20 +05:30
Alexis Delage 9255fdb0d0 fix: use localized dates 2026-08-16 18:06:32 +02:00
Alexis Delage 55d534bd8e fix: use localized times for 12 and 24 hours patterns 2026-08-16 18:06:32 +02:00
Alexis Delage 15145ab7cc fix: use localized date-times in alerts 2026-08-16 18:06:32 +02:00
Alexis Delage d708ed1290 fix: use localized text for AccuWeather alerts 2026-08-16 18:06:32 +02:00
Pranshul 2126be8a0a New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-16 21:17:26 +05:30
Pranshul 7f3bb87551 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-16 21:17:25 +05:30
Pranshul ca1328418e New translations strings.xml (Turkish)
[ci skip]
2026-08-16 21:17:23 +05:30
Pranshul 5ca4d5a52d New translations strings.xml (Russian)
[ci skip]
2026-08-16 21:17:22 +05:30
Pranshul 18ff6e1357 New translations strings.xml (Portuguese)
[ci skip]
2026-08-16 21:17:21 +05:30
Pranshul 0233af3c71 New translations strings.xml (Dutch)
[ci skip]
2026-08-16 21:17:20 +05:30
Pranshul 31cdeab3b9 New translations strings.xml (Japanese)
[ci skip]
2026-08-16 21:17:18 +05:30
Pranshul 95da6977cd New translations strings.xml (Hebrew)
[ci skip]
2026-08-16 21:17:17 +05:30
Pranshul fd13b4a4b5 New translations strings.xml (Finnish)
[ci skip]
2026-08-16 21:17:15 +05:30
Pranshul 411ac69118 New translations strings.xml (Czech)
[ci skip]
2026-08-16 21:17:14 +05:30
Pranshul d2242187fc New translations strings.xml (Spanish)
[ci skip]
2026-08-16 21:17:13 +05:30
reveler-hub 48b5e1b92f Merge remote-tracking branch 'origin/main' into main 2026-08-17 02:42:26 +12:00
reveler-hub 7f76a2ec6a Add CWA (Taiwan) as a weather forecast source closes #1003
Adds Central Weather Administration as a new per-country WeatherSource,
following the AEMET/IPMA pattern: user-supplied API key, two-level
location resolution (nationwide county lookup, then per-county township
lookup) cached via the existing LocationKeysDao as a composite string,
and generic AppException handling for missing/rejected keys.
2026-08-17 02:42:17 +12:00
PranshulGG 1e7b23b0a0 Update README and metadata with WMO and FOSS weather sources 2026-08-16 20:06:20 +05:30
PranshulGG c57cf08395 bump version 2026-08-16 16:54:18 +05:30
PranshulGG 987c02cf4a fix db crash 2026-08-16 16:53:40 +05:30
PranshulGG 6cac8835ab update weather sources list in README and metadata and refresh screenshots 2026-08-16 16:39:50 +05:30
PranshulGG 92ff8f2e64 fix logic for displaying Open-Meteo model name 2026-08-16 16:09:48 +05:30
PranshulGG 05e683582d fix descriptions 2026-08-16 15:59:05 +05:30
PranshulGG d94496193e Update setup-java action to v5 in release.yml 2026-08-16 15:38:31 +05:30
PranshulGG b972f5ca6c add WEATHERAPI_KEY to release workflow 2026-08-16 15:29:39 +05:30
PranshulGG 14b6e0559e bump version and add changelog 2026-08-16 15:26:58 +05:30
PranshulGG 8a83032278 fix translations 2026-08-16 15:25:51 +05:30
PranshulGG 232e1494b8 fix translations 2026-08-16 15:25:44 +05:30
PranshulGG 4e698f21e9 rename headlineContent to content 2026-08-16 15:00:14 +05:30
PranshulGG a156da9ac9 minimal nav animations 2026-08-16 14:31:27 +05:30
PranshulGG 671b057d7c fix few edge cases 2026-08-16 14:23:08 +05:30
PranshulGG fc4cfba8b3 weather auto refreshes until the app is in foreground closes #1026 2026-08-16 13:59:46 +05:30
PranshulGG cac518ffbb fixed weather block glitches during arrangement 2026-08-16 13:58:04 +05:30
PranshulGG b35e1eb202 date format based on the app locale #744 2026-08-16 12:55:49 +05:30
PranshulGG d5a2b30ce2 date format based on the app locale closes #744 2026-08-16 12:53:16 +05:30
PranshulGG 2ecd3352b5 guard nominatim if fails #960 2026-08-16 09:04:43 +05:30
Pranshul 02512d938c Merge pull request #1032 from PranshulGG/l10n_main
New Crowdin updates
2026-08-16 08:52:46 +05:30
Pranshul a96556bfc1 Merge pull request #1029 from reveler-hub/fix/small-ui-polish
Fix search-result casing and block-screen transition timing
2026-08-16 08:52:12 +05:30
Pranshul 4b90d96442 Merge branch 'main' into fix/small-ui-polish
Signed-off-by: Pranshul <pranshul.devmain@gmail.com>
2026-08-16 08:52:04 +05:30
Pranshul 423e3f911a New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-16 08:44:26 +05:30
Pranshul edb29fc177 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-16 08:44:25 +05:30
Pranshul 4eaad73181 New translations strings.xml (Filipino)
[ci skip]
2026-08-16 08:44:24 +05:30
Pranshul 07d78bb283 New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-16 08:44:23 +05:30
Pranshul eb2b47e19d New translations strings.xml (Kazakh)
[ci skip]
2026-08-16 08:44:21 +05:30
Pranshul 01db325285 New translations strings.xml (Thai)
[ci skip]
2026-08-16 08:44:20 +05:30
Pranshul 4db9829762 New translations strings.xml (Persian)
[ci skip]
2026-08-16 08:44:19 +05:30
Pranshul b9144d8778 New translations strings.xml (Indonesian)
[ci skip]
2026-08-16 08:44:18 +05:30
Pranshul 687b5c04af New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-16 08:44:17 +05:30
Pranshul a995278311 New translations strings.xml (Vietnamese)
[ci skip]
2026-08-16 08:44:15 +05:30
Pranshul ada9b23b33 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-16 08:44:14 +05:30
Pranshul c62bbbdfda New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-16 08:44:13 +05:30
Pranshul 263de7cb92 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-16 08:44:12 +05:30
Pranshul c47e8becbe New translations strings.xml (Turkish)
[ci skip]
2026-08-16 08:44:10 +05:30
Pranshul 1766273e07 New translations strings.xml (Swedish)
[ci skip]
2026-08-16 08:44:09 +05:30
Pranshul c9fea5a682 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-16 08:44:08 +05:30
Pranshul 0d0ae42785 New translations strings.xml (Slovenian)
[ci skip]
2026-08-16 08:44:07 +05:30
Pranshul a29281cd3e New translations strings.xml (Russian)
[ci skip]
2026-08-16 08:44:05 +05:30
Pranshul 0cf6937a96 New translations strings.xml (Portuguese)
[ci skip]
2026-08-16 08:44:04 +05:30
Pranshul be93c85d84 New translations strings.xml (Polish)
[ci skip]
2026-08-16 08:44:03 +05:30
Pranshul 8c33c06705 New translations strings.xml (Dutch)
[ci skip]
2026-08-16 08:44:02 +05:30
Pranshul 43a7000dd4 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-16 08:44:01 +05:30
Pranshul a55f29403a New translations strings.xml (Korean)
[ci skip]
2026-08-16 08:43:59 +05:30
Pranshul 149e98a4cd New translations strings.xml (Japanese)
[ci skip]
2026-08-16 08:43:58 +05:30
Pranshul 4c63584965 New translations strings.xml (Italian)
[ci skip]
2026-08-16 08:43:57 +05:30
Pranshul 278bed5583 New translations strings.xml (Hungarian)
[ci skip]
2026-08-16 08:43:56 +05:30
Pranshul 504c6d7cbc New translations strings.xml (Hebrew)
[ci skip]
2026-08-16 08:43:55 +05:30
Pranshul da46882a00 New translations strings.xml (Finnish)
[ci skip]
2026-08-16 08:43:53 +05:30
Pranshul 9aef395cd7 New translations strings.xml (Greek)
[ci skip]
2026-08-16 08:43:52 +05:30
Pranshul 5bd56547f4 New translations strings.xml (German)
[ci skip]
2026-08-16 08:43:51 +05:30
Pranshul 0f500a2413 New translations strings.xml (Czech)
[ci skip]
2026-08-16 08:43:50 +05:30
Pranshul 7fe34d5b3f New translations strings.xml (Catalan)
[ci skip]
2026-08-16 08:43:49 +05:30
Pranshul 38227c2c10 New translations strings.xml (Bulgarian)
[ci skip]
2026-08-16 08:43:48 +05:30
Pranshul 462ea6667a New translations strings.xml (Spanish)
[ci skip]
2026-08-16 08:43:46 +05:30
Pranshul 6d03757260 New translations strings.xml (French)
[ci skip]
2026-08-16 08:43:45 +05:30
Pranshul c2455851be New translations strings.xml (Romanian)
[ci skip]
2026-08-16 08:43:44 +05:30
Pranshul 84f952a05e Merge pull request #1030 from reveler-hub/feature/aemet-weather-source
Add AEMET as a weather forecast source
2026-08-16 08:41:28 +05:30
reveler-hub 416e3b11e5 Merge remote-tracking branch 'origin/main' into feature/aemet-weather-source
# Conflicts:
#	app/src/main/java/com/pranshulgg/weather_master_app/core/di/network/ApiModule.kt
#	app/src/main/java/com/pranshulgg/weather_master_app/core/di/weather/WeatherRepositoryModule.kt
#	app/src/main/java/com/pranshulgg/weather_master_app/core/model/domain/AppExceptions.kt
#	app/src/main/java/com/pranshulgg/weather_master_app/core/model/sources/WeatherSource.kt
#	app/src/main/java/com/pranshulgg/weather_master_app/data/provider/WeatherRepositoryProvider.kt
2026-08-16 05:19:04 +12:00
Pranshul ead98a797a Merge pull request #1028 from PranshulGG/l10n_main
New Crowdin updates
2026-08-15 21:32:56 +05:30
PranshulGG 1deb842442 fix nullability in FpasRepository cache 2026-08-15 21:24:16 +05:30
PranshulGG dc246bae8d add option to config Weather 4 widget date format closes #1018 2026-08-15 21:23:41 +05:30
reveler-hub e8b435f16c Rework AEMET key handling to reuse the existing error/Snackbar path
Per review feedback on this PR: the previous approach (a new
StatusBanner component, a persistent main-screen banner, live
validation on save, savedAt/expiry tracking) was AEMET-specific UI
behavior that wouldn't generalize to other keyed sources.

- Removed StatusBanner, the persistent banners, validateApiKey(),
  and the savedAt/isNearExpiry mechanism entirely (DB back to v55).
- AemetRepository now just fetches/resolves/returns like every
  other repository. A rejected key surfaces naturally as a 401 from
  AEMET during a normal fetch, thrown as a new shared
  AppException.ApiKeyRejectedError - the same WeatherResult.Error ->
  AppException -> SnackbarManager path every other error already
  uses, so any future keyed source gets this for free.

Tested on-device: bad key, no key, and (once restored) a valid key
all behave correctly through the existing Snackbar.
2026-08-16 03:51:03 +12:00
PranshulGG afc91ad4d3 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-08-15 20:50:37 +05:30
Pranshul 480715a9ae New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-15 19:56:09 +05:30
Pranshul c90ba47abb New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-15 19:56:08 +05:30
Pranshul 94d087b50b New translations strings.xml (Filipino)
[ci skip]
2026-08-15 19:56:07 +05:30
Pranshul 7831a8cb4f New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-15 19:56:06 +05:30
Pranshul c596930652 New translations strings.xml (Kazakh)
[ci skip]
2026-08-15 19:56:05 +05:30
Pranshul 06d8940c21 New translations strings.xml (Thai)
[ci skip]
2026-08-15 19:56:03 +05:30
Pranshul a43471f364 New translations strings.xml (Persian)
[ci skip]
2026-08-15 19:56:02 +05:30
Pranshul 6bc5369b1f New translations strings.xml (Indonesian)
[ci skip]
2026-08-15 19:56:01 +05:30
Pranshul bc763e1ce0 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-15 19:55:59 +05:30
Pranshul 97411bd233 New translations strings.xml (Vietnamese)
[ci skip]
2026-08-15 19:55:58 +05:30
Pranshul 3f9ca5a196 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-15 19:55:57 +05:30
Pranshul e8cc19431c New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-15 19:55:55 +05:30
Pranshul 66b11641b9 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-15 19:55:54 +05:30
Pranshul bbcdfd6e4b New translations strings.xml (Turkish)
[ci skip]
2026-08-15 19:55:53 +05:30
Pranshul 6cfcf4a922 New translations strings.xml (Swedish)
[ci skip]
2026-08-15 19:55:52 +05:30
Pranshul 6a1b5e188f New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-15 19:55:51 +05:30
Pranshul fe903ca96a New translations strings.xml (Slovenian)
[ci skip]
2026-08-15 19:55:50 +05:30
Pranshul ca27a85bf9 New translations strings.xml (Russian)
[ci skip]
2026-08-15 19:55:48 +05:30
Pranshul 9ee3618e81 New translations strings.xml (Portuguese)
[ci skip]
2026-08-15 19:55:47 +05:30
Pranshul bebe346e42 New translations strings.xml (Polish)
[ci skip]
2026-08-15 19:55:46 +05:30
Pranshul 43f09dd806 New translations strings.xml (Dutch)
[ci skip]
2026-08-15 19:55:44 +05:30
Pranshul df8c79261b New translations strings.xml (Lithuanian)
[ci skip]
2026-08-15 19:55:43 +05:30
Pranshul a13a9a3644 New translations strings.xml (Korean)
[ci skip]
2026-08-15 19:55:42 +05:30
Pranshul 549cd9e297 New translations strings.xml (Japanese)
[ci skip]
2026-08-15 19:55:41 +05:30
Pranshul f24f10e14a New translations strings.xml (Italian)
[ci skip]
2026-08-15 19:55:39 +05:30
Pranshul 29400f412c New translations strings.xml (Hungarian)
[ci skip]
2026-08-15 19:55:38 +05:30
Pranshul e03a719560 New translations strings.xml (Hebrew)
[ci skip]
2026-08-15 19:55:37 +05:30
Pranshul 26eeab05d3 New translations strings.xml (Finnish)
[ci skip]
2026-08-15 19:55:36 +05:30
Pranshul c97012b47f New translations strings.xml (Greek)
[ci skip]
2026-08-15 19:55:35 +05:30
Pranshul cc00107c23 New translations strings.xml (German)
[ci skip]
2026-08-15 19:55:33 +05:30
Pranshul c33e586290 New translations strings.xml (Czech)
[ci skip]
2026-08-15 19:55:32 +05:30
Pranshul 3e71d01a44 New translations strings.xml (Catalan)
[ci skip]
2026-08-15 19:55:31 +05:30
Pranshul bc2d800cac New translations strings.xml (Bulgarian)
[ci skip]
2026-08-15 19:55:30 +05:30
Pranshul ffa4549121 New translations strings.xml (Spanish)
[ci skip]
2026-08-15 19:55:29 +05:30
Pranshul e6a6dbf820 New translations strings.xml (French)
[ci skip]
2026-08-15 19:55:27 +05:30
Pranshul 517c074074 New translations strings.xml (Romanian)
[ci skip]
2026-08-15 19:55:26 +05:30
PranshulGG 404ac6ba0b update db 2026-08-15 19:35:13 +05:30
reveler-hub 82326f0bed Update README's supported weather sources list
AEMET (this PR), plus Met Office and Gismeteo, which were both added
in earlier commits but never made it into the README's source list.
Also notes which sources need a user-supplied API key and links to
each provider's sign-up page.
2026-08-16 00:39:37 +12:00
PranshulGG 64eb2cac31 update db 2026-08-15 18:03:18 +05:30
PranshulGG 98bb99d164 toggle button shapes 2026-08-15 18:03:05 +05:30
PranshulGG 477f327ad1 filter future hourly data 2026-08-15 18:02:46 +05:30
PranshulGG 36f532d171 fix keep past hours 2026-08-15 18:01:30 +05:30
reveler-hub 318605edc6 Add AEMET as a weather forecast source
Adds AEMET (Spain's national weather service) as a new WeatherSource
alongside existing national-service sources like DWD/IPMA/Met Office,
following the same per-country pattern and reusing the generic
API-key infrastructure.

- AemetApi/AemetRepository handle AEMET's two-step fetch (envelope
  with a datos URL, then a second unauthenticated request for the
  actual body) and its ISO-8859-15 response charset.
- Municipio-code resolution (AEMET needs a 5-digit INE code, not
  lat/lon) mirrors IpmaRepository's pattern: resolve once via
  /maestro/municipios, cache the result in the existing
  LocationKeysDao.
- AemetWeatherConditionMap + AemetJsonMapper normalize AEMET's
  estadoCielo codes and Spanish wind-direction letters into the
  app's domain model.
- API keys now track a savedAt timestamp (generic across all keyed
  sources, DB migration v55->v56). Saving an AEMET key now does a
  live check against AEMET before accepting it, showing a
  valid/invalid result banner in the config screen. Past ~3 months,
  the app re-confirms the key still works (rather than just
  guessing from elapsed time) before warning the user - a
  persistent banner on the main screen plus a note in the API key
  config screen, both using a new shared StatusBanner component.

Discussed in #1023.
2026-08-15 23:43:54 +12:00
reveler-hub 92ea801617 Fix search-result casing and block-screen transition timing
Two small unrelated UI fixes found while testing:

- Search result descriptions passed provider country/state names
  straight through with no capitalization handling. Providers could
  potentially show names without capital letters, or verbatim,
  since they are inconsistent about casing. Now title-cased
  defensively on display via a new String.toTitleCase() extension.
- Block-screen navigation transitions (UV index, air quality, etc.)
  had a small but noticeable delay: the fade used an explicit
  350ms/200ms tween, but the paired slide had no animationSpec, so
  it defaulted to a spring with different timing than the fade.
  Both now use the same explicit tween.

Also bundles the Gradle/AGP/KSP version bump Android Studio applied
on project import (Gradle 9.4.1->9.7.0, AGP 9.2.1->9.3.1, KSP
2.3.4->2.3.6), restoring the wrapper's distributionSha256Sum that
the auto-bump dropped.
2026-08-15 23:07:24 +12:00
Pranshul cc3e4810ab Merge pull request #1027 from reveler-hub/fix/fpas-alert-locale
Fix FPAS alerts to respect app language
2026-08-15 16:07:43 +05:30
PranshulGG a959cd93c4 update app exception 2026-08-15 16:07:03 +05:30
PranshulGG da373ba486 update dependencies 2026-08-15 16:06:51 +05:30
PranshulGG 78d783621b missing strings 2026-08-15 16:06:27 +05:30
PranshulGG 8980ece8df update nws conditions 2026-08-15 16:06:20 +05:30
PranshulGG a70551086e update BottomSheet state management 2026-08-15 16:06:03 +05:30
PranshulGG 462c497d2e add imd closes #935 closes #628 closes #391 2026-08-15 16:05:12 +05:30
Pranshul 45efc578b7 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-15 13:22:54 +05:30
Pranshul 2bb718b1e0 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-15 13:22:52 +05:30
Pranshul 11b686dd32 New translations strings.xml (Filipino)
[ci skip]
2026-08-15 13:22:51 +05:30
Pranshul 768eb83ce4 New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-15 13:22:50 +05:30
Pranshul b061e4bf76 New translations strings.xml (Kazakh)
[ci skip]
2026-08-15 13:22:49 +05:30
Pranshul 1a20a3056b New translations strings.xml (Thai)
[ci skip]
2026-08-15 13:22:48 +05:30
Pranshul 122836514c New translations strings.xml (Persian)
[ci skip]
2026-08-15 13:22:47 +05:30
Pranshul 2ee19a73be New translations strings.xml (Indonesian)
[ci skip]
2026-08-15 13:22:45 +05:30
Pranshul 87cfc62522 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-15 13:22:44 +05:30
Pranshul 0e9da04449 New translations strings.xml (Vietnamese)
[ci skip]
2026-08-15 13:22:43 +05:30
Pranshul 691b9f72a3 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-15 13:22:42 +05:30
Pranshul 1703aeeb0f New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-15 13:22:41 +05:30
Pranshul 05203c989e New translations strings.xml (Ukrainian)
[ci skip]
2026-08-15 13:22:39 +05:30
Pranshul 0bc2cc706d New translations strings.xml (Turkish)
[ci skip]
2026-08-15 13:22:38 +05:30
Pranshul e02523bfe9 New translations strings.xml (Swedish)
[ci skip]
2026-08-15 13:22:37 +05:30
Pranshul c4899a4b0e New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-15 13:22:36 +05:30
Pranshul adf58defef New translations strings.xml (Slovenian)
[ci skip]
2026-08-15 13:22:35 +05:30
Pranshul d69935beb5 New translations strings.xml (Russian)
[ci skip]
2026-08-15 13:22:33 +05:30
Pranshul e61c8602ab New translations strings.xml (Portuguese)
[ci skip]
2026-08-15 13:22:32 +05:30
Pranshul 8a3c59ee3e New translations strings.xml (Polish)
[ci skip]
2026-08-15 13:22:31 +05:30
Pranshul d64fde385b New translations strings.xml (Dutch)
[ci skip]
2026-08-15 13:22:30 +05:30
Pranshul 479499c438 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-15 13:22:29 +05:30
Pranshul 9ece78fa76 New translations strings.xml (Korean)
[ci skip]
2026-08-15 13:22:27 +05:30
Pranshul baab941181 New translations strings.xml (Japanese)
[ci skip]
2026-08-15 13:22:26 +05:30
Pranshul 51e04f82d9 New translations strings.xml (Italian)
[ci skip]
2026-08-15 13:22:25 +05:30
Pranshul 92e58fd3a2 New translations strings.xml (Hungarian)
[ci skip]
2026-08-15 13:22:24 +05:30
Pranshul af0b5ce5b0 New translations strings.xml (Hebrew)
[ci skip]
2026-08-15 13:22:22 +05:30
Pranshul ae22fef9e8 New translations strings.xml (Finnish)
[ci skip]
2026-08-15 13:22:21 +05:30
Pranshul 64313a2619 New translations strings.xml (Greek)
[ci skip]
2026-08-15 13:22:20 +05:30
Pranshul bb3d218e5c New translations strings.xml (German)
[ci skip]
2026-08-15 13:22:19 +05:30
Pranshul 6011cb57e6 New translations strings.xml (Czech)
[ci skip]
2026-08-15 13:22:18 +05:30
Pranshul 703b6241a5 New translations strings.xml (Catalan)
[ci skip]
2026-08-15 13:22:16 +05:30
Pranshul 4483fca7f0 New translations strings.xml (Bulgarian)
[ci skip]
2026-08-15 13:22:15 +05:30
Pranshul 4e4235df66 New translations strings.xml (Spanish)
[ci skip]
2026-08-15 13:22:14 +05:30
Pranshul 08f72f283b New translations strings.xml (French)
[ci skip]
2026-08-15 13:22:13 +05:30
Pranshul 5ae561681a New translations strings.xml (Romanian)
[ci skip]
2026-08-15 13:22:12 +05:30
reveler-hub c5b6222c41 Fix FPAS alerts to respect app language for multilingual CAP messages 2026-08-15 17:17:39 +12:00
PranshulGG b3d46603c9 drawable and missin strings 2026-08-15 10:33:09 +05:30
PranshulGG 457aa1ed42 clean stuff 2026-08-15 10:32:51 +05:30
PranshulGG 15c5353e70 add link for api config 2026-08-15 10:32:39 +05:30
PranshulGG b9373e8610 fix app exceptions 2026-08-15 10:32:20 +05:30
PranshulGG 97fd260333 more strings 2026-08-15 08:55:48 +05:30
Pranshul 3839dd6446 Merge pull request #1025 from PranshulGG/l10n_main
New Crowdin updates
2026-08-15 08:46:48 +05:30
PranshulGG 32c1a8cdcf fix text overflow 2026-08-15 08:44:39 +05:30
PranshulGG 3c2507a4a4 improve search 2026-08-15 08:43:48 +05:30
PranshulGG c64745d883 update db 2026-08-15 08:42:01 +05:30
PranshulGG e595a178cd clean up 2026-08-15 08:41:50 +05:30
PranshulGG 4d04f61356 past hours 2026-08-15 08:41:32 +05:30
PranshulGG 0cf8b9cb14 fix hourly forecasts 2026-08-15 08:41:21 +05:30
PranshulGG ca987ea01a cleanup 2026-08-15 08:40:49 +05:30
PranshulGG ce94ca03a9 add sleet, hail, mixed precip 2026-08-15 08:39:47 +05:30
PranshulGG f4cec63a20 get current time util 2026-08-15 08:39:26 +05:30
PranshulGG ff7498fff5 add met office 2026-08-15 08:38:59 +05:30
PranshulGG ffe5365f7b option to allow users to add their own api keys 2026-08-15 08:38:07 +05:30
PranshulGG baca28f67d keep cached past hours 2026-08-15 08:37:29 +05:30
Pranshul bf153b9b5d New translations strings.xml (Ukrainian)
[ci skip]
2026-08-15 07:27:05 +05:30
Pranshul 27de0caae2 New translations strings.xml (Turkish)
[ci skip]
2026-08-15 07:27:04 +05:30
Pranshul d6b536145f New translations strings.xml (Hungarian)
[ci skip]
2026-08-15 07:27:03 +05:30
Pranshul d90e2f46bb New translations strings.xml (Ukrainian)
[ci skip]
2026-08-15 00:54:57 +05:30
Pranshul b8b22aaf0f New translations strings.xml (Russian)
[ci skip]
2026-08-15 00:54:56 +05:30
Pranshul 3877bf8fe9 New translations strings.xml (Hungarian)
[ci skip]
2026-08-15 00:54:54 +05:30
Pranshul c9985050e7 New translations strings.xml (Indonesian)
[ci skip]
2026-08-14 18:41:04 +05:30
Pranshul 66e9c8210f New translations strings.xml (Ukrainian)
[ci skip]
2026-08-14 18:41:03 +05:30
Pranshul 354ce2c927 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-14 18:41:02 +05:30
Pranshul 4410e0914b New translations strings.xml (Korean)
[ci skip]
2026-08-14 12:19:23 +05:30
Pranshul c0b3cbb1e6 New translations strings.xml (Finnish)
[ci skip]
2026-08-14 12:19:21 +05:30
Pranshul ce2a10cc05 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-13 23:22:38 +05:30
Pranshul bd7bf5aaa7 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-13 23:22:36 +05:30
Pranshul 3296ded4d4 New translations strings.xml (Filipino)
[ci skip]
2026-08-13 23:22:35 +05:30
Pranshul 62b0481fd0 New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-13 23:22:33 +05:30
Pranshul 142395f6f4 New translations strings.xml (Kazakh)
[ci skip]
2026-08-13 23:22:32 +05:30
Pranshul 022e74a67f New translations strings.xml (Thai)
[ci skip]
2026-08-13 23:22:31 +05:30
Pranshul 8c1087e17e New translations strings.xml (Persian)
[ci skip]
2026-08-13 23:22:29 +05:30
Pranshul 1ad71b45ae New translations strings.xml (Indonesian)
[ci skip]
2026-08-13 23:22:27 +05:30
Pranshul 97d1d37c2c New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-13 23:22:26 +05:30
Pranshul 4b627aa43b New translations strings.xml (Vietnamese)
[ci skip]
2026-08-13 23:22:24 +05:30
Pranshul e4318a3b41 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-13 23:22:23 +05:30
Pranshul 4ffaaa32df New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-13 23:22:21 +05:30
Pranshul 11f29a88aa New translations strings.xml (Ukrainian)
[ci skip]
2026-08-13 23:22:20 +05:30
Pranshul 1166b749e2 New translations strings.xml (Turkish)
[ci skip]
2026-08-13 23:22:18 +05:30
Pranshul 686bd471c8 New translations strings.xml (Swedish)
[ci skip]
2026-08-13 23:22:17 +05:30
Pranshul 0d8c6f8419 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-13 23:22:15 +05:30
Pranshul da2d719bcb New translations strings.xml (Slovenian)
[ci skip]
2026-08-13 23:22:14 +05:30
Pranshul 34f8eed802 New translations strings.xml (Russian)
[ci skip]
2026-08-13 23:22:12 +05:30
Pranshul 000ba4beb4 New translations strings.xml (Portuguese)
[ci skip]
2026-08-13 23:22:11 +05:30
Pranshul ec7ad6c9dc New translations strings.xml (Polish)
[ci skip]
2026-08-13 23:22:09 +05:30
Pranshul 81ede0378d New translations strings.xml (Dutch)
[ci skip]
2026-08-13 23:22:08 +05:30
Pranshul 5109e37581 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-13 23:22:06 +05:30
Pranshul 0fd6ed57b1 New translations strings.xml (Korean)
[ci skip]
2026-08-13 23:22:05 +05:30
Pranshul 6301edd296 New translations strings.xml (Japanese)
[ci skip]
2026-08-13 23:22:03 +05:30
Pranshul a26545ecee New translations strings.xml (Italian)
[ci skip]
2026-08-13 23:22:02 +05:30
Pranshul bad24cbbee New translations strings.xml (Hungarian)
[ci skip]
2026-08-13 23:22:00 +05:30
Pranshul 549b78cae9 New translations strings.xml (Hebrew)
[ci skip]
2026-08-13 23:21:59 +05:30
Pranshul 9ce8df05f1 New translations strings.xml (Finnish)
[ci skip]
2026-08-13 23:21:57 +05:30
Pranshul d92e481ffb New translations strings.xml (Greek)
[ci skip]
2026-08-13 23:21:56 +05:30
Pranshul a66bf67cc6 New translations strings.xml (German)
[ci skip]
2026-08-13 23:21:54 +05:30
Pranshul 9d82060e81 New translations strings.xml (Czech)
[ci skip]
2026-08-13 23:21:53 +05:30
Pranshul 9d7fd99833 New translations strings.xml (Catalan)
[ci skip]
2026-08-13 23:21:51 +05:30
Pranshul 87f59b4641 New translations strings.xml (Bulgarian)
[ci skip]
2026-08-13 23:21:50 +05:30
Pranshul f29a788455 New translations strings.xml (Spanish)
[ci skip]
2026-08-13 23:21:48 +05:30
Pranshul b546f639db New translations strings.xml (French)
[ci skip]
2026-08-13 23:21:47 +05:30
Pranshul 57a4ff70ec New translations strings.xml (Romanian)
[ci skip]
2026-08-13 23:21:46 +05:30
Pranshul 2afd7d3070 Merge pull request #1020 from PranshulGG/l10n_main
New Crowdin updates
2026-08-13 21:27:46 +05:30
PranshulGG aa0f619657 missing strings 2026-08-13 21:18:14 +05:30
PranshulGG 64c3e96567 add uv index widget 2026-08-13 18:30:06 +05:30
Pranshul a90fe0c672 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-13 16:46:08 +05:30
Pranshul fcb3d10186 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-13 16:46:07 +05:30
Pranshul f6e05ce542 New translations strings.xml (Filipino)
[ci skip]
2026-08-13 16:46:05 +05:30
Pranshul 19e02c4c29 New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-13 16:46:04 +05:30
Pranshul c7c88ce9f4 New translations strings.xml (Kazakh)
[ci skip]
2026-08-13 16:46:02 +05:30
Pranshul 5de0f00718 New translations strings.xml (Thai)
[ci skip]
2026-08-13 16:46:01 +05:30
Pranshul d75b12344f New translations strings.xml (Persian)
[ci skip]
2026-08-13 16:46:00 +05:30
Pranshul ca48c0c09e New translations strings.xml (Indonesian)
[ci skip]
2026-08-13 16:45:58 +05:30
Pranshul ae1d4fc7bd New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-13 16:45:57 +05:30
Pranshul 06e11a70f8 New translations strings.xml (Vietnamese)
[ci skip]
2026-08-13 16:45:55 +05:30
Pranshul 38cf3fc198 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-13 16:45:54 +05:30
Pranshul 5bb6206303 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-13 16:45:52 +05:30
Pranshul 1ed86e03e3 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-13 16:45:51 +05:30
Pranshul 85301241cc New translations strings.xml (Turkish)
[ci skip]
2026-08-13 16:45:49 +05:30
Pranshul 5f6c014b7e New translations strings.xml (Swedish)
[ci skip]
2026-08-13 16:45:48 +05:30
Pranshul 03f848db04 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-13 16:45:46 +05:30
Pranshul 68ca3803d4 New translations strings.xml (Slovenian)
[ci skip]
2026-08-13 16:45:44 +05:30
Pranshul 6b81cfb922 New translations strings.xml (Russian)
[ci skip]
2026-08-13 16:45:42 +05:30
Pranshul c3e0c2ee7c New translations strings.xml (Portuguese)
[ci skip]
2026-08-13 16:45:41 +05:30
Pranshul 6247cf2916 New translations strings.xml (Polish)
[ci skip]
2026-08-13 16:45:40 +05:30
Pranshul b845518e41 New translations strings.xml (Dutch)
[ci skip]
2026-08-13 16:45:38 +05:30
Pranshul d8eaf32a0e New translations strings.xml (Lithuanian)
[ci skip]
2026-08-13 16:45:37 +05:30
Pranshul 746aa01593 New translations strings.xml (Korean)
[ci skip]
2026-08-13 16:45:35 +05:30
Pranshul 7b44cca756 New translations strings.xml (Japanese)
[ci skip]
2026-08-13 16:45:34 +05:30
Pranshul 44a5e23be2 New translations strings.xml (Italian)
[ci skip]
2026-08-13 16:45:33 +05:30
Pranshul 3277d1b9df New translations strings.xml (Hungarian)
[ci skip]
2026-08-13 16:45:31 +05:30
Pranshul 9867b4e5ba New translations strings.xml (Hebrew)
[ci skip]
2026-08-13 16:45:29 +05:30
Pranshul 9fd9c035ed New translations strings.xml (Finnish)
[ci skip]
2026-08-13 16:45:28 +05:30
Pranshul f1264e723f New translations strings.xml (Greek)
[ci skip]
2026-08-13 16:45:26 +05:30
Pranshul af25ffd493 New translations strings.xml (German)
[ci skip]
2026-08-13 16:45:25 +05:30
Pranshul d7a12c999e New translations strings.xml (Czech)
[ci skip]
2026-08-13 16:45:23 +05:30
Pranshul 11ea26a6e1 New translations strings.xml (Catalan)
[ci skip]
2026-08-13 16:45:22 +05:30
Pranshul 74d5a3592a New translations strings.xml (Bulgarian)
[ci skip]
2026-08-13 16:45:21 +05:30
Pranshul 0e80f21b44 New translations strings.xml (Spanish)
[ci skip]
2026-08-13 16:45:19 +05:30
Pranshul c0500e56fa New translations strings.xml (French)
[ci skip]
2026-08-13 16:45:17 +05:30
Pranshul 7c23fc8b23 New translations strings.xml (Romanian)
[ci skip]
2026-08-13 16:45:16 +05:30
PranshulGG 9dd8eea5c7 add precipitation probability to Weather 1 widget closes #1010 2026-08-13 15:51:21 +05:30
PranshulGG 3ba07102b8 add precipitation probability to Weather 1 widget closes #1010 2026-08-13 15:51:15 +05:30
PranshulGG 343c3d4bc2 add new hourly widget 2026-08-13 15:50:48 +05:30
PranshulGG 1e150e287b missing strings 2026-08-13 11:26:29 +05:30
PranshulGG 7b437779eb missing strings 2026-08-13 11:03:17 +05:30
PranshulGG db7debcd8e localized units 2026-08-13 11:01:16 +05:30
PranshulGG c860a1481f more missing strings 2026-08-13 10:57:18 +05:30
Pranshul 676edae685 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-13 10:50:22 +05:30
Pranshul 2341832053 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-13 10:50:21 +05:30
Pranshul ec59b6766c New translations strings.xml (Filipino)
[ci skip]
2026-08-13 10:50:19 +05:30
Pranshul d54a57194e New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-13 10:50:18 +05:30
Pranshul bf007a6523 New translations strings.xml (Kazakh)
[ci skip]
2026-08-13 10:50:17 +05:30
Pranshul a85c840fe2 New translations strings.xml (Thai)
[ci skip]
2026-08-13 10:50:16 +05:30
Pranshul 969848f498 New translations strings.xml (Persian)
[ci skip]
2026-08-13 10:50:14 +05:30
Pranshul 67fc3b346d New translations strings.xml (Indonesian)
[ci skip]
2026-08-13 10:50:13 +05:30
Pranshul afc2b06f6b New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-13 10:50:12 +05:30
Pranshul 0ac7fe7c47 New translations strings.xml (Vietnamese)
[ci skip]
2026-08-13 10:50:11 +05:30
Pranshul 1a41cd5a47 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-13 10:50:09 +05:30
Pranshul 56c6cef6b8 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-13 10:50:08 +05:30
Pranshul 5da8a878f5 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-13 10:50:07 +05:30
Pranshul cfbdf03d96 New translations strings.xml (Turkish)
[ci skip]
2026-08-13 10:50:06 +05:30
Pranshul e95b3b8b7c New translations strings.xml (Swedish)
[ci skip]
2026-08-13 10:50:04 +05:30
Pranshul f85017f43f New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-13 10:50:03 +05:30
Pranshul e7a388f16b New translations strings.xml (Slovenian)
[ci skip]
2026-08-13 10:50:02 +05:30
Pranshul 8bea7d3c6d New translations strings.xml (Russian)
[ci skip]
2026-08-13 10:50:01 +05:30
Pranshul e0eeeb6eb2 New translations strings.xml (Portuguese)
[ci skip]
2026-08-13 10:49:59 +05:30
Pranshul b4a136bb54 New translations strings.xml (Polish)
[ci skip]
2026-08-13 10:49:58 +05:30
Pranshul 518bad5042 New translations strings.xml (Dutch)
[ci skip]
2026-08-13 10:49:57 +05:30
Pranshul 3dbbfeee8a New translations strings.xml (Lithuanian)
[ci skip]
2026-08-13 10:49:56 +05:30
Pranshul 0cbf5da7c4 New translations strings.xml (Korean)
[ci skip]
2026-08-13 10:49:54 +05:30
Pranshul fbd5eb87f5 New translations strings.xml (Japanese)
[ci skip]
2026-08-13 10:49:53 +05:30
Pranshul 4a878ed801 New translations strings.xml (Italian)
[ci skip]
2026-08-13 10:49:52 +05:30
Pranshul cde66f9394 New translations strings.xml (Hungarian)
[ci skip]
2026-08-13 10:49:51 +05:30
Pranshul dfaa25f17b New translations strings.xml (Hebrew)
[ci skip]
2026-08-13 10:49:50 +05:30
Pranshul 90c2737e10 New translations strings.xml (Finnish)
[ci skip]
2026-08-13 10:49:48 +05:30
Pranshul 6dd2f0665a New translations strings.xml (Greek)
[ci skip]
2026-08-13 10:49:47 +05:30
Pranshul aa4ea06aff New translations strings.xml (German)
[ci skip]
2026-08-13 10:49:46 +05:30
Pranshul 0d5626a150 New translations strings.xml (Czech)
[ci skip]
2026-08-13 10:49:45 +05:30
Pranshul 30c4848db5 New translations strings.xml (Catalan)
[ci skip]
2026-08-13 10:49:43 +05:30
Pranshul f2f39087b3 New translations strings.xml (Bulgarian)
[ci skip]
2026-08-13 10:49:42 +05:30
Pranshul d94db12e0e New translations strings.xml (Spanish)
[ci skip]
2026-08-13 10:49:41 +05:30
Pranshul 9f097a350b New translations strings.xml (French)
[ci skip]
2026-08-13 10:49:40 +05:30
Pranshul ea1ed70e69 New translations strings.xml (Romanian)
[ci skip]
2026-08-13 10:49:38 +05:30
PranshulGG fda0a76218 add missing strings closes #948 2026-08-13 10:39:02 +05:30
PranshulGG 4bd9cbb44a add missing strings 2026-08-13 09:10:20 +05:30
Pranshul 4c57b6e129 New translations strings.xml (German)
[ci skip]
2026-08-13 04:45:08 +05:30
PranshulGG 57571c6bad keep past hour in the forecast 2026-08-12 22:12:40 +05:30
PranshulGG 47848a5fa2 keep past hour in the forecast 2026-08-12 22:02:39 +05:30
PranshulGG 794ccfca76 keep past hour in the forecast 2026-08-12 21:54:24 +05:30
PranshulGG 8670db4227 Fixed wrong pressure and humidity 2026-08-12 21:38:24 +05:30
PranshulGG 88f7bdc881 fix crashes 2026-08-12 21:36:53 +05:30
PranshulGG 2e56c74ac4 added gismeteo for russia closes #1005 2026-08-12 21:36:41 +05:30
Pranshul 47f94f39e9 New translations strings.xml (Hebrew)
[ci skip]
2026-08-12 01:26:33 +05:30
Pranshul 073312a234 New translations strings.xml (Greek)
[ci skip]
2026-08-11 19:27:11 +05:30
Pranshul 1c41b2ae59 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-11 13:15:36 +05:30
Pranshul 2c741f5c44 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-11 05:02:58 +05:30
Pranshul a51e9c0ca8 New translations strings.xml (Russian)
[ci skip]
2026-08-11 05:02:57 +05:30
Pranshul 6841eb6b2e New translations strings.xml (Lithuanian)
[ci skip]
2026-08-11 05:02:56 +05:30
Pranshul 4c0ba7fcdb New translations strings.xml (German)
[ci skip]
2026-08-11 05:02:54 +05:30
Pranshul 0a163fd87b New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-10 22:49:43 +05:30
Pranshul cb173476f2 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-10 22:49:42 +05:30
Pranshul b5a03ea640 New translations strings.xml (Finnish)
[ci skip]
2026-08-10 22:49:41 +05:30
Pranshul d467db7714 New translations strings.xml (Catalan)
[ci skip]
2026-08-10 22:49:39 +05:30
PranshulGG 8d40cfcc94 Fixed unwanted calls to alert APIs 2026-08-10 22:11:53 +05:30
PranshulGG 792f9370b2 Fixed unwanted calls to alert APIs 2026-08-10 22:11:47 +05:30
PranshulGG e8e08235c2 FOSS Public Alert Server added as alert source closes #1004 2026-08-10 22:11:26 +05:30
PranshulGG ad0a96f290 date cutting off in German closes #1007 2026-08-10 17:34:14 +05:30
PranshulGG a767a5fbeb Fix overflow issue closes #1008 2026-08-10 17:31:28 +05:30
Pranshul 499c8989f8 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-10 16:53:04 +05:30
Pranshul 8e31cfaeda New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-10 16:53:02 +05:30
Pranshul 355a5f9bf0 New translations strings.xml (Filipino)
[ci skip]
2026-08-10 16:53:01 +05:30
Pranshul c6dfcabf23 New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-10 16:53:00 +05:30
Pranshul ba0e41f1c8 New translations strings.xml (Kazakh)
[ci skip]
2026-08-10 16:52:58 +05:30
Pranshul 8a5faa6b06 New translations strings.xml (Thai)
[ci skip]
2026-08-10 16:52:57 +05:30
Pranshul 400295659e New translations strings.xml (Persian)
[ci skip]
2026-08-10 16:52:55 +05:30
Pranshul 2c42390128 New translations strings.xml (Indonesian)
[ci skip]
2026-08-10 16:52:54 +05:30
Pranshul 5decbf0144 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-10 16:52:53 +05:30
Pranshul 83520f5802 New translations strings.xml (Vietnamese)
[ci skip]
2026-08-10 16:52:51 +05:30
Pranshul e3e1efbdd1 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-10 16:52:50 +05:30
Pranshul dc896faba3 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-10 16:52:49 +05:30
Pranshul e20a4fabb1 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-10 16:52:48 +05:30
Pranshul 898bfc6eba New translations strings.xml (Turkish)
[ci skip]
2026-08-10 16:52:46 +05:30
Pranshul 92ce0a5706 New translations strings.xml (Swedish)
[ci skip]
2026-08-10 16:52:45 +05:30
Pranshul 61d290a4c9 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-10 16:52:44 +05:30
Pranshul 0dc84f3d18 New translations strings.xml (Slovenian)
[ci skip]
2026-08-10 16:52:42 +05:30
Pranshul ff9c25172f New translations strings.xml (Russian)
[ci skip]
2026-08-10 16:52:41 +05:30
Pranshul 61aabaecbd New translations strings.xml (Portuguese)
[ci skip]
2026-08-10 16:52:39 +05:30
Pranshul 3849b3251e New translations strings.xml (Polish)
[ci skip]
2026-08-10 16:52:38 +05:30
Pranshul 366c584259 New translations strings.xml (Dutch)
[ci skip]
2026-08-10 16:52:37 +05:30
Pranshul 00a47d069d New translations strings.xml (Lithuanian)
[ci skip]
2026-08-10 16:52:35 +05:30
Pranshul 770d5ba0e5 New translations strings.xml (Korean)
[ci skip]
2026-08-10 16:52:34 +05:30
Pranshul 80414f110a New translations strings.xml (Japanese)
[ci skip]
2026-08-10 16:52:33 +05:30
Pranshul 18e2d01d94 New translations strings.xml (Italian)
[ci skip]
2026-08-10 16:52:32 +05:30
Pranshul 7113945a81 New translations strings.xml (Hungarian)
[ci skip]
2026-08-10 16:52:29 +05:30
Pranshul d12bb7d151 New translations strings.xml (Hebrew)
[ci skip]
2026-08-10 16:52:28 +05:30
Pranshul 8f71864224 New translations strings.xml (Finnish)
[ci skip]
2026-08-10 16:52:26 +05:30
Pranshul a09f650d00 New translations strings.xml (Greek)
[ci skip]
2026-08-10 16:52:25 +05:30
Pranshul fe7a374952 New translations strings.xml (German)
[ci skip]
2026-08-10 16:52:24 +05:30
Pranshul 79ed86b0d5 New translations strings.xml (Czech)
[ci skip]
2026-08-10 16:52:22 +05:30
Pranshul 140f54aebf New translations strings.xml (Catalan)
[ci skip]
2026-08-10 16:52:21 +05:30
Pranshul 2a6a6b8d87 New translations strings.xml (Bulgarian)
[ci skip]
2026-08-10 16:52:20 +05:30
Pranshul 3827307a32 New translations strings.xml (Spanish)
[ci skip]
2026-08-10 16:52:18 +05:30
Pranshul 0a26842590 New translations strings.xml (French)
[ci skip]
2026-08-10 16:52:17 +05:30
Pranshul 728cd13c19 New translations strings.xml (Romanian)
[ci skip]
2026-08-10 16:52:16 +05:30
PranshulGG 9248dd7e6d rounded banner 2026-08-10 13:26:28 +05:30
PranshulGG 9a954574e9 update previews 2026-08-10 13:24:24 +05:30
PranshulGG 32dbc9b340 pick between 54 models for Open-Meteo 2026-08-10 11:30:59 +05:30
PranshulGG 5abefe75c5 pick between 54 models for Open-Meteo 2026-08-10 11:30:51 +05:30
Pranshul 1da76b134c New translations strings.xml (French)
[ci skip]
2026-08-10 09:44:33 +05:30
Pranshul 34fdf58285 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-10 03:10:02 +05:30
Pranshul 9bb7714bbd New translations strings.xml (Russian)
[ci skip]
2026-08-10 03:10:01 +05:30
Pranshul 0f75770d17 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-09 21:07:48 +05:30
Pranshul 55c8fb3f22 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-09 21:07:47 +05:30
Pranshul 7caaa66363 New translations strings.xml (Filipino)
[ci skip]
2026-08-09 21:07:46 +05:30
Pranshul 3a05449f4a New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-09 21:07:45 +05:30
Pranshul 9922678abb New translations strings.xml (Kazakh)
[ci skip]
2026-08-09 21:07:43 +05:30
Pranshul 25ca4e67c7 New translations strings.xml (Thai)
[ci skip]
2026-08-09 21:07:42 +05:30
Pranshul 3bf3a5b225 New translations strings.xml (Persian)
[ci skip]
2026-08-09 21:07:41 +05:30
Pranshul f03eaab4cf New translations strings.xml (Indonesian)
[ci skip]
2026-08-09 21:07:40 +05:30
Pranshul 430dc185fb New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-09 21:07:39 +05:30
Pranshul 3a588465d2 New translations strings.xml (Vietnamese)
[ci skip]
2026-08-09 21:07:38 +05:30
Pranshul 1584bca762 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-09 21:07:36 +05:30
Pranshul 12017b11c3 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-09 21:07:35 +05:30
Pranshul a69abf866a New translations strings.xml (Ukrainian)
[ci skip]
2026-08-09 21:07:34 +05:30
Pranshul 4edcf7b3ae New translations strings.xml (Turkish)
[ci skip]
2026-08-09 21:07:33 +05:30
Pranshul 3dcdeb197f New translations strings.xml (Swedish)
[ci skip]
2026-08-09 21:07:31 +05:30
Pranshul 55927d15ae New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-09 21:07:30 +05:30
Pranshul 3c5719f774 New translations strings.xml (Slovenian)
[ci skip]
2026-08-09 21:07:29 +05:30
Pranshul bdc30e16e3 New translations strings.xml (Russian)
[ci skip]
2026-08-09 21:07:28 +05:30
Pranshul 26ae9fdcd0 New translations strings.xml (Portuguese)
[ci skip]
2026-08-09 21:07:27 +05:30
Pranshul 91dbab2309 New translations strings.xml (Polish)
[ci skip]
2026-08-09 21:07:25 +05:30
Pranshul 802ce27bba New translations strings.xml (Dutch)
[ci skip]
2026-08-09 21:07:24 +05:30
Pranshul 09d88b1d19 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-09 21:07:23 +05:30
Pranshul 124f9f24fb New translations strings.xml (Korean)
[ci skip]
2026-08-09 21:07:22 +05:30
Pranshul 03cf055f52 New translations strings.xml (Japanese)
[ci skip]
2026-08-09 21:07:21 +05:30
Pranshul 912187a9b2 New translations strings.xml (Italian)
[ci skip]
2026-08-09 21:07:19 +05:30
Pranshul a302d51d70 New translations strings.xml (Hungarian)
[ci skip]
2026-08-09 21:07:18 +05:30
Pranshul 632a614894 New translations strings.xml (Hebrew)
[ci skip]
2026-08-09 21:07:17 +05:30
Pranshul a5a7d75b8d New translations strings.xml (Finnish)
[ci skip]
2026-08-09 21:07:16 +05:30
Pranshul 24915b42b1 New translations strings.xml (Greek)
[ci skip]
2026-08-09 21:07:15 +05:30
Pranshul bbb084cf73 New translations strings.xml (German)
[ci skip]
2026-08-09 21:07:13 +05:30
Pranshul 32f2587a50 New translations strings.xml (Czech)
[ci skip]
2026-08-09 21:07:12 +05:30
Pranshul 610088c8b5 New translations strings.xml (Catalan)
[ci skip]
2026-08-09 21:07:11 +05:30
Pranshul da5f903c74 New translations strings.xml (Bulgarian)
[ci skip]
2026-08-09 21:07:10 +05:30
Pranshul ce3bf468d4 New translations strings.xml (Spanish)
[ci skip]
2026-08-09 21:07:09 +05:30
Pranshul 1158709791 New translations strings.xml (French)
[ci skip]
2026-08-09 21:07:07 +05:30
Pranshul a36ca02589 New translations strings.xml (Romanian)
[ci skip]
2026-08-09 21:07:06 +05:30
PranshulGG 23402a272c update app previews 2026-08-09 20:58:40 +05:30
PranshulGG abfca933cd WMO Severe Weather added as alert source 2026-08-09 18:07:08 +05:30
PranshulGG 45ad8a2011 Improved location list UI 2026-08-09 18:06:38 +05:30
PranshulGG 64f55c9da0 added missing strings closes 2026-08-09 18:01:36 +05:30
Pranshul d1b62cbb31 Merge pull request #1001 from PranshulGG/l10n_main
New Crowdin updates
2026-08-09 11:05:01 +05:30
Pranshul f6a62bbeec Merge branch 'main' into l10n_main
Signed-off-by: Pranshul <pranshul.devmain@gmail.com>
2026-08-09 11:04:49 +05:30
Pranshul 3cbf80620b New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-09 08:57:53 +05:30
Pranshul 34177b4cf7 New translations strings.xml (German)
[ci skip]
2026-08-08 23:44:56 +05:30
Pranshul aeac03327f New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-08-08 23:44:54 +05:30
Pranshul 06e4df257c New translations strings.xml (Serbian (Latin))
[ci skip]
2026-08-08 23:44:53 +05:30
Pranshul f9646ef13d New translations strings.xml (Filipino)
[ci skip]
2026-08-08 23:44:52 +05:30
Pranshul bd9b4f5664 New translations strings.xml (Azerbaijani)
[ci skip]
2026-08-08 23:44:51 +05:30
Pranshul f29fcba543 New translations strings.xml (Kazakh)
[ci skip]
2026-08-08 23:44:50 +05:30
Pranshul 8a35f6f949 New translations strings.xml (Thai)
[ci skip]
2026-08-08 23:44:49 +05:30
Pranshul 3744b6133f New translations strings.xml (Persian)
[ci skip]
2026-08-08 23:44:47 +05:30
Pranshul 744f9e335a New translations strings.xml (Indonesian)
[ci skip]
2026-08-08 23:44:46 +05:30
Pranshul 88919d873a New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-08 23:44:45 +05:30
Pranshul 79c96602fa New translations strings.xml (Vietnamese)
[ci skip]
2026-08-08 23:44:44 +05:30
Pranshul abf4741a7f New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-08 23:44:43 +05:30
Pranshul 442c4267fd New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-08 23:44:41 +05:30
Pranshul 1613431e95 New translations strings.xml (Ukrainian)
[ci skip]
2026-08-08 23:44:40 +05:30
Pranshul f8a889a8ed New translations strings.xml (Turkish)
[ci skip]
2026-08-08 23:44:39 +05:30
Pranshul 5929359a1b New translations strings.xml (Swedish)
[ci skip]
2026-08-08 23:44:38 +05:30
Pranshul 7e59078be1 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-08-08 23:44:37 +05:30
Pranshul f2feb8fa6f New translations strings.xml (Slovenian)
[ci skip]
2026-08-08 23:44:35 +05:30
Pranshul c43862329a New translations strings.xml (Russian)
[ci skip]
2026-08-08 23:44:34 +05:30
Pranshul 1ecdac5096 New translations strings.xml (Portuguese)
[ci skip]
2026-08-08 23:44:33 +05:30
Pranshul c9f983ca84 New translations strings.xml (Polish)
[ci skip]
2026-08-08 23:44:32 +05:30
Pranshul f80c9585fa New translations strings.xml (Dutch)
[ci skip]
2026-08-08 23:44:31 +05:30
Pranshul 62df55f029 New translations strings.xml (Lithuanian)
[ci skip]
2026-08-08 23:44:30 +05:30
Pranshul 39c16784eb New translations strings.xml (Korean)
[ci skip]
2026-08-08 23:44:28 +05:30
Pranshul efc6b72f3e New translations strings.xml (Japanese)
[ci skip]
2026-08-08 23:44:27 +05:30
Pranshul a8ad1c098d New translations strings.xml (Italian)
[ci skip]
2026-08-08 23:44:26 +05:30
Pranshul 9a510c1b8b New translations strings.xml (Hungarian)
[ci skip]
2026-08-08 23:44:25 +05:30
Pranshul 40f3d482fa New translations strings.xml (Hebrew)
[ci skip]
2026-08-08 23:44:24 +05:30
Pranshul e2c4319698 New translations strings.xml (Finnish)
[ci skip]
2026-08-08 23:44:22 +05:30
Pranshul c8d414cbca New translations strings.xml (Greek)
[ci skip]
2026-08-08 23:44:21 +05:30
Pranshul 76a7320831 New translations strings.xml (Czech)
[ci skip]
2026-08-08 23:44:20 +05:30
Pranshul fa74d3ded9 New translations strings.xml (Catalan)
[ci skip]
2026-08-08 23:44:19 +05:30
Pranshul 07e43b8af2 New translations strings.xml (Bulgarian)
[ci skip]
2026-08-08 23:44:17 +05:30
Pranshul 6b6375de69 New translations strings.xml (Spanish)
[ci skip]
2026-08-08 23:44:16 +05:30
Pranshul bc68cca8cb New translations strings.xml (French)
[ci skip]
2026-08-08 23:44:15 +05:30
Pranshul 5637c6da45 New translations strings.xml (Romanian)
[ci skip]
2026-08-08 23:44:14 +05:30
PranshulGG 3f2ba808d5 added missing strings closes #1013 2026-08-08 20:21:57 +05:30
PranshulGG 4707619b9f crash fixes 2026-08-08 20:15:03 +05:30
Pranshul e7dfde895f New translations strings.xml (Vietnamese)
[ci skip]
2026-08-08 17:29:53 +05:30
PranshulGG a51335db29 improve intro screen 2026-08-08 11:09:35 +05:30
Pranshul 84a4a1e551 New translations strings.xml (Romanian)
[ci skip]
2026-08-08 00:34:45 +05:30
Pranshul 75a57bb369 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-07 18:15:33 +05:30
Pranshul 8be288e838 New translations strings.xml (Dutch)
[ci skip]
2026-08-07 18:15:32 +05:30
Pranshul 8278e2d0ab New translations strings.xml (Hebrew)
[ci skip]
2026-08-07 12:00:41 +05:30
Pranshul fafc78e2c0 New translations strings.xml (Spanish)
[ci skip]
2026-08-07 05:48:46 +05:30
Pranshul 1e73ace403 New translations strings.xml (Indonesian)
[ci skip]
2026-08-06 23:10:40 +05:30
Pranshul c9e1657855 New translations strings.xml (Vietnamese)
[ci skip]
2026-08-06 23:10:39 +05:30
Pranshul 4b70a2e717 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-06 23:10:37 +05:30
Pranshul c5fd01f5b3 New translations strings.xml (Greek)
[ci skip]
2026-08-06 23:10:36 +05:30
PranshulGG 430bd7d94a fix dew point crashes 2026-08-06 20:32:08 +05:30
Pranshul b0278c0fc1 New translations strings.xml (Indonesian)
[ci skip]
2026-08-06 17:06:38 +05:30
Pranshul 82dbed4a08 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-06 17:06:36 +05:30
Pranshul 17ff5e9985 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-08-06 17:06:35 +05:30
Pranshul 770c4c09ac New translations strings.xml (Lithuanian)
[ci skip]
2026-08-06 17:06:33 +05:30
Pranshul 4c842b52e5 New translations strings.xml (Italian)
[ci skip]
2026-08-06 17:06:32 +05:30
Pranshul 073925719e New translations strings.xml (Greek)
[ci skip]
2026-08-06 17:06:31 +05:30
Pranshul 39c2197b40 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-06 11:10:37 +05:30
Pranshul e19032848e New translations strings.xml (Lithuanian)
[ci skip]
2026-08-06 11:10:35 +05:30
PranshulGG 16fa2366f0 Wrong temperature summary 2026-08-06 09:28:21 +05:30
Pranshul 8d28ed98c1 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-06 04:33:52 +05:30
Pranshul 5155b2f748 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-05 22:14:10 +05:30
Pranshul 7ab05ff903 New translations strings.xml (Russian)
[ci skip]
2026-08-05 22:14:09 +05:30
Pranshul fb966ac1fc New translations strings.xml (Finnish)
[ci skip]
2026-08-05 22:14:07 +05:30
PranshulGG 52ae155b73 translation fixes 2026-08-05 18:26:46 +05:30
Pranshul 5282aa8b4a New translations strings.xml (Chinese Traditional)
[ci skip]
2026-08-05 16:10:03 +05:30
PranshulGG 97ea5abc17 fix strings 2026-08-05 13:48:54 +05:30
PranshulGG 74f1f9ca39 update logos 2026-08-05 12:31:23 +05:30
PranshulGG 2272157b60 fix application id 2026-08-05 12:27:39 +05:30
PranshulGG a78eec66bd update readme 2026-08-05 12:26:38 +05:30
PranshulGG 4bc33951e4 missing strings 2026-08-05 12:26:25 +05:30
PranshulGG b5a7677db0 fix alert crashes 2026-08-05 12:26:16 +05:30
Pranshul e21956ee13 New translations strings.xml (Romanian)
[ci skip]
2026-08-05 09:12:03 +05:30
Pranshul 0421684d8b New translations strings.xml (Romanian)
[ci skip]
2026-08-05 02:48:37 +05:30
Pranshul 1e50046c0f New translations strings.xml (Japanese)
[ci skip]
2026-08-04 19:56:06 +05:30
Pranshul df79648fbc New translations strings.xml (Korean)
[ci skip]
2026-08-04 13:33:00 +05:30
Pranshul 4e7b8a3422 New translations strings.xml (Hebrew)
[ci skip]
2026-08-04 06:03:36 +05:30
PranshulGG 5aa163f919 add privacy policy 2026-08-03 20:24:35 +05:30
PranshulGG 3ca2d4e372 Added dew point scale closes #990 2026-08-03 16:33:22 +05:30
PranshulGG 0f49cff675 fixed landscape layout #991 2026-08-03 16:17:38 +05:30
PranshulGG b58d1396bc options to change text and background color closes #973 2026-08-03 15:35:02 +05:30
PranshulGG d91e108603 fix version 2026-08-03 11:53:32 +05:30
PranshulGG 62755e80d0 license 2026-08-03 11:53:12 +05:30
PranshulGG d0e1638960 Add dates to the daily forecast on the main screen #975 2026-08-03 11:53:06 +05:30
PranshulGG 38779270c6 translation fixes 2026-08-03 11:25:31 +05:30
PranshulGG 3267ad4fc6 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-08-03 11:13:24 +05:30
PranshulGG 5aafd36fb6 update version 2026-08-03 11:13:10 +05:30
PranshulGG 2cd03623da Weather3 customizations 2026-08-03 11:11:57 +05:30
PranshulGG 0537795ef0 new as a search source 2026-08-03 11:11:26 +05:30
Pranshul 8f76ec6a64 Merge pull request #998 from PranshulGG/l10n_main
New Crowdin updates
2026-08-03 11:10:52 +05:30
Pranshul 95dde6101d Merge pull request #1000 from hydrielax/main
fix: MeteoFranceCondition mapping to WeatherCondition
2026-08-03 11:08:16 +05:30
Pranshul e06d990a30 New translations strings.xml (Polish)
[ci skip]
2026-08-03 02:18:59 +05:30
Alexis Delage d4aff5cbc4 fix: MeteoFranceCondition mapping to WeatherCondition
The fix is based on the official icons corresponding to each code, and also on my own experience using both WeatherMaster and MeteoFrance official app
2026-08-02 18:47:06 +02:00
Pranshul 08b8d07c83 New translations strings.xml (Czech)
[ci skip]
2026-08-02 20:23:41 +05:30
Pranshul 5b30275470 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-08-02 05:42:04 +05:30
PranshulGG 3104cbd6f2 icon drawable 2026-08-01 14:50:29 +05:30
PranshulGG daf794fc1c update db version 2026-08-01 14:50:17 +05:30
PranshulGG 07730aed97 add Changelog bottom sheet 2026-08-01 14:50:04 +05:30
PranshulGG 0445ac0359 add IPMA (Portugal) closes #983 2026-08-01 14:49:43 +05:30
Pranshul 59ac2eec33 New translations strings.xml (Vietnamese)
[ci skip]
2026-08-01 12:46:10 +05:30
Pranshul c595e82820 New translations strings.xml (Russian)
[ci skip]
2026-08-01 01:44:41 +05:30
Pranshul 2c5ee6c64e New translations strings.xml (French)
[ci skip]
2026-07-31 19:48:28 +05:30
Pranshul c194237425 New translations strings.xml (Vietnamese)
[ci skip]
2026-07-31 11:47:37 +05:30
Pranshul a963a44674 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-07-31 01:18:09 +05:30
Pranshul 8bcb4ce8f6 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-07-31 01:18:07 +05:30
Pranshul 36ed8fca55 New translations strings.xml (Filipino)
[ci skip]
2026-07-31 01:18:06 +05:30
Pranshul c5681f1aec New translations strings.xml (Azerbaijani)
[ci skip]
2026-07-31 01:18:05 +05:30
Pranshul c12f3b6cbd New translations strings.xml (Kazakh)
[ci skip]
2026-07-31 01:18:03 +05:30
Pranshul 5cb9a11b21 New translations strings.xml (Thai)
[ci skip]
2026-07-31 01:18:02 +05:30
Pranshul bba8005dd1 New translations strings.xml (Persian)
[ci skip]
2026-07-31 01:18:01 +05:30
Pranshul 6c3504a1db New translations strings.xml (Indonesian)
[ci skip]
2026-07-31 01:17:59 +05:30
Pranshul 64d92c8e5b New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-31 01:17:58 +05:30
Pranshul 064f44e47c New translations strings.xml (Vietnamese)
[ci skip]
2026-07-31 01:17:57 +05:30
Pranshul 83c647706a New translations strings.xml (Chinese Traditional)
[ci skip]
2026-07-31 01:17:55 +05:30
Pranshul 8732a73018 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-07-31 01:17:54 +05:30
Pranshul 70873b0170 New translations strings.xml (Ukrainian)
[ci skip]
2026-07-31 01:17:53 +05:30
Pranshul 6fbeb3063b New translations strings.xml (Turkish)
[ci skip]
2026-07-31 01:17:52 +05:30
Pranshul 2462c0c8cc New translations strings.xml (Swedish)
[ci skip]
2026-07-31 01:17:50 +05:30
Pranshul 546eb7ef1f New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-07-31 01:17:49 +05:30
Pranshul 58221d8a4b New translations strings.xml (Slovenian)
[ci skip]
2026-07-31 01:17:48 +05:30
Pranshul 32d320a352 New translations strings.xml (Russian)
[ci skip]
2026-07-31 01:17:46 +05:30
Pranshul 6dbfb7269e New translations strings.xml (Portuguese)
[ci skip]
2026-07-31 01:17:45 +05:30
Pranshul b5dea96fc0 New translations strings.xml (Polish)
[ci skip]
2026-07-31 01:17:44 +05:30
Pranshul c057923404 New translations strings.xml (Dutch)
[ci skip]
2026-07-31 01:17:43 +05:30
Pranshul 69017417e7 New translations strings.xml (Lithuanian)
[ci skip]
2026-07-31 01:17:41 +05:30
Pranshul dec36d4189 New translations strings.xml (Korean)
[ci skip]
2026-07-31 01:17:40 +05:30
Pranshul bd183a9f62 New translations strings.xml (Japanese)
[ci skip]
2026-07-31 01:17:39 +05:30
Pranshul fcaee23975 New translations strings.xml (Italian)
[ci skip]
2026-07-31 01:17:37 +05:30
Pranshul bd794e821a New translations strings.xml (Hungarian)
[ci skip]
2026-07-31 01:17:36 +05:30
Pranshul 4a91234729 New translations strings.xml (Hebrew)
[ci skip]
2026-07-31 01:17:35 +05:30
Pranshul 90aac42048 New translations strings.xml (Finnish)
[ci skip]
2026-07-31 01:17:33 +05:30
Pranshul 4aa1ba02ad New translations strings.xml (Greek)
[ci skip]
2026-07-31 01:17:32 +05:30
Pranshul d22a83b867 New translations strings.xml (Czech)
[ci skip]
2026-07-31 01:17:31 +05:30
Pranshul 7fbc3013d9 New translations strings.xml (Catalan)
[ci skip]
2026-07-31 01:17:29 +05:30
Pranshul d56c472911 New translations strings.xml (Bulgarian)
[ci skip]
2026-07-31 01:17:28 +05:30
Pranshul f52879d45b New translations strings.xml (Spanish)
[ci skip]
2026-07-31 01:17:26 +05:30
Pranshul 320f332da6 New translations strings.xml (French)
[ci skip]
2026-07-31 01:17:25 +05:30
Pranshul 1881fb15d2 New translations strings.xml (Romanian)
[ci skip]
2026-07-31 01:17:24 +05:30
PranshulGG c00ea27aae Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-07-30 16:17:20 +05:30
PranshulGG 1db31d20d9 Add WEATHERAPI_KEY to gradle.properties 2026-07-30 16:17:12 +05:30
Pranshul 08a1f11408 Merge pull request #989 from PranshulGG/l10n_main
New Crowdin updates
2026-07-30 16:10:46 +05:30
Pranshul cc71c65b72 Merge branch 'main' into l10n_main
Signed-off-by: Pranshul <pranshul.devmain@gmail.com>
2026-07-30 16:10:34 +05:30
Pranshul b6624c1e4f Merge pull request #994 from arpitagarwal1301/fix/976-visibility-graph-bounds
Fix visibility graph overflow
2026-07-30 16:08:26 +05:30
PranshulGG bff0c7465d new version check every 2hours 2026-07-30 16:07:24 +05:30
PranshulGG 2d575b8167 new strings 2026-07-30 16:07:10 +05:30
PranshulGG 6c6600d02c fix credits 2026-07-30 16:06:44 +05:30
PranshulGG 6af7d57ad3 edit location options 2026-07-30 16:06:34 +05:30
PranshulGG f27d92cd79 include next day hours closes #974 2026-07-30 16:06:09 +05:30
Pranshul 4a686a6862 New translations strings.xml (Lithuanian)
[ci skip]
2026-07-30 12:46:49 +05:30
Pranshul a146adf69a New translations strings.xml (Polish)
[ci skip]
2026-07-30 06:14:21 +05:30
Pranshul 4adbafa9e0 New translations strings.xml (French)
[ci skip]
2026-07-29 23:46:08 +05:30
Pranshul f17dc42601 New translations strings.xml (Korean)
[ci skip]
2026-07-29 17:49:02 +05:30
PranshulGG 05d0749c77 upgrade db version 2026-07-29 17:29:07 +05:30
PranshulGG f8bcf885a8 new api 2026-07-29 17:28:53 +05:30
PranshulGG da6715d958 fix data reconciler 2026-07-29 17:28:46 +05:30
PranshulGG 5c3d5dab77 alerts 2026-07-29 17:28:16 +05:30
PranshulGG df96aa2481 alert screen 2026-07-29 17:28:03 +05:30
PranshulGG fcbb52f26b add weatherapi.com as alert source 2026-07-29 17:27:49 +05:30
Pranshul 81461f7c25 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-29 11:45:00 +05:30
Pranshul 9f0c63eff1 New translations strings.xml (Hebrew)
[ci skip]
2026-07-28 23:08:03 +05:30
Pranshul 5d3906df42 New translations strings.xml (Italian)
[ci skip]
2026-07-28 23:08:02 +05:30
Arpit Agarwal 9b6e1a2613 Fix visibility graph overflow 2026-07-28 18:59:47 +05:30
PranshulGG b6381be715 new drawable 2026-07-28 16:33:07 +05:30
PranshulGG ff8af9bd73 filter search results without timezone 2026-07-28 16:32:25 +05:30
PranshulGG 5cd825e052 Fixed null value crashes for NWS 2026-07-28 16:32:04 +05:30
Pranshul fef587a6e5 New translations strings.xml (Russian)
[ci skip]
2026-07-28 16:32:02 +05:30
Pranshul e018ed21c1 New translations strings.xml (Dutch)
[ci skip]
2026-07-28 16:32:00 +05:30
PranshulGG 7a55055a90 weather alerts 2026-07-28 16:31:44 +05:30
PranshulGG 981838b48f weather alerts 2026-07-28 16:31:37 +05:30
PranshulGG 1f350ce7ba weather alerts 2026-07-28 16:31:33 +05:30
PranshulGG 3290e68c63 weather alerts 2026-07-28 16:31:26 +05:30
PranshulGG 4f79efb80c weather alerts 2026-07-28 16:31:22 +05:30
PranshulGG 81b3caef4a weather alerts 2026-07-28 16:31:17 +05:30
PranshulGG c2739dee85 weather alerts 2026-07-28 16:30:58 +05:30
PranshulGG f36498c5c2 weather alerts 2026-07-28 16:30:47 +05:30
Pranshul 74984c3791 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-07-28 10:29:25 +05:30
Pranshul 2501a21cf4 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-07-28 10:29:23 +05:30
Pranshul 88f01a2f16 New translations strings.xml (Filipino)
[ci skip]
2026-07-28 10:29:22 +05:30
Pranshul 4063a8ddcf New translations strings.xml (Azerbaijani)
[ci skip]
2026-07-28 10:29:21 +05:30
Pranshul 9d8ec47bb4 New translations strings.xml (Kazakh)
[ci skip]
2026-07-28 10:29:20 +05:30
Pranshul a20cd212b2 New translations strings.xml (Thai)
[ci skip]
2026-07-28 10:29:19 +05:30
Pranshul 01d3e8e9f9 New translations strings.xml (Persian)
[ci skip]
2026-07-28 10:29:17 +05:30
Pranshul 8dd6766d93 New translations strings.xml (Indonesian)
[ci skip]
2026-07-28 10:29:16 +05:30
Pranshul d798f7bf52 New translations strings.xml (Vietnamese)
[ci skip]
2026-07-28 10:29:15 +05:30
Pranshul 5690d69b34 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-07-28 10:29:14 +05:30
Pranshul 477c62d18a New translations strings.xml (Ukrainian)
[ci skip]
2026-07-28 10:29:13 +05:30
Pranshul b99ac0dce8 New translations strings.xml (Turkish)
[ci skip]
2026-07-28 10:29:11 +05:30
Pranshul 90326e46c1 New translations strings.xml (Swedish)
[ci skip]
2026-07-28 10:29:10 +05:30
Pranshul 0d457b99cc New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-07-28 10:29:09 +05:30
Pranshul a3d15f71a8 New translations strings.xml (Slovenian)
[ci skip]
2026-07-28 10:29:08 +05:30
Pranshul 57d621b407 New translations strings.xml (Polish)
[ci skip]
2026-07-28 10:29:07 +05:30
Pranshul 8997b835f7 New translations strings.xml (Lithuanian)
[ci skip]
2026-07-28 10:29:05 +05:30
Pranshul 0680be9d77 New translations strings.xml (Hungarian)
[ci skip]
2026-07-28 10:29:04 +05:30
Pranshul a6d49f5411 New translations strings.xml (Greek)
[ci skip]
2026-07-28 10:29:03 +05:30
Pranshul c39908fda0 New translations strings.xml (Czech)
[ci skip]
2026-07-28 10:29:02 +05:30
Pranshul e372bde373 New translations strings.xml (Catalan)
[ci skip]
2026-07-28 10:29:01 +05:30
Pranshul 432b427a7c New translations strings.xml (Bulgarian)
[ci skip]
2026-07-28 10:29:00 +05:30
Pranshul 75443257ec New translations strings.xml (Spanish)
[ci skip]
2026-07-28 10:28:58 +05:30
Pranshul 5f7e3c1fa3 New translations strings.xml (Romanian)
[ci skip]
2026-07-28 10:28:57 +05:30
Pranshul b88560f9f9 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-07-28 10:28:55 +05:30
Pranshul eea67e74b4 New translations strings.xml (Hebrew)
[ci skip]
2026-07-28 10:28:54 +05:30
Pranshul d592ad923b New translations strings.xml (Italian)
[ci skip]
2026-07-28 10:28:53 +05:30
Pranshul e3790b77fa New translations strings.xml (Korean)
[ci skip]
2026-07-28 10:28:52 +05:30
Pranshul 508c45601f New translations strings.xml (Portuguese)
[ci skip]
2026-07-28 10:28:51 +05:30
Pranshul d350773571 New translations strings.xml (Japanese)
[ci skip]
2026-07-28 10:28:50 +05:30
Pranshul 78a2e68928 New translations strings.xml (French)
[ci skip]
2026-07-28 10:28:49 +05:30
Pranshul 5c507b92f7 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-28 10:28:47 +05:30
Pranshul ad748cd240 New translations strings.xml (Russian)
[ci skip]
2026-07-28 10:28:46 +05:30
Pranshul 87ff70d480 New translations strings.xml (Dutch)
[ci skip]
2026-07-28 10:28:45 +05:30
Pranshul 5afc421dc2 New translations strings.xml (Finnish)
[ci skip]
2026-07-28 10:28:44 +05:30
Pranshul a941595b46 New translations strings.xml (German)
[ci skip]
2026-07-28 10:28:42 +05:30
PranshulGG c2757ea4b5 add alert severity strings to strings.xml 2026-07-28 09:40:32 +05:30
Pranshul 6e13c8b0ef New translations strings.xml (German)
[ci skip]
2026-07-28 04:19:44 +05:30
Pranshul 08d8cdbdac New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-07-27 21:46:04 +05:30
Pranshul 2b9fcd7878 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-07-27 21:46:03 +05:30
Pranshul e6ebf905a6 New translations strings.xml (Filipino)
[ci skip]
2026-07-27 21:46:02 +05:30
Pranshul 1504884429 New translations strings.xml (Azerbaijani)
[ci skip]
2026-07-27 21:46:00 +05:30
Pranshul aea71b1c8a New translations strings.xml (Kazakh)
[ci skip]
2026-07-27 21:45:59 +05:30
Pranshul 59735f1b53 New translations strings.xml (Thai)
[ci skip]
2026-07-27 21:45:57 +05:30
Pranshul 2c7ee93a92 New translations strings.xml (Persian)
[ci skip]
2026-07-27 21:45:56 +05:30
Pranshul e883cb1b22 New translations strings.xml (Indonesian)
[ci skip]
2026-07-27 21:45:55 +05:30
Pranshul d83f4f4a34 New translations strings.xml (Vietnamese)
[ci skip]
2026-07-27 21:45:53 +05:30
Pranshul 7d8b97e67e New translations strings.xml (Chinese Traditional)
[ci skip]
2026-07-27 21:45:52 +05:30
Pranshul ae148bafeb New translations strings.xml (Ukrainian)
[ci skip]
2026-07-27 21:45:50 +05:30
Pranshul cb49613ff7 New translations strings.xml (Turkish)
[ci skip]
2026-07-27 21:45:49 +05:30
Pranshul 3f16878da1 New translations strings.xml (Swedish)
[ci skip]
2026-07-27 21:45:47 +05:30
Pranshul e88f357d47 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-07-27 21:45:46 +05:30
Pranshul 4cc790ed98 New translations strings.xml (Slovenian)
[ci skip]
2026-07-27 21:45:44 +05:30
Pranshul 24e55b15f1 New translations strings.xml (Polish)
[ci skip]
2026-07-27 21:45:43 +05:30
Pranshul 151daf1226 New translations strings.xml (Lithuanian)
[ci skip]
2026-07-27 21:45:41 +05:30
Pranshul aaa1585bbb New translations strings.xml (Hungarian)
[ci skip]
2026-07-27 21:45:40 +05:30
Pranshul 2824bd33eb New translations strings.xml (Greek)
[ci skip]
2026-07-27 21:45:38 +05:30
Pranshul 7ce1b3c31a New translations strings.xml (Czech)
[ci skip]
2026-07-27 21:45:37 +05:30
Pranshul 5b8a93bfd9 New translations strings.xml (Catalan)
[ci skip]
2026-07-27 21:45:35 +05:30
Pranshul 777c059f62 New translations strings.xml (Bulgarian)
[ci skip]
2026-07-27 21:45:34 +05:30
Pranshul f4332f12b3 New translations strings.xml (Spanish)
[ci skip]
2026-07-27 21:45:33 +05:30
Pranshul bb8f9143da New translations strings.xml (Romanian)
[ci skip]
2026-07-27 21:45:31 +05:30
Pranshul 23efc87258 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-07-27 21:45:29 +05:30
Pranshul b2d48c1c59 New translations strings.xml (Hebrew)
[ci skip]
2026-07-27 21:45:28 +05:30
Pranshul 7c08f8e7e0 New translations strings.xml (Italian)
[ci skip]
2026-07-27 21:45:27 +05:30
Pranshul 90a4e4ffa0 New translations strings.xml (Korean)
[ci skip]
2026-07-27 21:45:25 +05:30
Pranshul 2a4759c321 New translations strings.xml (Portuguese)
[ci skip]
2026-07-27 21:45:24 +05:30
Pranshul b4bd3bca72 New translations strings.xml (Japanese)
[ci skip]
2026-07-27 21:45:23 +05:30
Pranshul 960eaa907a New translations strings.xml (French)
[ci skip]
2026-07-27 21:45:21 +05:30
Pranshul 8c63eb4839 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-27 21:45:20 +05:30
Pranshul 7e7ec4f483 New translations strings.xml (Russian)
[ci skip]
2026-07-27 21:45:18 +05:30
Pranshul fac1037862 New translations strings.xml (Dutch)
[ci skip]
2026-07-27 21:45:17 +05:30
Pranshul d6d939f629 New translations strings.xml (Finnish)
[ci skip]
2026-07-27 21:45:15 +05:30
Pranshul 2f4a9c6070 New translations strings.xml (German)
[ci skip]
2026-07-27 21:45:14 +05:30
PranshulGG ef58d661fc Update database schema to version 49 2026-07-27 16:31:58 +05:30
PranshulGG ea10e14735 add info button to LocationsScreen top bar to show long press info snackbar 2026-07-27 16:31:45 +05:30
PranshulGG bf0ceca34d navigate to edit location screen in MainScreen and update air quality source display 2026-07-27 16:31:36 +05:30
PranshulGG bccf0092b3 use getFullLocationName utility in MainSearchBar 2026-07-27 16:31:25 +05:30
PranshulGG c2b424f347 implement air quality and AccuWeather data cleanup in WeatherDataReconcilerRepository 2026-07-27 16:31:15 +05:30
PranshulGG 06b7c6648d implement saving custom location names and add GetLocationName utility functions 2026-07-27 16:31:04 +05:30
PranshulGG 687ec11956 add overline support to ActionTile and SettingTile.ActionTile 2026-07-27 16:30:53 +05:30
PranshulGG c429f8ff3e add updateLocationCustomName to LocationsDao and integrate AccuDao into WeatherMasterDatabase with version 49 bump 2026-07-27 16:30:40 +05:30
PranshulGG c2064256ff integrate AirQualityRepositoryProvider into WeatherViewModel and update stale data cleanup logic for air quality sources 2026-07-27 16:29:57 +05:30
PranshulGG efab4d940c refine daily summary computation to use remaining hourly data and cleanup imports 2026-07-27 16:29:25 +05:30
PranshulGG 235eac4569 rename OpenMeteoAqiMapper to AqiDomainMapper and remove OpenMeteoAqiDto mapping 2026-07-27 16:29:03 +05:30
PranshulGG 843c02d58c implement AirQualityRepository in OpenMeteoAqiRepository and add domain mapper for OpenMeteo AQI 2026-07-27 16:28:53 +05:30
PranshulGG 80b32aae29 add AccuWeather AQI support and update repository dependencies 2026-07-27 16:28:23 +05:30
PranshulGG 505c7c53b4 Implement AccuWeather Air Quality support 2026-07-27 16:27:31 +05:30
PranshulGG 8bd8fb70a3 add location_long_press_info string and update multiple localizations 2026-07-27 16:26:57 +05:30
Pranshul 859c2da0f0 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-07-27 14:54:37 +05:30
Pranshul 8c881a6058 New translations strings.xml (Hebrew)
[ci skip]
2026-07-27 14:54:36 +05:30
Pranshul 74b083b503 New translations strings.xml (Russian)
[ci skip]
2026-07-27 14:54:35 +05:30
Pranshul e39be278ea New translations strings.xml (Japanese)
[ci skip]
2026-07-27 08:44:32 +05:30
Pranshul a902a33085 New translations strings.xml (Italian)
[ci skip]
2026-07-27 02:08:23 +05:30
Pranshul 9a004c28f9 New translations strings.xml (Russian)
[ci skip]
2026-07-26 20:12:24 +05:30
Pranshul 61257cddff New translations strings.xml (Russian)
[ci skip]
2026-07-26 14:03:10 +05:30
Pranshul da00862941 New translations strings.xml (Russian)
[ci skip]
2026-07-26 07:36:05 +05:30
Pranshul 7d33b699d4 New translations strings.xml (Korean)
[ci skip]
2026-07-26 01:08:23 +05:30
Pranshul 19d32f8477 New translations strings.xml (Russian)
[ci skip]
2026-07-26 01:08:22 +05:30
Pranshul 57d4e036fd New translations strings.xml (Russian)
[ci skip]
2026-07-25 19:06:18 +05:30
Pranshul 75cbf896e7 New translations strings.xml (Japanese)
[ci skip]
2026-07-25 13:07:07 +05:30
Pranshul f24ab12576 New translations strings.xml (French)
[ci skip]
2026-07-25 13:07:06 +05:30
Pranshul 698955e5d2 New translations strings.xml (Russian)
[ci skip]
2026-07-25 13:07:04 +05:30
Pranshul 7aa1e42383 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-25 06:37:03 +05:30
Pranshul 364d381376 New translations strings.xml (Russian)
[ci skip]
2026-07-25 06:37:01 +05:30
Pranshul 84118a8a7c New translations strings.xml (Dutch)
[ci skip]
2026-07-25 06:37:00 +05:30
Pranshul 0c57f8c9a6 New translations strings.xml (Finnish)
[ci skip]
2026-07-25 06:36:59 +05:30
Pranshul 72a4e0b658 New translations strings.xml (German)
[ci skip]
2026-07-25 06:36:58 +05:30
PranshulGG de8448634e Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-07-24 20:46:12 +05:30
PranshulGG e4c64b8bb9 comment out support tile in SettingsScreen and restore startDestination to NavRoutes.MAIN 2026-07-24 20:46:04 +05:30
Pranshul 6376435df2 Merge pull request #972 from PranshulGG/l10n_main
New Crowdin updates
2026-07-24 20:43:27 +05:30
Pranshul 90ea267a0e Merge branch 'main' into l10n_main
Signed-off-by: Pranshul <pranshul.devmain@gmail.com>
2026-07-24 20:43:14 +05:30
PranshulGG 5c2329ab67 fix string format crashes closes #988 2026-07-24 20:37:38 +05:30
Pranshul 03ef9582f2 New translations strings.xml (Kazakh)
[ci skip]
2026-07-24 18:30:42 +05:30
Pranshul 1a3b717cf1 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-07-24 18:30:40 +05:30
Pranshul 121efe7bc7 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-07-24 18:30:39 +05:30
Pranshul 24f33783cd New translations strings.xml (Filipino)
[ci skip]
2026-07-24 18:30:38 +05:30
Pranshul 774b88db4e New translations strings.xml (Azerbaijani)
[ci skip]
2026-07-24 18:30:36 +05:30
Pranshul 9767ee9343 New translations strings.xml (Thai)
[ci skip]
2026-07-24 18:30:35 +05:30
Pranshul 3365d59fba New translations strings.xml (Persian)
[ci skip]
2026-07-24 18:30:33 +05:30
Pranshul 10d5623c55 New translations strings.xml (Indonesian)
[ci skip]
2026-07-24 18:30:32 +05:30
Pranshul 6637c9e938 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-24 18:30:30 +05:30
Pranshul f1cb4b3991 New translations strings.xml (Vietnamese)
[ci skip]
2026-07-24 18:30:29 +05:30
Pranshul 1a06a41283 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-07-24 18:30:27 +05:30
Pranshul 3a3d836a9b New translations strings.xml (Chinese Simplified)
[ci skip]
2026-07-24 18:30:26 +05:30
Pranshul 6d188d02f9 New translations strings.xml (Ukrainian)
[ci skip]
2026-07-24 18:30:24 +05:30
Pranshul 92708eeb3a New translations strings.xml (Turkish)
[ci skip]
2026-07-24 18:30:23 +05:30
Pranshul 3af3013a93 New translations strings.xml (Swedish)
[ci skip]
2026-07-24 18:30:21 +05:30
Pranshul 7f9cdd5be2 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-07-24 18:30:20 +05:30
Pranshul 1d0eaa8789 New translations strings.xml (Slovenian)
[ci skip]
2026-07-24 18:30:19 +05:30
Pranshul 9ebe44feaa New translations strings.xml (Russian)
[ci skip]
2026-07-24 18:30:17 +05:30
Pranshul 03223ec459 New translations strings.xml (Portuguese)
[ci skip]
2026-07-24 18:30:16 +05:30
Pranshul 026b038b00 New translations strings.xml (Polish)
[ci skip]
2026-07-24 18:30:14 +05:30
Pranshul b90642aa8b New translations strings.xml (Dutch)
[ci skip]
2026-07-24 18:30:12 +05:30
Pranshul 49887b88ad New translations strings.xml (Lithuanian)
[ci skip]
2026-07-24 18:30:11 +05:30
Pranshul 7c0ca9e39b New translations strings.xml (Korean)
[ci skip]
2026-07-24 18:30:10 +05:30
Pranshul d6213f553d New translations strings.xml (Japanese)
[ci skip]
2026-07-24 18:30:08 +05:30
Pranshul 6c698403f8 New translations strings.xml (Italian)
[ci skip]
2026-07-24 18:30:07 +05:30
Pranshul 8a842cc7f6 New translations strings.xml (Hungarian)
[ci skip]
2026-07-24 18:30:05 +05:30
Pranshul 0bd04a4425 New translations strings.xml (Hebrew)
[ci skip]
2026-07-24 18:30:04 +05:30
Pranshul ad6bddc33a New translations strings.xml (Finnish)
[ci skip]
2026-07-24 18:30:03 +05:30
Pranshul 71f1563880 New translations strings.xml (Greek)
[ci skip]
2026-07-24 18:30:01 +05:30
Pranshul ec378c8e13 New translations strings.xml (German)
[ci skip]
2026-07-24 18:30:00 +05:30
Pranshul ab296ccf5e New translations strings.xml (Czech)
[ci skip]
2026-07-24 18:29:58 +05:30
Pranshul 3be0cbdfe9 New translations strings.xml (Catalan)
[ci skip]
2026-07-24 18:29:57 +05:30
Pranshul 0a2c17fec2 New translations strings.xml (Bulgarian)
[ci skip]
2026-07-24 18:29:56 +05:30
Pranshul 5242f11af5 New translations strings.xml (Spanish)
[ci skip]
2026-07-24 18:29:55 +05:30
Pranshul 2146247e61 New translations strings.xml (French)
[ci skip]
2026-07-24 18:29:53 +05:30
Pranshul 5c8f4d8e17 New translations strings.xml (Romanian)
[ci skip]
2026-07-24 18:29:52 +05:30
PranshulGG 919549f877 add alertSource, airQualitySource, and customName to weather_locations and update database schemas to v48 2026-07-24 16:09:55 +05:30
PranshulGG b1207f2d9f add handleSourceChangeForWeather and support air quality force refresh in getWeather 2026-07-24 16:09:37 +05:30
PranshulGG 0b2b752f06 add strings for location editing and weather sources 2026-07-24 16:09:24 +05:30
PranshulGG 846e95b0c2 add trailing content and placeholder styling options to DialogTextFieldTile 2026-07-24 16:09:16 +05:30
PranshulGG 43feee4576 add floatingActionButtonPosition parameter to LargeTopBarScaffold 2026-07-24 16:09:07 +05:30
PranshulGG 57c33df481 add trailing and placeholderAsValue to DialogInputTile in SettingTile.kt 2026-07-24 16:08:59 +05:30
PranshulGG 9fbdce5b69 add alertSource, airQualitySource, and customName to Location model and use string resources in LocationsScreenContent 2026-07-24 16:08:48 +05:30
PranshulGG 064a3d7b8d add navigation for EditLocationScreen and update NavRoutes with locationId argument 2026-07-24 16:08:25 +05:30
PranshulGG af0dc61e51 implement Edit Location screen with support for name editing and source selection 2026-07-24 16:08:05 +05:30
PranshulGG 09502364c7 remove DataSourceScreen.kt 2026-07-24 16:07:56 +05:30
PranshulGG e9e2894e20 add AlertSource and AirQualitySource enums and update WeatherLocationEntity with database migrations 2026-07-24 16:07:08 +05:30
Pranshul a947c9456f New translations strings.xml (Japanese)
[ci skip]
2026-07-24 12:31:35 +05:30
Pranshul 6ba4dce473 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-07-24 06:15:04 +05:30
Pranshul 675fa1f7dc New translations strings.xml (Hebrew)
[ci skip]
2026-07-24 06:15:03 +05:30
Pranshul deab4f3c11 New translations strings.xml (Greek)
[ci skip]
2026-07-24 06:15:02 +05:30
Pranshul 979b93e1cb New translations strings.xml (Lithuanian)
[ci skip]
2026-07-24 00:19:15 +05:30
Pranshul 34c51476f7 New translations strings.xml (Greek)
[ci skip]
2026-07-24 00:19:14 +05:30
Pranshul 4b9bead9cf New translations strings.xml (Kazakh)
[ci skip]
2026-07-23 18:19:21 +05:30
Pranshul c15331980b New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-07-23 18:19:19 +05:30
Pranshul b849e63db5 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-07-23 18:19:18 +05:30
Pranshul e7f1c5fad8 New translations strings.xml (Filipino)
[ci skip]
2026-07-23 18:19:16 +05:30
Pranshul 22a91455a7 New translations strings.xml (Azerbaijani)
[ci skip]
2026-07-23 18:19:15 +05:30
Pranshul e9cb5e7c37 New translations strings.xml (Thai)
[ci skip]
2026-07-23 18:19:14 +05:30
Pranshul ed03fc0d3c New translations strings.xml (Persian)
[ci skip]
2026-07-23 18:19:12 +05:30
Pranshul 339276e8cb New translations strings.xml (Indonesian)
[ci skip]
2026-07-23 18:19:11 +05:30
Pranshul 83b9eb3ebe New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-23 18:19:10 +05:30
Pranshul 35b4686b42 New translations strings.xml (Vietnamese)
[ci skip]
2026-07-23 18:19:08 +05:30
Pranshul 4715bc502f New translations strings.xml (Chinese Traditional)
[ci skip]
2026-07-23 18:19:07 +05:30
Pranshul f1d1e0a2a8 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-07-23 18:19:05 +05:30
Pranshul 7303a25190 New translations strings.xml (Ukrainian)
[ci skip]
2026-07-23 18:19:04 +05:30
Pranshul 65c3069d44 New translations strings.xml (Turkish)
[ci skip]
2026-07-23 18:19:03 +05:30
Pranshul 7587ff082d New translations strings.xml (Swedish)
[ci skip]
2026-07-23 18:19:01 +05:30
Pranshul c998379da8 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-07-23 18:19:00 +05:30
Pranshul fe807595fb New translations strings.xml (Slovenian)
[ci skip]
2026-07-23 18:18:58 +05:30
Pranshul 575861c11c New translations strings.xml (Russian)
[ci skip]
2026-07-23 18:18:56 +05:30
Pranshul ef44a199ef New translations strings.xml (Portuguese)
[ci skip]
2026-07-23 18:18:55 +05:30
Pranshul 7b5a7cc12b New translations strings.xml (Polish)
[ci skip]
2026-07-23 18:18:53 +05:30
Pranshul be29e89175 New translations strings.xml (Dutch)
[ci skip]
2026-07-23 18:18:51 +05:30
Pranshul b4f9d3e925 New translations strings.xml (Lithuanian)
[ci skip]
2026-07-23 18:18:49 +05:30
Pranshul 9dcb2847e7 New translations strings.xml (Korean)
[ci skip]
2026-07-23 18:18:48 +05:30
Pranshul dc6aeb232f New translations strings.xml (Japanese)
[ci skip]
2026-07-23 18:18:46 +05:30
Pranshul 207cd584ce New translations strings.xml (Italian)
[ci skip]
2026-07-23 18:18:45 +05:30
Pranshul 44f190efc2 New translations strings.xml (Hungarian)
[ci skip]
2026-07-23 18:18:44 +05:30
Pranshul 3207118bd9 New translations strings.xml (Hebrew)
[ci skip]
2026-07-23 18:18:42 +05:30
Pranshul 07a39f1b01 New translations strings.xml (Finnish)
[ci skip]
2026-07-23 18:18:40 +05:30
Pranshul 15987d40ad New translations strings.xml (Greek)
[ci skip]
2026-07-23 18:18:39 +05:30
Pranshul 000d01d53d New translations strings.xml (German)
[ci skip]
2026-07-23 18:18:38 +05:30
Pranshul 4ce97d2926 New translations strings.xml (Czech)
[ci skip]
2026-07-23 18:18:36 +05:30
Pranshul 85e9c335fa New translations strings.xml (Catalan)
[ci skip]
2026-07-23 18:18:35 +05:30
Pranshul 2e2513d785 New translations strings.xml (Bulgarian)
[ci skip]
2026-07-23 18:18:33 +05:30
Pranshul feb70e9fb7 New translations strings.xml (Spanish)
[ci skip]
2026-07-23 18:18:31 +05:30
Pranshul bbeda9892e New translations strings.xml (French)
[ci skip]
2026-07-23 18:18:30 +05:30
Pranshul caf2edb9a5 New translations strings.xml (Romanian)
[ci skip]
2026-07-23 18:18:28 +05:30
PranshulGG 5307930e35 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-07-23 12:55:51 +05:30
PranshulGG 98908b39d6 add DataSourceScreen and data_source navigation route 2026-07-23 12:55:42 +05:30
PranshulGG 82604383a0 updated strings 2026-07-23 12:55:26 +05:30
Pranshul 0c6ab67de5 New translations strings.xml (Finnish)
[ci skip]
2026-07-23 12:19:54 +05:30
Pranshul 39f5576871 New translations strings.xml (Russian)
[ci skip]
2026-07-23 01:53:47 +05:30
Pranshul 9c99ae0dc0 New translations strings.xml (Finnish)
[ci skip]
2026-07-23 01:53:45 +05:30
Pranshul 956febe1e4 New translations strings.xml (Finnish)
[ci skip]
2026-07-22 19:49:41 +05:30
Pranshul 0c428ab47a New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-22 12:43:33 +05:30
Pranshul cb77efa483 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-22 06:43:27 +05:30
Pranshul 65fbd34d09 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-07-21 21:34:22 +05:30
Pranshul 5eb14cf3dc New translations strings.xml (Finnish)
[ci skip]
2026-07-21 21:34:21 +05:30
Pranshul 327df68aa4 New translations strings.xml (Spanish)
[ci skip]
2026-07-21 14:50:29 +05:30
Pranshul 527d23772d New translations strings.xml (Japanese)
[ci skip]
2026-07-21 08:48:40 +05:30
Pranshul e6a04c53a7 New translations strings.xml (French)
[ci skip]
2026-07-21 08:48:39 +05:30
Pranshul 2d3e3dd5dd New translations strings.xml (Vietnamese)
[ci skip]
2026-07-21 02:50:10 +05:30
Pranshul 6e8d0eb1bd New translations strings.xml (German)
[ci skip]
2026-07-21 02:50:09 +05:30
Pranshul fd812834aa Update funding links in FUNDING.yml
Signed-off-by: Pranshul <pranshul.devmain@gmail.com>
2026-07-20 20:50:42 +05:30
Pranshul 4395b2c6a6 Update GitHub funding link format
Signed-off-by: Pranshul <pranshul.devmain@gmail.com>
2026-07-20 20:48:46 +05:30
Pranshul 289fcf2162 Add funding links to .github/FUNDING.yml
Updated funding model links for GitHub, Ko-fi, and Liberapay.

Signed-off-by: Pranshul <pranshul.devmain@gmail.com>
2026-07-20 20:46:36 +05:30
Pranshul e37f31996f New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-20 20:45:04 +05:30
Pranshul 2f3db7a43f New translations strings.xml (Hebrew)
[ci skip]
2026-07-20 20:45:02 +05:30
Pranshul 6a53ad0b08 New translations strings.xml (Finnish)
[ci skip]
2026-07-20 20:45:00 +05:30
Pranshul ca505ae9eb New translations strings.xml (French)
[ci skip]
2026-07-20 20:44:58 +05:30
Pranshul 25b9ccb847 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-20 14:30:53 +05:30
Pranshul 2df12b3089 New translations strings.xml (Polish)
[ci skip]
2026-07-20 01:03:37 +05:30
PranshulGG d6d70900d2 update readme 2026-07-19 17:20:01 +05:30
PranshulGG 5af3405efa bump versionCode to 56 and versionName to 3.7.0 2026-07-19 15:16:48 +05:30
PranshulGG b235220a3a fix syntax for ACCU_KEY secret in release workflow 2026-07-19 13:30:04 +05:30
PranshulGG 5f8e3925a5 add ACCU_KEY to release workflow 2026-07-19 13:26:29 +05:30
PranshulGG 6494789a13 update RainBlock layout to use Column for precipitation units and value display 2026-07-19 13:24:13 +05:30
PranshulGG 65d09aa3fe add support tile to settings screen and add favorite icon drawable 2026-07-19 12:42:27 +05:30
PranshulGG 9acae1ce64 fix string placeholders in French and Japanese translations and add missing summary template in German 2026-07-19 12:38:02 +05:30
PranshulGG 89fe3adfd8 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-07-19 12:15:51 +05:30
Pranshul 86736acf25 Merge pull request #967 from PranshulGG/l10n_main
New Crowdin updates
2026-07-19 12:15:36 +05:30
PranshulGG 62606fa1d2 refactor WeatherSource validation and change start destination to MAIN 2026-07-19 12:15:21 +05:30
Pranshul 7a121bdd5e New translations strings.xml (Polish)
[ci skip]
2026-07-19 00:02:23 +05:30
Pranshul c1569bd6ff New translations strings.xml (Lithuanian)
[ci skip]
2026-07-19 00:02:22 +05:30
Pranshul 41e48d7c9a New translations strings.xml (Hebrew)
[ci skip]
2026-07-19 00:02:21 +05:30
Pranshul f4829a2e52 Merge pull request #963 from PranshulGG/l10n_main
New Crowdin updates
2026-07-18 21:21:09 +05:30
Pranshul 2121c073d0 New translations strings.xml (Dutch)
[ci skip]
2026-07-18 18:06:12 +05:30
PranshulGG 15f59e043e icon drawable 2026-07-18 15:15:08 +05:30
Pranshul 48ec4cc375 New translations strings.xml (Kazakh)
[ci skip]
2026-07-18 12:04:35 +05:30
Pranshul 54a0036cc9 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-07-18 12:04:34 +05:30
Pranshul d82bfbd05f New translations strings.xml (Serbian (Latin))
[ci skip]
2026-07-18 12:04:32 +05:30
Pranshul f5f3b9bf8f New translations strings.xml (Filipino)
[ci skip]
2026-07-18 12:04:31 +05:30
Pranshul 606f020cab New translations strings.xml (Azerbaijani)
[ci skip]
2026-07-18 12:04:30 +05:30
Pranshul 1357acbd58 New translations strings.xml (Thai)
[ci skip]
2026-07-18 12:04:29 +05:30
Pranshul c0b43ebd1e New translations strings.xml (Persian)
[ci skip]
2026-07-18 12:04:28 +05:30
Pranshul 745f27fd13 New translations strings.xml (Indonesian)
[ci skip]
2026-07-18 12:04:26 +05:30
Pranshul a626c8310c New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-18 12:04:25 +05:30
Pranshul 996cf38ec4 New translations strings.xml (Vietnamese)
[ci skip]
2026-07-18 12:04:24 +05:30
Pranshul 71af7d453e New translations strings.xml (Chinese Traditional)
[ci skip]
2026-07-18 12:04:23 +05:30
Pranshul 41e6fb2189 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-07-18 12:04:21 +05:30
Pranshul 7fe05243a8 New translations strings.xml (Ukrainian)
[ci skip]
2026-07-18 12:04:20 +05:30
Pranshul 4c7654381e New translations strings.xml (Turkish)
[ci skip]
2026-07-18 12:04:19 +05:30
Pranshul 536e0262f6 New translations strings.xml (Swedish)
[ci skip]
2026-07-18 12:04:18 +05:30
Pranshul e1cdfb9049 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-07-18 12:04:17 +05:30
Pranshul ff2017586c New translations strings.xml (Slovenian)
[ci skip]
2026-07-18 12:04:15 +05:30
Pranshul b3f71e5f33 New translations strings.xml (Russian)
[ci skip]
2026-07-18 12:04:14 +05:30
Pranshul 2109efc811 New translations strings.xml (Portuguese)
[ci skip]
2026-07-18 12:04:13 +05:30
Pranshul 4116e057fa New translations strings.xml (Polish)
[ci skip]
2026-07-18 12:04:12 +05:30
Pranshul 3b9c42dfc2 New translations strings.xml (Dutch)
[ci skip]
2026-07-18 12:04:10 +05:30
Pranshul 6b2e484cb4 New translations strings.xml (Lithuanian)
[ci skip]
2026-07-18 12:04:09 +05:30
Pranshul ffb9e671f1 New translations strings.xml (Korean)
[ci skip]
2026-07-18 12:04:08 +05:30
Pranshul 606cb45c80 New translations strings.xml (Japanese)
[ci skip]
2026-07-18 12:04:07 +05:30
Pranshul a467c8e8e7 New translations strings.xml (Italian)
[ci skip]
2026-07-18 12:04:05 +05:30
Pranshul 5d6b628f99 New translations strings.xml (Hungarian)
[ci skip]
2026-07-18 12:04:04 +05:30
Pranshul 0131347f7a New translations strings.xml (Hebrew)
[ci skip]
2026-07-18 12:04:03 +05:30
Pranshul 622ab3063d New translations strings.xml (Finnish)
[ci skip]
2026-07-18 12:04:02 +05:30
Pranshul 9d839d74a3 New translations strings.xml (Greek)
[ci skip]
2026-07-18 12:04:00 +05:30
Pranshul ceb737b44b New translations strings.xml (German)
[ci skip]
2026-07-18 12:03:59 +05:30
Pranshul e2ada7c46a New translations strings.xml (Czech)
[ci skip]
2026-07-18 12:03:58 +05:30
Pranshul 597b658b08 New translations strings.xml (Catalan)
[ci skip]
2026-07-18 12:03:57 +05:30
Pranshul 142de313f0 New translations strings.xml (Bulgarian)
[ci skip]
2026-07-18 12:03:55 +05:30
Pranshul 4bee08e9b8 New translations strings.xml (Spanish)
[ci skip]
2026-07-18 12:03:54 +05:30
Pranshul 6a0e177182 New translations strings.xml (French)
[ci skip]
2026-07-18 12:03:53 +05:30
Pranshul 951c98f603 New translations strings.xml (Romanian)
[ci skip]
2026-07-18 12:03:52 +05:30
PranshulGG 564db75da6 add gadgetbridge support 2026-07-18 11:53:39 +05:30
PranshulGG 5a3d645542 view worker information 2026-07-17 20:56:00 +05:30
Pranshul 8e79aefbc7 New translations strings.xml (Italian)
[ci skip]
2026-07-17 17:25:21 +05:30
Pranshul 3ba91eaefc New translations strings.xml (Hebrew)
[ci skip]
2026-07-16 23:01:55 +05:30
Pranshul 82110f17a1 New translations strings.xml (Finnish)
[ci skip]
2026-07-16 23:01:54 +05:30
Pranshul 081c6f8836 New translations strings.xml (German)
[ci skip]
2026-07-16 23:01:52 +05:30
PranshulGG 12e95bdb3b add database schemas for versions 45 and 46 2026-07-16 20:26:12 +05:30
PranshulGG 3b95e40aa3 rain and snow star and lower thresholds 2026-07-16 20:25:36 +05:30
Pranshul a52a757f47 New translations strings.xml (Lithuanian)
[ci skip]
2026-07-16 16:42:35 +05:30
Pranshul ebc4452e61 New translations strings.xml (Japanese)
[ci skip]
2026-07-16 16:42:33 +05:30
Pranshul 641994a5c3 New translations strings.xml (French)
[ci skip]
2026-07-16 16:42:32 +05:30
PranshulGG cd7ba2d878 an error if the currently selected source isn't available for the region closes #960 2026-07-16 10:05:17 +05:30
Pranshul 4497bf0aef New translations strings.xml (Kazakh)
[ci skip]
2026-07-15 21:49:31 +05:30
Pranshul 6cddc43b33 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-07-15 21:49:30 +05:30
Pranshul 9e191c7a5d New translations strings.xml (Serbian (Latin))
[ci skip]
2026-07-15 21:49:29 +05:30
Pranshul 0e8a3a9d34 New translations strings.xml (Filipino)
[ci skip]
2026-07-15 21:49:27 +05:30
Pranshul 8497d0f535 New translations strings.xml (Azerbaijani)
[ci skip]
2026-07-15 21:49:26 +05:30
Pranshul 796af5925a New translations strings.xml (Thai)
[ci skip]
2026-07-15 21:49:24 +05:30
Pranshul a223cba972 New translations strings.xml (Persian)
[ci skip]
2026-07-15 21:49:23 +05:30
Pranshul 01ddc283b4 New translations strings.xml (Indonesian)
[ci skip]
2026-07-15 21:49:22 +05:30
Pranshul a3b9fbf5b9 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-15 21:49:20 +05:30
Pranshul 2a4e93c6c3 New translations strings.xml (Vietnamese)
[ci skip]
2026-07-15 21:49:19 +05:30
Pranshul 0f61c7dc98 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-07-15 21:49:18 +05:30
Pranshul 5e27fe3ecc New translations strings.xml (Chinese Simplified)
[ci skip]
2026-07-15 21:49:16 +05:30
Pranshul b26b205635 New translations strings.xml (Ukrainian)
[ci skip]
2026-07-15 21:49:15 +05:30
Pranshul 9326e2ddd1 New translations strings.xml (Turkish)
[ci skip]
2026-07-15 21:49:14 +05:30
Pranshul 644b99e5de New translations strings.xml (Swedish)
[ci skip]
2026-07-15 21:49:12 +05:30
Pranshul 3ac8e3cc34 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-07-15 21:49:11 +05:30
Pranshul c8edfd93e3 New translations strings.xml (Slovenian)
[ci skip]
2026-07-15 21:49:09 +05:30
Pranshul 6208bea136 New translations strings.xml (Russian)
[ci skip]
2026-07-15 21:49:08 +05:30
Pranshul cae533c6e9 New translations strings.xml (Portuguese)
[ci skip]
2026-07-15 21:49:06 +05:30
Pranshul a6aff4c2e5 New translations strings.xml (Polish)
[ci skip]
2026-07-15 21:49:05 +05:30
Pranshul 2368157d8a New translations strings.xml (Dutch)
[ci skip]
2026-07-15 21:49:03 +05:30
Pranshul f8104a9501 New translations strings.xml (Lithuanian)
[ci skip]
2026-07-15 21:49:02 +05:30
Pranshul 20faf7c5d3 New translations strings.xml (Korean)
[ci skip]
2026-07-15 21:49:01 +05:30
Pranshul 50b8b2f84f New translations strings.xml (Japanese)
[ci skip]
2026-07-15 21:48:59 +05:30
Pranshul a3259f778a New translations strings.xml (Italian)
[ci skip]
2026-07-15 21:48:58 +05:30
Pranshul ea4a24eea9 New translations strings.xml (Hungarian)
[ci skip]
2026-07-15 21:48:56 +05:30
Pranshul 16a966a9e8 New translations strings.xml (Hebrew)
[ci skip]
2026-07-15 21:48:55 +05:30
Pranshul 50475e4f16 New translations strings.xml (Finnish)
[ci skip]
2026-07-15 21:48:54 +05:30
Pranshul bda6f8d2d9 New translations strings.xml (Greek)
[ci skip]
2026-07-15 21:48:52 +05:30
Pranshul 46bf026a8d New translations strings.xml (German)
[ci skip]
2026-07-15 21:48:51 +05:30
Pranshul 3a3cddd8be New translations strings.xml (Czech)
[ci skip]
2026-07-15 21:48:50 +05:30
Pranshul e6c2b75434 New translations strings.xml (Catalan)
[ci skip]
2026-07-15 21:48:48 +05:30
Pranshul c6f8b55725 New translations strings.xml (Bulgarian)
[ci skip]
2026-07-15 21:48:47 +05:30
Pranshul 58d5eecad4 New translations strings.xml (Spanish)
[ci skip]
2026-07-15 21:48:46 +05:30
Pranshul 52db57481b New translations strings.xml (French)
[ci skip]
2026-07-15 21:48:44 +05:30
Pranshul 7e817863f4 New translations strings.xml (Romanian)
[ci skip]
2026-07-15 21:48:43 +05:30
PranshulGG 2bbb2c8537 make summary conditions nullable, and update OpenMeteo AQI forecast days 2026-07-15 20:45:57 +05:30
PranshulGG 0cac9b692b only show current hourly forecast 2026-07-15 20:44:32 +05:30
PranshulGG 733e6a8ab8 only show current hourly forecast 2026-07-15 20:44:28 +05:30
PranshulGG f0958e0ead add missing strings 2026-07-15 20:43:59 +05:30
PranshulGG 2a318c0266 add summary overview templates for day and night conditions to strings.xml 2026-07-15 20:35:38 +05:30
PranshulGG ed4d9eb150 detailed air quality closes #937 2026-07-15 15:52:57 +05:30
Pranshul cde5f618e9 New translations strings.xml (Finnish)
[ci skip]
2026-07-15 14:34:08 +05:30
Pranshul 82d70145d8 New translations strings.xml (Finnish)
[ci skip]
2026-07-14 19:19:26 +05:30
Pranshul e553d2562a Merge pull request #953 from PranshulGG/l10n_main
New Crowdin updates
2026-07-14 17:30:21 +05:30
PranshulGG 01ff4cec25 update glance to 1.3.0-alpha02 fix apostrophe escaping in summary strings 2026-07-14 17:29:58 +05:30
Pranshul 9dff05f6e5 New translations strings.xml (Finnish)
[ci skip]
2026-07-14 13:13:33 +05:30
Pranshul ee909f858f New translations strings.xml (Lithuanian)
[ci skip]
2026-07-14 04:10:27 +05:30
Pranshul cd3a883c3b New translations strings.xml (Hebrew)
[ci skip]
2026-07-14 04:10:26 +05:30
Pranshul 2acb4f9742 New translations strings.xml (Kazakh)
[ci skip]
2026-07-13 22:14:02 +05:30
Pranshul f5d8cf23e9 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-07-13 22:14:01 +05:30
Pranshul 56425e7e94 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-07-13 22:13:59 +05:30
Pranshul ee95d7f4c2 New translations strings.xml (Filipino)
[ci skip]
2026-07-13 22:13:58 +05:30
Pranshul c916a82f3e New translations strings.xml (Azerbaijani)
[ci skip]
2026-07-13 22:13:57 +05:30
Pranshul 074249a74e New translations strings.xml (Thai)
[ci skip]
2026-07-13 22:13:55 +05:30
Pranshul 5aec9a9d2b New translations strings.xml (Persian)
[ci skip]
2026-07-13 22:13:54 +05:30
Pranshul 1920c8b23d New translations strings.xml (Indonesian)
[ci skip]
2026-07-13 22:13:53 +05:30
Pranshul 50d47bbc4b New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-13 22:13:51 +05:30
Pranshul 46aad61b1b New translations strings.xml (Vietnamese)
[ci skip]
2026-07-13 22:13:50 +05:30
Pranshul a7550f0a67 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-07-13 22:13:49 +05:30
Pranshul 084f614519 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-07-13 22:13:48 +05:30
Pranshul eb31413345 New translations strings.xml (Ukrainian)
[ci skip]
2026-07-13 22:13:46 +05:30
Pranshul 723fc352a8 New translations strings.xml (Turkish)
[ci skip]
2026-07-13 22:13:45 +05:30
Pranshul 6e9e7c46e9 New translations strings.xml (Swedish)
[ci skip]
2026-07-13 22:13:44 +05:30
Pranshul 82cc93c772 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-07-13 22:13:42 +05:30
Pranshul e77815b3fd New translations strings.xml (Slovenian)
[ci skip]
2026-07-13 22:13:41 +05:30
Pranshul 8f4cd91157 New translations strings.xml (Russian)
[ci skip]
2026-07-13 22:13:40 +05:30
Pranshul 740caaa7c9 New translations strings.xml (Portuguese)
[ci skip]
2026-07-13 22:13:38 +05:30
Pranshul 5dcb915da6 New translations strings.xml (Polish)
[ci skip]
2026-07-13 22:13:37 +05:30
Pranshul 6f9e2739d1 New translations strings.xml (Dutch)
[ci skip]
2026-07-13 22:13:36 +05:30
Pranshul e74d372a6f New translations strings.xml (Lithuanian)
[ci skip]
2026-07-13 22:13:34 +05:30
Pranshul 2245a6d952 New translations strings.xml (Korean)
[ci skip]
2026-07-13 22:13:33 +05:30
Pranshul 913d25a7d3 New translations strings.xml (Japanese)
[ci skip]
2026-07-13 22:13:31 +05:30
Pranshul 36e27f378f New translations strings.xml (Italian)
[ci skip]
2026-07-13 22:13:30 +05:30
Pranshul faefff91f5 New translations strings.xml (Hungarian)
[ci skip]
2026-07-13 22:13:28 +05:30
Pranshul e80935e9d2 New translations strings.xml (Hebrew)
[ci skip]
2026-07-13 22:13:27 +05:30
Pranshul 4fa0673b8e New translations strings.xml (Finnish)
[ci skip]
2026-07-13 22:13:25 +05:30
Pranshul 2623963eb8 New translations strings.xml (Greek)
[ci skip]
2026-07-13 22:13:24 +05:30
Pranshul 09bb78b884 New translations strings.xml (German)
[ci skip]
2026-07-13 22:13:22 +05:30
Pranshul 1e5497b6cc New translations strings.xml (Czech)
[ci skip]
2026-07-13 22:13:21 +05:30
Pranshul d7c37109ef New translations strings.xml (Catalan)
[ci skip]
2026-07-13 22:13:19 +05:30
Pranshul ee34637cd6 New translations strings.xml (Bulgarian)
[ci skip]
2026-07-13 22:13:18 +05:30
Pranshul 74ba3a3b69 New translations strings.xml (Spanish)
[ci skip]
2026-07-13 22:13:16 +05:30
Pranshul e233f51641 New translations strings.xml (French)
[ci skip]
2026-07-13 22:13:15 +05:30
Pranshul 3b0cc96335 New translations strings.xml (Romanian)
[ci skip]
2026-07-13 22:13:13 +05:30
PranshulGG ab8906b51a Improved summary 2026-07-13 22:06:41 +05:30
PranshulGG f720ef1d33 Improved summary 2026-07-13 22:06:35 +05:30
PranshulGG 805167b703 update weather summary string templates 2026-07-13 22:04:23 +05:30
PranshulGG 11f033d026 add meteo am for italy as a source closes #958 2026-07-13 20:23:13 +05:30
PranshulGG 353189d018 add meteo am for italy as a source closes #958 2026-07-13 20:22:54 +05:30
PranshulGG 060c474268 add meteo am for italy as a source closes #958 2026-07-13 20:22:24 +05:30
Pranshul eb493e1001 New translations strings.xml (Hebrew)
[ci skip]
2026-07-13 16:08:51 +05:30
PranshulGG f73101a69e update widget labels, add Weather 4 widget receiver, and use AppException in SmhiRepository 2026-07-12 17:27:32 +05:30
PranshulGG 96735101ab add Weather4Widget support and include conditionName in WidgetDailyItem mapping 2026-07-12 17:27:09 +05:30
PranshulGG 127f86bcd9 add date and clock variants to WidgetVariant enum 2026-07-12 17:27:00 +05:30
PranshulGG d3f45f2de2 add showDailyInsteadOfCurrent flag to WidgetConfig and support Weather4 widget 2026-07-12 17:26:49 +05:30
PranshulGG d7eb691168 filter widget variants and update size slider steps in widget configurations 2026-07-12 17:26:37 +05:30
PranshulGG bb71636ed3 fix uv index level 2026-07-12 17:26:06 +05:30
PranshulGG f98a890728 set clock format 2026-07-12 17:25:56 +05:30
PranshulGG f2ac00b6da AccuWeather as a source 2026-07-12 17:25:42 +05:30
PranshulGG 3ce0ca1adf implement Weather 4 widget with clock and date variants and configuration UI 2026-07-12 17:24:51 +05:30
Pranshul 68d1960014 New translations strings.xml (German)
[ci skip]
2026-07-12 07:38:47 +05:30
Pranshul 28407cbec3 New translations strings.xml (Ukrainian)
[ci skip]
2026-07-12 01:42:29 +05:30
Pranshul 4bda0631da New translations strings.xml (Ukrainian)
[ci skip]
2026-07-11 01:43:43 +05:30
Pranshul da05bf3d37 New translations strings.xml (Polish)
[ci skip]
2026-07-09 21:31:05 +05:30
Pranshul bd3719d833 New translations strings.xml (Hebrew)
[ci skip]
2026-07-09 21:31:03 +05:30
Pranshul cb02462cc2 New translations strings.xml (Italian)
[ci skip]
2026-07-09 15:35:01 +05:30
Pranshul c81e4a87db New translations strings.xml (Bulgarian)
[ci skip]
2026-07-09 15:35:00 +05:30
Pranshul 68bc23ecfb New translations strings.xml (Japanese)
[ci skip]
2026-07-09 08:23:04 +05:30
PranshulGG 6baa451b13 replace SharedPreferences injection with PreferencesHelper and update widget mapping signatures 2026-07-08 22:20:05 +05:30
PranshulGG 03d085aade provide SharedPreferences in AppModule and inject it into WeatherViewModel and widget mapping logic 2026-07-08 21:20:02 +05:30
PranshulGG 38d07fe2df adjust scroll offset in DailyDaysHeader and remove unused imports in MainActivity 2026-07-08 21:19:30 +05:30
PranshulGG b86c012bcb inject SharedPreferences into WeatherWorker and WidgetReload and update widget mapping logic 2026-07-08 21:19:07 +05:30
PranshulGG 536dc57357 add icon size configuration to horizontal weather widgets and expand font size range 2026-07-08 21:18:43 +05:30
Pranshul d5d409314c New translations strings.xml (French)
[ci skip]
2026-07-08 20:32:24 +05:30
PranshulGG 1fe7f7fb16 remove delay in WeatherWorker, use WORK_NAME constant in scheduler, and trigger reschedule on interval change 2026-07-08 15:24:44 +05:30
PranshulGG 51f8f7f0a5 add light and dark widget hourly container colors 2026-07-08 15:24:30 +05:30
PranshulGG 3633056517 remove shadow text layers and Box wrappers 2026-07-08 15:24:19 +05:30
PranshulGG 6d0d3be00e add custom background and text theme support for weather widgets and update configuration settings 2026-07-08 15:24:06 +05:30
PranshulGG 6644427470 add hideShadow option to clock and date views and increase configuration size ranges 2026-07-08 15:23:37 +05:30
PranshulGG cd2de7f75c Glance widget text color can now be changed closes #942 2026-07-08 15:08:31 +05:30
Pranshul 675eb41f1b New translations strings.xml (Kazakh)
[ci skip]
2026-07-08 14:21:28 +05:30
Pranshul 521cddeed0 New translations strings.xml (Vietnamese)
[ci skip]
2026-07-08 02:12:01 +05:30
Pranshul 0b06dc5816 New translations strings.xml (Hebrew)
[ci skip]
2026-07-08 02:11:59 +05:30
Pranshul f356fbfb72 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-07-07 20:11:16 +05:30
PranshulGG a6dcd6bbd3 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-07-07 14:47:16 +05:30
PranshulGG 6dae31fe00 update glance version to 1.1.1 2026-07-07 14:47:09 +05:30
PranshulGG 95f1ba152e fix parameter order in WeatherWidgetLarge 2026-07-07 14:42:38 +05:30
PranshulGG a2481dd06b simplify daily weather condition mapping 2026-07-07 14:42:16 +05:30
PranshulGG 2026b7ef7d update daily weather condition logic and temperature source in day summary 2026-07-07 14:41:48 +05:30
PranshulGG 4b13ed3ca3 Improved widget names 2026-07-07 14:41:35 +05:30
PranshulGG 21bd675681 remove updatePeriodMillis from widget provider info files 2026-07-07 14:41:31 +05:30
PranshulGG 155f49707f refactor widget state management and optimize update logic using updateAll closes #947 2026-07-07 14:41:09 +05:30
Pranshul 9198a86d11 New translations strings.xml (Lithuanian)
[ci skip]
2026-07-07 13:40:32 +05:30
Pranshul a17a29cc7c New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-07 00:03:27 +05:30
Pranshul 4e330845f7 Merge pull request #936 from PranshulGG/l10n_main
New Crowdin updates
2026-07-06 22:32:28 +05:30
Pranshul c3c73d96f6 New translations strings.xml (Dutch)
[ci skip]
2026-07-06 18:06:05 +05:30
Pranshul 8048e631ae New translations strings.xml (Lithuanian)
[ci skip]
2026-07-06 18:06:03 +05:30
Pranshul da0ba5bd3f New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-07-06 11:45:11 +05:30
Pranshul f79b496852 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-07-06 11:45:10 +05:30
Pranshul ddd7b50da5 New translations strings.xml (Filipino)
[ci skip]
2026-07-06 11:45:08 +05:30
Pranshul 6346a55e5b New translations strings.xml (Azerbaijani)
[ci skip]
2026-07-06 11:45:07 +05:30
Pranshul b1df66c011 New translations strings.xml (Thai)
[ci skip]
2026-07-06 11:45:06 +05:30
Pranshul 251c38ede0 New translations strings.xml (Persian)
[ci skip]
2026-07-06 11:45:04 +05:30
Pranshul 29e221da19 New translations strings.xml (Indonesian)
[ci skip]
2026-07-06 11:45:03 +05:30
Pranshul f173d5ed3c New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-07-06 11:45:02 +05:30
Pranshul db80684e32 New translations strings.xml (Vietnamese)
[ci skip]
2026-07-06 11:45:00 +05:30
Pranshul 095ac63cee New translations strings.xml (Chinese Traditional)
[ci skip]
2026-07-06 11:44:59 +05:30
Pranshul 84d4d21d5e New translations strings.xml (Chinese Simplified)
[ci skip]
2026-07-06 11:44:57 +05:30
Pranshul 9378dc577f New translations strings.xml (Ukrainian)
[ci skip]
2026-07-06 11:44:56 +05:30
Pranshul d0f113e30e New translations strings.xml (Turkish)
[ci skip]
2026-07-06 11:44:54 +05:30
Pranshul 673fbc1a5a New translations strings.xml (Swedish)
[ci skip]
2026-07-06 11:44:53 +05:30
Pranshul 157c16b32c New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-07-06 11:44:51 +05:30
Pranshul 3bc416bfa0 New translations strings.xml (Slovenian)
[ci skip]
2026-07-06 11:44:49 +05:30
Pranshul 72d965898f New translations strings.xml (Russian)
[ci skip]
2026-07-06 11:44:48 +05:30
Pranshul e2b3f88d28 New translations strings.xml (Portuguese)
[ci skip]
2026-07-06 11:44:47 +05:30
Pranshul 9eba8f09fc New translations strings.xml (Polish)
[ci skip]
2026-07-06 11:44:45 +05:30
Pranshul cac973a3af New translations strings.xml (Dutch)
[ci skip]
2026-07-06 11:44:43 +05:30
Pranshul 3d403ca096 New translations strings.xml (Lithuanian)
[ci skip]
2026-07-06 11:44:42 +05:30
Pranshul 8b3a846d29 New translations strings.xml (Korean)
[ci skip]
2026-07-06 11:44:40 +05:30
Pranshul b179ca0dc9 New translations strings.xml (Japanese)
[ci skip]
2026-07-06 11:44:38 +05:30
Pranshul d043e1c87e New translations strings.xml (Italian)
[ci skip]
2026-07-06 11:44:37 +05:30
Pranshul 6989340ef1 New translations strings.xml (Hungarian)
[ci skip]
2026-07-06 11:44:35 +05:30
Pranshul bbce3ba5ae New translations strings.xml (Hebrew)
[ci skip]
2026-07-06 11:44:34 +05:30
Pranshul 8efc7a96af New translations strings.xml (Finnish)
[ci skip]
2026-07-06 11:44:33 +05:30
Pranshul c37c780eb2 New translations strings.xml (Greek)
[ci skip]
2026-07-06 11:44:31 +05:30
Pranshul 795d5bcef3 New translations strings.xml (German)
[ci skip]
2026-07-06 11:44:29 +05:30
Pranshul c11318f163 New translations strings.xml (Czech)
[ci skip]
2026-07-06 11:44:28 +05:30
Pranshul 10b98fa78f New translations strings.xml (Catalan)
[ci skip]
2026-07-06 11:44:26 +05:30
Pranshul fdbd28e84d New translations strings.xml (Bulgarian)
[ci skip]
2026-07-06 11:44:25 +05:30
Pranshul 38d13e54b6 New translations strings.xml (Spanish)
[ci skip]
2026-07-06 11:44:23 +05:30
Pranshul cee4ddf86d New translations strings.xml (French)
[ci skip]
2026-07-06 11:44:21 +05:30
Pranshul 4460b663c4 New translations strings.xml (Romanian)
[ci skip]
2026-07-06 11:44:20 +05:30
PranshulGG a097b4f2fd add new strings closes #946 2026-07-06 11:32:49 +05:30
Pranshul c560a3b958 New translations strings.xml (Russian)
[ci skip]
2026-07-05 19:01:59 +05:30
Pranshul f701fd56b5 New translations strings.xml (Catalan)
[ci skip]
2026-07-05 19:01:57 +05:30
Pranshul c9244e2efd New translations strings.xml (Spanish)
[ci skip]
2026-07-05 19:01:56 +05:30
Pranshul e056d71632 New translations strings.xml (Russian)
[ci skip]
2026-07-05 13:01:49 +05:30
Pranshul d45ee763dd New translations strings.xml (Italian)
[ci skip]
2026-07-05 03:12:53 +05:30
Pranshul 1afcdc503e New translations strings.xml (Italian)
[ci skip]
2026-07-04 21:16:02 +05:30
PranshulGG ed9c2bcf3a use max temperature instead of average for summary headlines closes #944 2026-07-03 15:30:01 +05:30
PranshulGG 7e576900ea calculate mean weather condition from hourly data 2026-07-03 13:54:56 +05:30
Pranshul 98d2883d26 New translations strings.xml (Turkish)
[ci skip]
2026-07-02 22:48:54 +05:30
Pranshul bc710505f5 New translations strings.xml (Lithuanian)
[ci skip]
2026-07-02 22:48:52 +05:30
Pranshul ba81fb4f85 New translations strings.xml (Dutch)
[ci skip]
2026-07-02 16:21:34 +05:30
PranshulGG 067bca4af1 Fixed date formatting crashes for ECCC 2026-07-02 10:18:04 +05:30
PranshulGG 900713ca3d Fixed search errors #919 2026-07-02 10:17:53 +05:30
Pranshul 7c7d6d99c2 New translations strings.xml (Ukrainian)
[ci skip]
2026-07-02 02:17:11 +05:30
Pranshul 4ca4dc9b96 New translations strings.xml (Polish)
[ci skip]
2026-07-02 02:17:10 +05:30
Pranshul e3ce217a70 New translations strings.xml (Dutch)
[ci skip]
2026-07-02 02:17:09 +05:30
Pranshul b9a32b1640 New translations strings.xml (Hebrew)
[ci skip]
2026-07-02 02:17:08 +05:30
Pranshul 3962d45c8f New translations strings.xml (French)
[ci skip]
2026-07-01 20:18:12 +05:30
Pranshul 875d6e7b80 New translations strings.xml (Italian)
[ci skip]
2026-06-30 22:50:27 +05:30
PranshulGG c34f113de3 Fixed wind speed forecast using the wrong time 2026-06-30 20:43:13 +05:30
Pranshul 6089afc23e New translations strings.xml (Japanese)
[ci skip]
2026-06-30 15:50:57 +05:30
PranshulGG bb3822718d add source request button to WeatherSourcesScreen and bump version to 3.6.0 2026-06-30 09:50:00 +05:30
PranshulGG a9af38eb38 fix string format placeholders in Korean and Portuguese translations 2026-06-30 09:39:54 +05:30
PranshulGG 574a167b07 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-06-30 09:26:46 +05:30
PranshulGG c8d9bf058f round pressure values to integers in PressureHourlyCard.kt 2026-06-30 09:26:34 +05:30
PranshulGG 842db00f21 refactor WidgetWeatherUpdater to use a generic update function, add error logging, and ensure notification is hidden in WeatherWorker catch block 2026-06-30 09:26:27 +05:30
PranshulGG 33cf77ba27 Fixed landscape/tablet layout issues 2026-06-30 09:26:06 +05:30
Pranshul 020fe12043 Merge pull request #932 from PranshulGG/l10n_main
New Crowdin updates
2026-06-30 09:25:44 +05:30
Pranshul 67037e82a6 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-06-30 00:34:31 +05:30
Pranshul d04fab22cc New translations strings.xml (Serbian (Latin))
[ci skip]
2026-06-30 00:34:30 +05:30
Pranshul abced8efdd New translations strings.xml (Filipino)
[ci skip]
2026-06-30 00:34:28 +05:30
Pranshul c6945cf380 New translations strings.xml (Azerbaijani)
[ci skip]
2026-06-30 00:34:27 +05:30
Pranshul e40d1a7f89 New translations strings.xml (Thai)
[ci skip]
2026-06-30 00:34:25 +05:30
Pranshul ae81dda885 New translations strings.xml (Persian)
[ci skip]
2026-06-30 00:34:24 +05:30
Pranshul 81a2e142b0 New translations strings.xml (Indonesian)
[ci skip]
2026-06-30 00:34:22 +05:30
Pranshul a3ba8a1dab New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-06-30 00:34:21 +05:30
Pranshul e06b2dcbda New translations strings.xml (Vietnamese)
[ci skip]
2026-06-30 00:34:19 +05:30
Pranshul 9086d09201 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-06-30 00:34:18 +05:30
Pranshul 26870df47d New translations strings.xml (Chinese Simplified)
[ci skip]
2026-06-30 00:34:17 +05:30
Pranshul b119a39c71 New translations strings.xml (Ukrainian)
[ci skip]
2026-06-30 00:34:15 +05:30
Pranshul 7a47a8f6b7 New translations strings.xml (Turkish)
[ci skip]
2026-06-30 00:34:14 +05:30
Pranshul e80edc1e6a New translations strings.xml (Swedish)
[ci skip]
2026-06-30 00:34:12 +05:30
Pranshul a869c48a68 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-06-30 00:34:11 +05:30
Pranshul 3e44617612 New translations strings.xml (Slovenian)
[ci skip]
2026-06-30 00:34:09 +05:30
Pranshul c80da8aec5 New translations strings.xml (Russian)
[ci skip]
2026-06-30 00:34:08 +05:30
Pranshul aa92444824 New translations strings.xml (Portuguese)
[ci skip]
2026-06-30 00:34:06 +05:30
Pranshul fc42fef72e New translations strings.xml (Polish)
[ci skip]
2026-06-30 00:34:04 +05:30
Pranshul 799c99e0ab New translations strings.xml (Dutch)
[ci skip]
2026-06-30 00:34:03 +05:30
Pranshul edcf0be6dc New translations strings.xml (Lithuanian)
[ci skip]
2026-06-30 00:34:01 +05:30
Pranshul 8cdfe8766b New translations strings.xml (Korean)
[ci skip]
2026-06-30 00:34:00 +05:30
Pranshul e356fdeff0 New translations strings.xml (Japanese)
[ci skip]
2026-06-30 00:33:58 +05:30
Pranshul 23a120f873 New translations strings.xml (Italian)
[ci skip]
2026-06-30 00:33:56 +05:30
Pranshul 2b6381cdd5 New translations strings.xml (Hungarian)
[ci skip]
2026-06-30 00:33:55 +05:30
Pranshul 0069db761b New translations strings.xml (Hebrew)
[ci skip]
2026-06-30 00:33:53 +05:30
Pranshul 1691aeebb5 New translations strings.xml (Finnish)
[ci skip]
2026-06-30 00:33:51 +05:30
Pranshul ee110d7037 New translations strings.xml (Greek)
[ci skip]
2026-06-30 00:33:50 +05:30
Pranshul 45016c578f New translations strings.xml (German)
[ci skip]
2026-06-30 00:33:48 +05:30
Pranshul ec1ed2d8cc New translations strings.xml (Czech)
[ci skip]
2026-06-30 00:33:46 +05:30
Pranshul 79ce021fe4 New translations strings.xml (Catalan)
[ci skip]
2026-06-30 00:33:45 +05:30
Pranshul 9512f781eb New translations strings.xml (Bulgarian)
[ci skip]
2026-06-30 00:33:42 +05:30
Pranshul 247c3de3bb New translations strings.xml (Spanish)
[ci skip]
2026-06-30 00:33:41 +05:30
Pranshul 9a151c9072 New translations strings.xml (French)
[ci skip]
2026-06-30 00:33:39 +05:30
Pranshul 5cbffde74b New translations strings.xml (Romanian)
[ci skip]
2026-06-30 00:33:37 +05:30
PranshulGG 5cc45eca52 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-06-29 17:21:35 +05:30
Pranshul bc57486911 Merge pull request #931 from PranshulGG/l10n_main
New Crowdin updates
2026-06-29 17:21:29 +05:30
PranshulGG 7986a5d531 add opacity and photo_size_select_large vector drawables 2026-06-29 17:21:11 +05:30
PranshulGG 7866d78c85 delete 2026-06-29 17:21:02 +05:30
PranshulGG b57693a125 remove skipForegroundCheck argument from updateAllWidgets call in WeatherViewModel 2026-06-29 17:20:10 +05:30
PranshulGG e0383fcaf5 remove skipForegroundCheck argument from updateAllWidgets call in WeatherViewModel 2026-06-29 17:20:06 +05:30
PranshulGG be7cf6219d add error_no_results_found string resource 2026-06-29 17:19:57 +05:30
PranshulGG eb9f8445a4 add ReloadButton to SummaryWidget and remove onUpdate worker call in SummaryWidgetReceiver 2026-06-29 17:19:50 +05:30
PranshulGG c571ecd56a add ReloadButton and ReloadAction for widget reloading 2026-06-29 17:17:49 +05:30
PranshulGG ae42bc0b25 add configuration activity to weather widgets and update pill widget dimensions and styling 2026-06-29 17:17:38 +05:30
PranshulGG a065a59b56 update widget preview drawables 2026-06-29 17:17:24 +05:30
PranshulGG 9a0489e007 make search results nullable in GeoNames and OpenMeteo models and handle null/empty cases in mappers 2026-06-29 17:17:12 +05:30
PranshulGG d63b32cd01 improve search error handling and empty result messaging, and remove focus clearing in SearchFloatingToolbar 2026-06-29 17:16:48 +05:30
PranshulGG 419ff8eff3 add WidgetVariant enum class for widget sizes 2026-06-29 17:16:33 +05:30
PranshulGG 444b51c40b update WidgetConfig with new display properties and add support for WeatherWidget and WeatherHorizontalWidget in WidgetConfigActivity 2026-06-29 17:16:22 +05:30
PranshulGG 08db096cdf refactor WidgetHourlyItem to use custom sizes and add WidgetReload class for widget updates 2026-06-29 17:16:10 +05:30
PranshulGG 13747a633b update sizeMode to Exact in WidgetPill and remove onUpdate in WidgetPillReceiver 2026-06-29 17:15:58 +05:30
PranshulGG eb6b4b3640 refactor WeatherWorker and remove appTheme from widget state logic 2026-06-29 17:15:29 +05:30
PranshulGG 93637dab4a refactor WeatherWidgetPill UI to use fixed sizes and add ReloadButton for empty state 2026-06-29 17:14:57 +05:30
PranshulGG b537539156 add widget configuration screen and support for large, compact, and small variants 2026-06-29 17:14:45 +05:30
PranshulGG 29db2465d9 add configuration screen and support for dynamic font sizes and themes in horizontal weather widgets 2026-06-29 17:13:54 +05:30
PranshulGG e0d19e471d refactor Glance widget configuration layout and update UI styling with a reload button 2026-06-29 17:13:16 +05:30
PranshulGG f02de5c042 add font size, icon size, and forecast count customization to ClockDailyWidget and its configuration UI 2026-06-29 17:12:36 +05:30
PranshulGG 46bccf3b24 add dynamic text sizing and adaptive theme colors to clock and date widgets 2026-06-29 17:12:02 +05:30
PranshulGG fe6cf88a7e remove unused sys_clock layout files 2026-06-29 17:11:51 +05:30
Pranshul 7fedac7aba New translations strings.xml (Lithuanian)
[ci skip]
2026-06-29 14:45:12 +05:30
Pranshul b386b75182 New translations strings.xml (Ukrainian)
[ci skip]
2026-06-28 23:23:49 +05:30
Pranshul 4a069f0f91 New translations strings.xml (Czech)
[ci skip]
2026-06-28 23:23:48 +05:30
PranshulGG 2074122fb4 update periodic work policy to UPDATE, and refactor notification context usage 2026-06-27 20:29:55 +05:30
PranshulGG 327ea2ff77 Fixed Missing weather condition for DWD closes #915 2026-06-27 20:29:24 +05:30
Pranshul f78376eec3 Merge pull request #926 from PranshulGG/l10n_main
New Crowdin updates
2026-06-27 20:14:14 +05:30
Pranshul fffa99063e New translations strings.xml (Korean)
[ci skip]
2026-06-27 15:48:19 +05:30
Pranshul 3e9af6bfae New translations strings.xml (Bulgarian)
[ci skip]
2026-06-27 06:15:18 +05:30
Pranshul c613db6fbd New translations strings.xml (Bulgarian)
[ci skip]
2026-06-26 23:27:06 +05:30
Pranshul 379d0cafd2 New translations strings.xml (Lithuanian)
[ci skip]
2026-06-26 12:12:28 +05:30
Pranshul 7dcd7d9a0e New translations strings.xml (Spanish)
[ci skip]
2026-06-26 05:13:26 +05:30
Pranshul 73c05c434e Merge pull request #914 from PranshulGG/l10n_main
New Crowdin updates
2026-06-25 21:47:33 +05:30
Pranshul 6d16c4b2cd Merge pull request #923 from FSaurenbach/main
DWD: Do not show incomplete days (except current day)
2026-06-25 21:45:54 +05:30
PranshulGG 3fe9825b7b Fixed Crashes for FMI #924 2026-06-25 21:44:22 +05:30
Ferdinand Saurenbach 3490af955d DWD: Do not show incomplete days (except current day) 2026-06-25 14:34:46 +02:00
Pranshul 1721eb3153 New translations strings.xml (Bulgarian)
[ci skip]
2026-06-25 15:10:42 +05:30
Pranshul f5d3399937 New translations strings.xml (French)
[ci skip]
2026-06-25 15:10:40 +05:30
Pranshul b3fcf452a8 New translations strings.xml (Greek)
[ci skip]
2026-06-25 15:10:39 +05:30
Pranshul 138d9c064c New translations strings.xml (Greek)
[ci skip]
2026-06-25 08:26:32 +05:30
Pranshul e8339c69b6 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-06-24 23:58:46 +05:30
PranshulGG 2a17909935 bump version code and version name to 3.5.1 (54) 2026-06-24 14:40:11 +05:30
PranshulGG b133d25311 Fixed wrong daily icons 2026-06-24 14:39:33 +05:30
PranshulGG c531e65c44 Fixed widget crashes closes #909 2026-06-24 14:39:20 +05:30
PranshulGG 9731d8960f add Hebrew and Lithuanian to the language list 2026-06-24 12:11:49 +05:30
PranshulGG 59f0366933 update source tile title to use fullName in MainScreenBottomSheets 2026-06-24 12:01:13 +05:30
PranshulGG 8edf1f28fc bump version to 3.5.0, add BMKG and China weather sources, and update Crowdin badges 2026-06-24 11:49:15 +05:30
PranshulGG 4474b6a5eb Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster
# Conflicts:
#	app/src/main/res/values-pt-rBR/strings.xml
2026-06-24 11:37:58 +05:30
Pranshul 78f2226b7a Merge pull request #908 from PranshulGG/l10n_main
New Crowdin updates
2026-06-24 11:37:29 +05:30
PranshulGG 9db951c67d fix string format placeholders in Brazilian Portuguese translations 2026-06-24 11:37:18 +05:30
Pranshul ac23e28fe4 New translations strings.xml (Hebrew)
[ci skip]
2026-06-24 11:36:28 +05:30
Pranshul e37b8470f5 New translations strings.xml (Lithuanian)
[ci skip]
2026-06-24 11:36:27 +05:30
Pranshul eeaf41b468 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-06-24 11:36:25 +05:30
Pranshul 2fc1fc579b New translations strings.xml (Serbian (Latin))
[ci skip]
2026-06-24 11:36:24 +05:30
Pranshul 1963ee205c New translations strings.xml (Filipino)
[ci skip]
2026-06-24 11:36:23 +05:30
Pranshul 5c4902b7dd New translations strings.xml (Azerbaijani)
[ci skip]
2026-06-24 11:36:22 +05:30
Pranshul 2f8b14b535 New translations strings.xml (Thai)
[ci skip]
2026-06-24 11:36:21 +05:30
Pranshul 4f5b8d5bb6 New translations strings.xml (Persian)
[ci skip]
2026-06-24 11:36:20 +05:30
Pranshul 432156e747 New translations strings.xml (Indonesian)
[ci skip]
2026-06-24 11:36:18 +05:30
Pranshul dd94c0d9ba New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-06-24 11:36:17 +05:30
Pranshul 4a14a10666 New translations strings.xml (Vietnamese)
[ci skip]
2026-06-24 11:36:16 +05:30
Pranshul d122733b4c New translations strings.xml (Chinese Traditional)
[ci skip]
2026-06-24 11:36:14 +05:30
Pranshul a0bf49861c New translations strings.xml (Chinese Simplified)
[ci skip]
2026-06-24 11:36:13 +05:30
Pranshul 48dee56c7e New translations strings.xml (Ukrainian)
[ci skip]
2026-06-24 11:36:12 +05:30
Pranshul 4cb78607fd New translations strings.xml (Turkish)
[ci skip]
2026-06-24 11:36:11 +05:30
Pranshul f4f0183097 New translations strings.xml (Swedish)
[ci skip]
2026-06-24 11:36:10 +05:30
Pranshul e85a0073f6 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-06-24 11:36:09 +05:30
Pranshul 741d014897 New translations strings.xml (Slovenian)
[ci skip]
2026-06-24 11:36:08 +05:30
Pranshul f6420ffa2f New translations strings.xml (Russian)
[ci skip]
2026-06-24 11:36:07 +05:30
Pranshul f0c914b4b0 New translations strings.xml (Portuguese)
[ci skip]
2026-06-24 11:36:06 +05:30
Pranshul 459ab7e8af New translations strings.xml (Polish)
[ci skip]
2026-06-24 11:36:04 +05:30
Pranshul 96add1f35a New translations strings.xml (Dutch)
[ci skip]
2026-06-24 11:36:03 +05:30
Pranshul 7b49d9d904 New translations strings.xml (Korean)
[ci skip]
2026-06-24 11:36:02 +05:30
Pranshul 7b917b6c78 New translations strings.xml (Japanese)
[ci skip]
2026-06-24 11:36:01 +05:30
Pranshul 255dfce685 New translations strings.xml (Italian)
[ci skip]
2026-06-24 11:36:00 +05:30
Pranshul 8a2f9ab297 New translations strings.xml (Hungarian)
[ci skip]
2026-06-24 11:35:59 +05:30
Pranshul 1c1fe1af11 New translations strings.xml (Finnish)
[ci skip]
2026-06-24 11:35:58 +05:30
Pranshul 2cbf37b8e0 New translations strings.xml (Greek)
[ci skip]
2026-06-24 11:35:57 +05:30
Pranshul b4b5118124 New translations strings.xml (German)
[ci skip]
2026-06-24 11:35:56 +05:30
Pranshul 85538040a8 New translations strings.xml (Czech)
[ci skip]
2026-06-24 11:35:54 +05:30
Pranshul 5eb58e7bca New translations strings.xml (Catalan)
[ci skip]
2026-06-24 11:35:53 +05:30
Pranshul c490881747 New translations strings.xml (Bulgarian)
[ci skip]
2026-06-24 11:35:52 +05:30
Pranshul ba1656d3d5 New translations strings.xml (Spanish)
[ci skip]
2026-06-24 11:35:51 +05:30
Pranshul eb9e92b55a New translations strings.xml (French)
[ci skip]
2026-06-24 11:35:50 +05:30
Pranshul b18c3f8bea New translations strings.xml (Romanian)
[ci skip]
2026-06-24 11:35:49 +05:30
Pranshul 2395382c95 Merge pull request #903 from PranshulGG/l10n_main
New Crowdin updates
2026-06-24 11:24:54 +05:30
PranshulGG c1b17ed0d2 update WeatherWorker to treat background updates as manual refresh 2026-06-24 11:23:39 +05:30
PranshulGG 1c091f78eb add null checks for precipitation probability in SnowHourlyCard and RainHourlyCard 2026-06-24 11:23:23 +05:30
PranshulGG f3b4a57c40 add BMKG weather source support for Indonesia closes #900 2026-06-24 11:21:52 +05:30
PranshulGG de35f8f78e refactor VisibilityBlock layout and add descriptive visibility labels 2026-06-24 09:55:32 +05:30
PranshulGG ecab4f1df0 add font_download_24px vector drawable 2026-06-24 08:51:07 +05:30
PranshulGG 3c2f341315 display average wind speed in the daily forecast instead of max 2026-06-24 08:50:54 +05:30
Pranshul 8adff8837c New translations strings.xml (Polish)
[ci skip]
2026-06-24 04:26:40 +05:30
Pranshul 4ab3154a2d New translations strings.xml (Hebrew)
[ci skip]
2026-06-23 22:06:13 +05:30
Pranshul fe0aa8edad New translations strings.xml (Lithuanian)
[ci skip]
2026-06-23 22:06:12 +05:30
Pranshul fbdf56fe49 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-06-23 22:06:10 +05:30
Pranshul 60caaf8fac New translations strings.xml (Serbian (Latin))
[ci skip]
2026-06-23 22:06:09 +05:30
Pranshul 37dfde7536 New translations strings.xml (Filipino)
[ci skip]
2026-06-23 22:06:07 +05:30
Pranshul d6ced47723 New translations strings.xml (Azerbaijani)
[ci skip]
2026-06-23 22:06:06 +05:30
Pranshul d0e9fde71b New translations strings.xml (Thai)
[ci skip]
2026-06-23 22:06:04 +05:30
Pranshul a5c2fdd7c0 New translations strings.xml (Persian)
[ci skip]
2026-06-23 22:06:03 +05:30
Pranshul 3bea61386b New translations strings.xml (Indonesian)
[ci skip]
2026-06-23 22:06:02 +05:30
Pranshul a923b86f72 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-06-23 22:06:00 +05:30
Pranshul 30ed3b5e35 New translations strings.xml (Vietnamese)
[ci skip]
2026-06-23 22:05:59 +05:30
Pranshul 11646d9f4e New translations strings.xml (Chinese Traditional)
[ci skip]
2026-06-23 22:05:57 +05:30
Pranshul d99d43efba New translations strings.xml (Chinese Simplified)
[ci skip]
2026-06-23 22:05:56 +05:30
Pranshul 38a452e82b New translations strings.xml (Ukrainian)
[ci skip]
2026-06-23 22:05:54 +05:30
Pranshul f6b5b72ca5 New translations strings.xml (Turkish)
[ci skip]
2026-06-23 22:05:53 +05:30
Pranshul e5fd2f41be New translations strings.xml (Swedish)
[ci skip]
2026-06-23 22:05:51 +05:30
Pranshul 87513050b8 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-06-23 22:05:50 +05:30
Pranshul d3d972aab6 New translations strings.xml (Slovenian)
[ci skip]
2026-06-23 22:05:48 +05:30
Pranshul 669c724882 New translations strings.xml (Russian)
[ci skip]
2026-06-23 22:05:47 +05:30
Pranshul 166233e5af New translations strings.xml (Portuguese)
[ci skip]
2026-06-23 22:05:45 +05:30
Pranshul b3be33c62d New translations strings.xml (Polish)
[ci skip]
2026-06-23 22:05:44 +05:30
Pranshul 7015226c68 New translations strings.xml (Dutch)
[ci skip]
2026-06-23 22:05:43 +05:30
Pranshul c0aa385ae5 New translations strings.xml (Korean)
[ci skip]
2026-06-23 22:05:41 +05:30
Pranshul 7b568638a2 New translations strings.xml (Japanese)
[ci skip]
2026-06-23 22:05:39 +05:30
Pranshul 1b77ee373a New translations strings.xml (Italian)
[ci skip]
2026-06-23 22:05:38 +05:30
Pranshul ca1f0ab450 New translations strings.xml (Hungarian)
[ci skip]
2026-06-23 22:05:36 +05:30
Pranshul 79d0bb9f71 New translations strings.xml (Finnish)
[ci skip]
2026-06-23 22:05:35 +05:30
Pranshul f445ebbaeb New translations strings.xml (Greek)
[ci skip]
2026-06-23 22:05:33 +05:30
Pranshul ba4dcf17f6 New translations strings.xml (German)
[ci skip]
2026-06-23 22:05:32 +05:30
Pranshul d3ee7eb17e New translations strings.xml (Czech)
[ci skip]
2026-06-23 22:05:30 +05:30
Pranshul caf56fbdac New translations strings.xml (Catalan)
[ci skip]
2026-06-23 22:05:29 +05:30
Pranshul 4794678485 New translations strings.xml (Bulgarian)
[ci skip]
2026-06-23 22:05:27 +05:30
Pranshul 95ceb73719 New translations strings.xml (Spanish)
[ci skip]
2026-06-23 22:05:26 +05:30
Pranshul 2e58403ca7 New translations strings.xml (French)
[ci skip]
2026-06-23 22:05:24 +05:30
Pranshul adb7452bf4 New translations strings.xml (Romanian)
[ci skip]
2026-06-23 22:05:23 +05:30
PranshulGG 230cc7bb94 hide precipitation probability in DailyCard when value is null 2026-06-23 21:48:46 +05:30
PranshulGG 5d08ac6bb3 calculate average wind speed instead of maximum in nws 2026-06-23 21:48:35 +05:30
PranshulGG 71c155b7ac refactor time formatting logic in SunBlock.kt 2026-06-23 21:48:18 +05:30
PranshulGG 5974427d48 add China weather source 2026-06-23 21:48:07 +05:30
PranshulGG c364a7df72 Added an option to use **Google Sans Flex** font 2026-06-23 21:46:48 +05:30
Pranshul 934179fd3e New translations strings.xml (Hebrew)
[ci skip]
2026-06-23 00:58:36 +05:30
Pranshul b7a0962447 New translations strings.xml (Polish)
[ci skip]
2026-06-23 00:58:34 +05:30
Pranshul e9b3efc019 New translations strings.xml (Spanish)
[ci skip]
2026-06-23 00:58:33 +05:30
Pranshul 543409c3c6 New translations strings.xml (Spanish)
[ci skip]
2026-06-22 18:55:13 +05:30
PranshulGG 07b3d904c3 refactor ClockDailyWidget to display 5 items with weighted distribution and adjust padding 2026-06-22 16:01:54 +05:30
PranshulGG 74d435ed79 refactor ClockDailyWidget to display 5 items with weighted distribution and adjust padding 2026-06-22 15:16:00 +05:30
Pranshul 2359c88aff New translations strings.xml (Japanese)
[ci skip]
2026-06-22 04:49:39 +05:30
Pranshul c41e965145 New translations strings.xml (Lithuanian)
[ci skip]
2026-06-21 22:42:33 +05:30
Pranshul f37d8429e2 New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-06-21 22:42:31 +05:30
Pranshul 080972a26a New translations strings.xml (Serbian (Latin))
[ci skip]
2026-06-21 22:42:30 +05:30
Pranshul 934409e344 New translations strings.xml (Filipino)
[ci skip]
2026-06-21 22:42:29 +05:30
Pranshul 796fcee1eb New translations strings.xml (Azerbaijani)
[ci skip]
2026-06-21 22:42:28 +05:30
Pranshul 846f6761e7 New translations strings.xml (Thai)
[ci skip]
2026-06-21 22:42:26 +05:30
Pranshul ffffbe4c1f New translations strings.xml (Persian)
[ci skip]
2026-06-21 22:42:25 +05:30
Pranshul 88938b3e18 New translations strings.xml (Indonesian)
[ci skip]
2026-06-21 22:42:24 +05:30
Pranshul 9cd437bf1f New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-06-21 22:42:23 +05:30
Pranshul 41567202ad New translations strings.xml (Vietnamese)
[ci skip]
2026-06-21 22:42:21 +05:30
Pranshul aa6fa26ad0 New translations strings.xml (Chinese Traditional)
[ci skip]
2026-06-21 22:42:20 +05:30
Pranshul 61e12c71f2 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-06-21 22:42:19 +05:30
Pranshul b12d5b9fb2 New translations strings.xml (Ukrainian)
[ci skip]
2026-06-21 22:42:18 +05:30
Pranshul c6347bfdee New translations strings.xml (Turkish)
[ci skip]
2026-06-21 22:42:16 +05:30
Pranshul a436416faa New translations strings.xml (Swedish)
[ci skip]
2026-06-21 22:42:15 +05:30
Pranshul 115bd879d2 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-06-21 22:42:14 +05:30
Pranshul 2dd3e7c5d9 New translations strings.xml (Slovenian)
[ci skip]
2026-06-21 22:42:12 +05:30
Pranshul 6deb7d9986 New translations strings.xml (Russian)
[ci skip]
2026-06-21 22:42:11 +05:30
Pranshul 74f1c0d3fa New translations strings.xml (Portuguese)
[ci skip]
2026-06-21 22:42:10 +05:30
Pranshul f968500ebc New translations strings.xml (Polish)
[ci skip]
2026-06-21 22:42:08 +05:30
Pranshul c12d059ce9 New translations strings.xml (Dutch)
[ci skip]
2026-06-21 22:42:07 +05:30
Pranshul 4e5243aab8 New translations strings.xml (Korean)
[ci skip]
2026-06-21 22:42:06 +05:30
Pranshul 90ba2fe0a3 New translations strings.xml (Japanese)
[ci skip]
2026-06-21 22:42:05 +05:30
Pranshul 51717a1eb4 New translations strings.xml (Italian)
[ci skip]
2026-06-21 22:42:03 +05:30
Pranshul 1544843fcf New translations strings.xml (Hungarian)
[ci skip]
2026-06-21 22:42:02 +05:30
Pranshul f76c66a144 New translations strings.xml (Finnish)
[ci skip]
2026-06-21 22:42:01 +05:30
Pranshul 7a5fc52d68 New translations strings.xml (Greek)
[ci skip]
2026-06-21 22:42:00 +05:30
Pranshul 6ad7e9bb7f New translations strings.xml (German)
[ci skip]
2026-06-21 22:41:58 +05:30
Pranshul c5dd8296ed New translations strings.xml (Czech)
[ci skip]
2026-06-21 22:41:57 +05:30
Pranshul 27fdb9a885 New translations strings.xml (Catalan)
[ci skip]
2026-06-21 22:41:56 +05:30
Pranshul 294c3b89fb New translations strings.xml (Bulgarian)
[ci skip]
2026-06-21 22:41:54 +05:30
Pranshul d7c4645bc9 New translations strings.xml (Spanish)
[ci skip]
2026-06-21 22:41:53 +05:30
Pranshul ec3aae5600 New translations strings.xml (French)
[ci skip]
2026-06-21 22:41:52 +05:30
Pranshul 84d3d92f53 New translations strings.xml (Romanian)
[ci skip]
2026-06-21 22:41:51 +05:30
PranshulGG 8cc9cf179b update glance widget preview image 2026-06-21 18:27:46 +05:30
PranshulGG 55adcb3acb add color_transparent string resource 2026-06-21 18:27:40 +05:30
PranshulGG 736a599bae add WidgetColors for theme management and increase daily forecast count to 6 2026-06-21 18:27:33 +05:30
PranshulGG 92437ca5bd trigger weather update on widget update and update horizontal widget UI layout 2026-06-21 18:27:22 +05:30
PranshulGG 230911f770 add text color support to WidgetDate and WidgetClock components 2026-06-21 18:27:10 +05:30
PranshulGG b67d7e8fdc add ClockDailyWidget with forecast support and implement theme-based configuration for widgets 2026-06-21 18:26:59 +05:30
PranshulGG d6e645c0e0 update app banner 2026-06-21 17:38:55 +05:30
Pranshul 1de646fcc5 New translations strings.xml (Korean)
[ci skip]
2026-06-21 16:04:06 +05:30
PranshulGG 038ad8883c update weather summary string resource in SummaryWidget and SummaryCard 2026-06-21 12:32:11 +05:30
PranshulGG f499dadb69 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-06-21 12:30:23 +05:30
PranshulGG 5e561cd301 add database schema for version 44 2026-06-21 12:30:04 +05:30
PranshulGG 135d047af5 refactor DailyDaysHeader to use LazyRow and implement auto-scroll to selected index 2026-06-21 12:28:55 +05:30
PranshulGG 0abc1f383c use rememberSaveable for selectedIndex in DailyScreen.kt 2026-06-21 11:45:34 +05:30
PranshulGG 86a8700f17 daily forecast now supports Humidity, Pressure, Visibility data 2026-06-21 11:44:47 +05:30
Pranshul fcb5abbcf1 New translations strings.xml (Korean)
[ci skip]
2026-06-21 10:00:47 +05:30
PranshulGG a3765cbd73 handle NaN in wind hourly bar height calculation 2026-06-20 15:17:43 +05:30
PranshulGG f543509d71 trigger weather worker on widget update in SummaryWidgetReceiver and WidgetPillReceiver 2026-06-20 15:17:26 +05:30
PranshulGG 37c9bd6992 add format_size_24px vector and update weather_preview image 2026-06-20 15:17:16 +05:30
PranshulGG 72083112e5 rename Glance widget label, update weather periodic work policy, and add shadow color resource 2026-06-20 15:17:01 +05:30
PranshulGG a351afb468 add WidgetConfig and WidgetConfigActivity for widget configuration 2026-06-20 15:16:42 +05:30
PranshulGG b4decf5381 update WeatherWorker logic, improve widget state handling, and increase hourly forecast limit 2026-06-20 15:16:32 +05:30
PranshulGG 641bbe726c change clock size selection to predefined options, fix widget layout spacing, and trigger worker on update 2026-06-20 15:16:18 +05:30
PranshulGG a7d889f8fc trigger weather worker on widget update and add config to WeatherWidgetStateJson 2026-06-20 15:15:55 +05:30
PranshulGG 9e2dc088d0 trigger weather worker on widget update and add config to WeatherWidgetStateJson 2026-06-20 15:15:16 +05:30
PranshulGG 8ac28e036d implement responsive sizing for horizontal weather widget and add mini/compact variants 2026-06-20 15:14:50 +05:30
PranshulGG a0dbcb9a21 add size-specific clock layout files and update ViewClock to select layouts based on text size 2026-06-20 15:13:23 +05:30
PranshulGG 4478f7c98a remove small weather widget and WidgetConfig 2026-06-20 15:12:41 +05:30
PranshulGG fdfaa74e17 refactor WeatherWidgetStateDefinition to use DataStoreFactory and dynamic fileKey 2026-06-20 15:12:23 +05:30
Pranshul d74480e98b New translations strings.xml (Lithuanian)
[ci skip]
2026-06-19 14:54:17 +05:30
Pranshul 0396ffadc5 New translations strings.xml (Lithuanian)
[ci skip]
2026-06-19 02:48:29 +05:30
Pranshul d019c182eb New translations strings.xml (Korean)
[ci skip]
2026-06-19 02:48:27 +05:30
PranshulGG 664419b770 implement Glance weather widget and configuration UI for clock and date settings 2026-06-18 22:26:54 +05:30
Pranshul 9d65d9c8b4 Merge pull request #898 from PranshulGG/l10n_main
New Crowdin updates
2026-06-18 22:26:48 +05:30
Pranshul f22948eafb New translations strings.xml (Korean)
[ci skip]
2026-06-18 20:50:21 +05:30
Pranshul 4341c4047c New translations strings.xml (Lithuanian)
[ci skip]
2026-06-18 02:49:00 +05:30
Pranshul db3509b176 New translations strings.xml (Polish)
[ci skip]
2026-06-18 02:48:58 +05:30
Pranshul 44b18200f7 New translations strings.xml (Polish)
[ci skip]
2026-06-17 20:39:23 +05:30
Pranshul 0f26e1d4f2 New translations strings.xml (Lithuanian)
[ci skip]
2026-06-17 14:41:03 +05:30
Pranshul f9b6b04b3f New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-06-17 08:19:08 +05:30
Pranshul 1e66cdc33d New translations strings.xml (Lithuanian)
[ci skip]
2026-06-17 02:16:33 +05:30
Pranshul 3a73fbaad2 New translations strings.xml (Lithuanian)
[ci skip]
2026-06-16 19:44:46 +05:30
Pranshul 79c7c8b662 Reorganize translation section in README
Signed-off-by: Pranshul <pranshul.devmain@gmail.com>
2026-06-16 19:21:53 +05:30
PranshulGG 60d53cf343 refactor FmiXmlMapper to separate current icon retrieval from hourly fallback logic 2026-06-15 20:52:44 +05:30
PranshulGG 94d4dce5ca rename numbers.kt to NumberUtils.kt, add toSafeDouble extension, and update ECCC and FMI mappers 2026-06-15 20:32:46 +05:30
PranshulGG b8f5bd0e0f add GEO_NAMES_USERNAME and MF_KEY properties to release workflow 2026-06-15 19:23:44 +05:30
Pranshul 22ed28096d New translations strings.xml (Italian)
[ci skip]
2026-06-15 19:22:51 +05:30
Pranshul 7752d0b81c New translations strings.xml (Greek)
[ci skip]
2026-06-15 19:22:49 +05:30
Pranshul 86b24d974d New translations strings.xml (German)
[ci skip]
2026-06-15 19:22:48 +05:30
PranshulGG f06de99291 fix Indonesian locale value and remove commented navigation code in AppNavHost.kt 2026-06-15 19:04:12 +05:30
PranshulGG 010a1068a5 update horizontal padding to 16dp in Visibility, UvIndex, Pressure, and Wind blocks 2026-06-15 19:00:00 +05:30
PranshulGG 3748e095c5 fix string format placeholder in German translation and implement new version snackbar dismissal logic 2026-06-15 18:56:34 +05:30
PranshulGG d1ea9720e3 bump versionCode to 52 and versionName to 3.4.0 2026-06-15 18:47:33 +05:30
PranshulGG 518c876e82 compute apparent temperature fallback for feelsLike in EcccJsonMapper 2026-06-15 18:47:22 +05:30
PranshulGG 8b3c7d2817 allow custom snackbar duration in SnackbarManager 2026-06-15 18:44:15 +05:30
PranshulGG 32cf4618d4 implement version update check with local caching and notify user on MainScreen 2026-06-15 18:43:06 +05:30
PranshulGG 6fc1819038 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-06-15 16:44:26 +05:30
Pranshul 55fb9ac560 Merge pull request #895 from PranshulGG/l10n_main
New Crowdin updates
2026-06-15 16:44:16 +05:30
PranshulGG a4c993cc00 remove debug log from FmiXmlMapper.kt 2026-06-15 16:43:59 +05:30
PranshulGG 5bfd5945a3 add FMI and ECCC sources, and format description list as HTML 2026-06-15 16:43:04 +05:30
PranshulGG 0da69bd223 add getDayStartUtcAlignedToLocal to DateTimeFormatters and jaxb converter dependency 2026-06-15 16:39:08 +05:30
PranshulGG 9344d0692c pass location timezone to OpenMeteo API call 2026-06-15 16:38:58 +05:30
PranshulGG eb20b9358c add converter-jaxb dependency to libs.versions.toml 2026-06-15 16:38:51 +05:30
PranshulGG 96526f46d8 update imports 2026-06-15 16:38:37 +05:30
PranshulGG fe6fa0e9e0 calculate daily max precipitation probability from hourly data in ECCC mapper and remove try-catch in EcccRepository 2026-06-15 16:38:04 +05:30
PranshulGG 1ad6034e66 update HourlyCard to use weather current time 2026-06-15 16:37:49 +05:30
PranshulGG 7e789e9e01 remove default timezone in OpenMeteoApi and fix BASE_URL in MeteoFranceApi 2026-06-15 16:37:18 +05:30
PranshulGG 81583ad05a implement FMI as a weather source and update precipitation navigation routes 2026-06-15 16:37:06 +05:30
PranshulGG d6475b22ac Refactor weather screens to use dedicated hourly card components 2026-06-15 16:35:08 +05:30
PranshulGG a8ff948b81 add timezone support to device location updates fixed #897 2026-06-15 13:06:27 +05:30
Pranshul 535fe3ec85 New translations strings.xml (Russian)
[ci skip]
2026-06-15 03:42:06 +05:30
Pranshul 64289be950 New translations strings.xml (Spanish)
[ci skip]
2026-06-14 21:05:43 +05:30
PranshulGG a14679feee default OpenMeteo timezone to UTC, fix NWS precipitation probability mapping, and simplify chart labels across screens 2026-06-14 18:44:28 +05:30
PranshulGG d79be76936 use UTC for time strings and remove zoneId parameter in chart screens 2026-06-14 17:31:21 +05:30
PranshulGG 1ec3d6da4f use UTC for time strings and remove zoneId parameter in chart screens 2026-06-14 17:07:51 +05:30
Pranshul b67acc3885 New translations strings.xml (Italian)
[ci skip]
2026-06-14 13:47:36 +05:30
Pranshul 2f17041843 New translations strings.xml (German)
[ci skip]
2026-06-14 13:47:35 +05:30
Pranshul 11fc7f138a Merge branch 'main' into l10n_main
Signed-off-by: Pranshul <pranshul.devmain@gmail.com>
2026-06-14 07:55:32 +05:30
Pranshul 90d2826e21 New translations strings.xml (Russian)
[ci skip]
2026-06-14 07:52:33 +05:30
Pranshul b9e40ba294 New translations strings.xml (Polish)
[ci skip]
2026-06-14 07:52:31 +05:30
Pranshul da713a28cb New translations strings.xml (Italian)
[ci skip]
2026-06-14 07:52:28 +05:30
Pranshul b868ff00fc New translations strings.xml (German)
[ci skip]
2026-06-14 07:52:25 +05:30
Pranshul 2450673826 New translations strings.xml (Catalan)
[ci skip]
2026-06-14 07:52:23 +05:30
Pranshul 71ec19b395 New translations strings.xml (Spanish)
[ci skip]
2026-06-14 07:52:22 +05:30
Pranshul 82b215a8e9 New translations strings.xml (French)
[ci skip]
2026-06-14 07:52:20 +05:30
PranshulGG 434ab7800d fix string format placeholders in Polish, Italian, and German translations and add Log import in Headlines.kt #889 2026-06-13 22:07:41 +05:30
PranshulGG 19c7676a4e FMI as a source, attempt #630 2026-06-12 21:58:02 +05:30
PranshulGG 739361255d add feature request issue template 2026-06-12 17:37:15 +05:30
PranshulGG 0462d8a79e fix indentation of validations in new_source.yaml 2026-06-12 17:07:45 +05:30
PranshulGG 31482a7df3 move required attribute under validations in new_source.yaml 2026-06-12 17:06:32 +05:30
PranshulGG 0e89f1c4b0 add new source issue template 2026-06-12 17:05:41 +05:30
PranshulGG da689a6ca3 add bug report issue template 2026-06-12 17:00:22 +05:30
PranshulGG 2017697bfb add bug report issue template 2026-06-12 16:55:58 +05:30
PranshulGG 91abf80631 Merge branch 'main' of https://github.com/PranshulGG/WeatherMaster 2026-06-12 16:50:03 +05:30
Pranshul 050e4a73d9 Merge pull request #886 from PranshulGG/l10n_main
New Crowdin updates
2026-06-12 16:49:25 +05:30
PranshulGG 00fa6e25fc add Room database schema version 43 2026-06-12 16:48:57 +05:30
PranshulGG 1c534f1d10 update wind speed validation to support daily forecasts in WeatherBlocks.kt 2026-06-12 16:30:27 +05:30
PranshulGG a6c512ccbf rename MeteoFranceMapper to MeteFranceJsonMapper, remove @Preview from NoHourlyDataAvailable, and remove logging interceptor from SmhiApi 2026-06-12 16:30:11 +05:30
PranshulGG 4aa316ead2 handle empty hourly weather data in findMatchingHourly, HourlyCard, and ComputeDaySummary 2026-06-12 16:29:57 +05:30
PranshulGG 0fdb62ee64 add ECCC weather source and refactor weather source settings screen closes #875 2026-06-12 16:29:41 +05:30
PranshulGG cc026da135 change notification importance to DEFAULT 2026-06-12 12:08:03 +05:30
PranshulGG 103390e9e1 remove HttpLoggingInterceptor from network APIs, fix thunderstorm animation parameters in WeatherAnimations.kt 2026-06-12 10:47:11 +05:30
PranshulGG 5b34db7ce8 fixed unusually high temperatures when using NWS 2026-06-11 09:44:54 +05:30
PranshulGG 46dd248030 increase minSdk to 26, disable library desugaring, and use safeZoneId utility to handle timezone exceptions closes #889 2026-06-10 21:57:18 +05:30
PranshulGG 92eb2b0b36 remove HttpLoggingInterceptor from API classes and remove debug log in DwdJsonMapper closes #893 2026-06-10 21:41:47 +05:30
Pranshul 66f77f65ae New translations strings.xml (Chinese Simplified)
[ci skip]
2026-06-10 16:37:10 +05:30
Pranshul 2c58544eff New translations strings.xml (Japanese)
[ci skip]
2026-06-10 16:37:08 +05:30
PranshulGG 360b7372d8 update weather_preview and add widget_horizontal_preview and widget_small_preview assets 2026-06-10 16:09:25 +05:30
PranshulGG cd91bd3705 add WeatherSmallWidget and WeatherHorizontalWidget to AndroidManifest and WeatherWidgetUpdater 2026-06-10 16:09:07 +05:30
PranshulGG b2fa8ede42 add WeatherSmallWidget with receiver and UI layout using Jetpack Glance 2026-06-10 16:08:48 +05:30
PranshulGG f5459ff752 add WeatherHorizontalWidget and provider info for horizontal 2026-06-10 16:08:38 +05:30
PranshulGG 577baa24b4 recreate activity on theme change and implement dynamic navigation bar styles using enableEdgeToEdge in MainActivity 2026-06-10 16:07:35 +05:30
PranshulGG e7df1c9b4a update WeatherWidgetNormal layout, increase padding, and relocate temperature display 2026-06-10 14:30:54 +05:30
PranshulGG 148e1347ba update AGP, Kotlin, and other dependencies, add hilt-metadata-jvm, and use ZoneId in IntroScreen #889 2026-06-10 12:18:54 +05:30
PranshulGG 63aa564086 update language selection logic to support system locale and refactor number formatting to use localized locales 2026-06-10 10:25:11 +05:30
Pranshul 399b5123ec New translations strings.xml (Arabic, Saudi Arabia)
[ci skip]
2026-06-09 19:14:15 +05:30
Pranshul 92a3f1cc50 New translations strings.xml (Serbian (Latin))
[ci skip]
2026-06-09 19:14:14 +05:30
Pranshul 2338079041 New translations strings.xml (Filipino)
[ci skip]
2026-06-09 19:14:12 +05:30
Pranshul 21b180728c New translations strings.xml (Azerbaijani)
[ci skip]
2026-06-09 19:14:11 +05:30
Pranshul 8dab6126d4 New translations strings.xml (Thai)
[ci skip]
2026-06-09 19:14:09 +05:30
Pranshul cc1e06c2a3 New translations strings.xml (Persian)
[ci skip]
2026-06-09 19:14:08 +05:30
Pranshul c0f2135021 New translations strings.xml (Indonesian)
[ci skip]
2026-06-09 19:14:06 +05:30
Pranshul b43912b7c5 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-06-09 19:14:05 +05:30
Pranshul b42b582e6e New translations strings.xml (Vietnamese)
[ci skip]
2026-06-09 19:14:04 +05:30
Pranshul 62dfd30f1b New translations strings.xml (Chinese Traditional)
[ci skip]
2026-06-09 19:14:02 +05:30
Pranshul 332d7249ac New translations strings.xml (Chinese Simplified)
[ci skip]
2026-06-09 19:14:01 +05:30
Pranshul 1a15aaa965 New translations strings.xml (Ukrainian)
[ci skip]
2026-06-09 19:13:59 +05:30
Pranshul 0de7a150bd New translations strings.xml (Turkish)
[ci skip]
2026-06-09 19:13:58 +05:30
Pranshul d002f4cbab New translations strings.xml (Swedish)
[ci skip]
2026-06-09 19:13:56 +05:30
Pranshul 63a13c57f4 New translations strings.xml (Serbian (Cyrillic))
[ci skip]
2026-06-09 19:13:55 +05:30
Pranshul 6ea0bf64b9 New translations strings.xml (Slovenian)
[ci skip]
2026-06-09 19:13:53 +05:30
Pranshul 8351dbf827 New translations strings.xml (Russian)
[ci skip]
2026-06-09 19:13:52 +05:30
Pranshul 23932371fb New translations strings.xml (Portuguese)
[ci skip]
2026-06-09 19:13:50 +05:30
Pranshul 16864ed688 New translations strings.xml (Polish)
[ci skip]
2026-06-09 19:13:48 +05:30
Pranshul 39571861cd New translations strings.xml (Dutch)
[ci skip]
2026-06-09 19:13:47 +05:30
Pranshul 693a596a7e New translations strings.xml (Korean)
[ci skip]
2026-06-09 19:13:45 +05:30
Pranshul eca77b3659 New translations strings.xml (Japanese)
[ci skip]
2026-06-09 19:13:43 +05:30
Pranshul bb217ee8dc New translations strings.xml (Italian)
[ci skip]
2026-06-09 19:13:42 +05:30
Pranshul bd2c12d6bb New translations strings.xml (Hungarian)
[ci skip]
2026-06-09 19:13:40 +05:30
Pranshul 60b37c58e6 New translations strings.xml (Finnish)
[ci skip]
2026-06-09 19:13:38 +05:30
Pranshul f6f4e21c0e New translations strings.xml (Greek)
[ci skip]
2026-06-09 19:13:37 +05:30
Pranshul b0c046ad7b New translations strings.xml (German)
[ci skip]
2026-06-09 19:13:35 +05:30
Pranshul 76fc4544af New translations strings.xml (Czech)
[ci skip]
2026-06-09 19:13:34 +05:30
Pranshul 72415c8520 New translations strings.xml (Catalan)
[ci skip]
2026-06-09 19:13:32 +05:30
Pranshul ef2676bde1 New translations strings.xml (Bulgarian)
[ci skip]
2026-06-09 19:13:31 +05:30
Pranshul 7524a9308e New translations strings.xml (Spanish)
[ci skip]
2026-06-09 19:13:30 +05:30
Pranshul 880b80d779 New translations strings.xml (French)
[ci skip]
2026-06-09 19:13:28 +05:30
Pranshul 52045c9dff New translations strings.xml (Romanian)
[ci skip]
2026-06-09 19:13:26 +05:30
PranshulGG 96ac827746 add mail_24px vector drawable 2026-06-09 19:11:37 +05:30
PranshulGG 47aea1ad3f add network connectivity constraint to WeatherWorker in WeatherUpdateScheduler 2026-06-09 19:11:27 +05:30
PranshulGG a41396a335 add unit conversion for dew point in HumidityScreen, include info cards in PrecipitationScreen 2026-06-09 19:11:18 +05:30
Pranshul 383cb07273 New translations strings.xml (Portuguese, Brazilian)
[ci skip]
2026-06-08 22:34:16 +05:30
Pranshul 662a22ce33 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-06-08 22:34:15 +05:30
Pranshul b008ea54bd New translations strings.xml (Czech)
[ci skip]
2026-06-08 16:07:33 +05:30
Pranshul 79d3151020 New translations strings.xml (French)
[ci skip]
2026-06-08 06:25:18 +05:30
Pranshul 60aa1c35c3 New translations strings.xml (Czech)
[ci skip]
2026-06-08 00:23:37 +05:30
Pranshul 5264874bd9 New translations strings.xml (German)
[ci skip]
2026-06-07 18:28:27 +05:30
Pranshul 0dd03cf6ec New translations strings.xml (Spanish)
[ci skip]
2026-06-07 18:28:25 +05:30
PranshulGG 4162f0353b add placeholders for GEO_NAMES_USERNAME and MF_KEY in gradle.properties 2026-06-07 15:37:39 +05:30
PranshulGG 319948e25c add email action tile to AboutScreen and remove TODO comment 2026-06-07 13:49:52 +05:30
PranshulGG be4fce9c77 Added option to use System Language fixed #872 2026-06-07 13:47:06 +05:30
Pranshul b151de735a New translations strings.xml (German)
[ci skip]
2026-06-07 12:19:19 +05:30
Pranshul 67e3de0b39 New translations strings.xml (Chinese Simplified)
[ci skip]
2026-06-06 23:05:20 +05:30
Pranshul 2cab9da603 New translations strings.xml (Czech)
[ci skip]
2026-06-06 23:05:19 +05:30
Pranshul 7e46a5df7b New translations strings.xml (French)
[ci skip]
2026-06-06 23:05:18 +05:30
Pranshul 1b0cef1b36 New translations strings.xml (Portuguese)
[ci skip]
2026-06-06 16:55:05 +05:30
Pranshul d50206280c New translations strings.xml (French)
[ci skip]
2026-06-06 16:55:04 +05:30
PranshulGG 27937ad90f add countryCode support to location models closes #887 2026-06-06 13:25:40 +05:30
PranshulGG b02d11369d add countryCode support to location models closes #887 2026-06-06 13:25:34 +05:30
Pranshul e18cd087ea New translations strings.xml (Polish)
[ci skip]
2026-06-06 10:52:56 +05:30
Pranshul de25bb0028 New translations strings.xml (Japanese)
[ci skip]
2026-06-06 10:52:55 +05:30
679 changed files with 65392 additions and 9085 deletions

No files matched your search

+4
View File
@@ -0,0 +1,4 @@
# These are supported funding model platforms
github: [PranshulGG]
ko_fi: pranshulgg
liberapay: PranshulGG
+51
View File
@@ -0,0 +1,51 @@
name: Bug Report
description: Report a bug
labels: [ "bug" ]
body:
- type: markdown
attributes:
value: |
Please fill out the sections below to help everyone identify and fix the bug
- type: textarea
id: description
attributes:
label: Describe your issue
placeholder: When I click here this happens
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
placeholder: |
1. Go to page X
2. Click here
3. Click there
validations:
required: true
- type: textarea
id: expected
attributes:
label: What was the expected result?
placeholder: I expected this to happen
- type: input
id: source_used
attributes:
label: Which weather source are you using?
placeholder: Example "Open Meteo"
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Put here any screenshots or videos (optional)
- type: checkboxes
id: acknowledgementsCheck
attributes:
label: Acknowledgements
description: Your issue will be closed if you don’t read this carefully.
options:
- label: I have reviewed the existing issues to confirm that this is a unique report and not related to any currently open or closed tickets.
required: true
- label: I understand that this app is provided as-is, without any guarantees, and I might not receive a response to my request. Sometimes you might not get the response you want.
required: true
@@ -0,0 +1,51 @@
name: Feature Request
description: Suggest an idea to improve this project
body:
- type: markdown
attributes:
value: |
Please provide detailed information to help us understand your idea and its potential impact.
- type: textarea
id: description
attributes:
label: Problem Statement
placeholder: Describe the problem or limitation you're facing that the new feature would solve.
description: Clearly explain the challenge or issue you're encountering to help us understand the context.
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
placeholder: Explain how you think the feature should work and address the problem.
description: Describe the solution in detail, including any specific behaviors or functionality it should have.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
placeholder: Describe any alternative solutions or features you've considered.
description: If there are other ways to solve the issue, please share them here.
- type: textarea
id: additional
attributes:
label: Additional Context
placeholder: Provide any extra details, links, or examples that might help clarify your request.
description: This field is optional but highly encouraged if you have additional information.
- type: checkboxes
id: acknowledgementsCheck
attributes:
label: Acknowledgements
description: Please confirm the following before submitting your feature request
options:
- label: I have searched the existing issues and discussions to ensure this feature has not already been requested.
required: true
- label: I understand that submitting a request does not guarantee it will be implemented.
required: true
- label: I have provided all necessary information to clearly explain my request.
required: true
- type: markdown
attributes:
value: |
Thank you for suggesting an improvement! Your feedback is valuable, and we will review it as soon as possible.
+30
View File
@@ -0,0 +1,30 @@
name: New source
description: Suggest an new source
body:
- type: markdown
attributes:
value: |
Please fill out the sections below
- type: textarea
id: api_link
attributes:
label: Link to publicly available API or Docs
placeholder: Link here
validations:
required: true
- type: textarea
id: details
attributes:
label: Additional details/context about this source
validations:
required: true
- type: checkboxes
id: acknowledgementsCheck
attributes:
label: Acknowledgements
description: Your issue will be closed if you don’t read this carefully.
options:
- label: I have reviewed the existing issues to confirm that this is a unique report and not related to any currently open or closed tickets.
required: true
- label: I understand that this app is provided as-is, without any guarantees, and I might not receive a response to my request. Sometimes you might not get the response you want.
required: true
+9 -1
View File
@@ -16,6 +16,8 @@ jobs:
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
GEO_NAMES_USERNAME: ${{ secrets.GEO_NAMES_USERNAME }}
MF_KEY: ${{ secrets.MF_KEY }}
ACCU_KEY: ${{ secrets.ACCU_KEY }}
WEATHERAPI_KEY: ${{ secrets.WEATHERAPI_KEY }}
steps:
- name: Checkout
@@ -25,13 +27,15 @@ jobs:
run: chmod +x gradlew
- name: Set up JDK 21
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: "21.0.7"
- name: Setup Android SDK
uses: android-actions/setup-android@v3
with:
packages: 'platform-tools'
- name: Decode keystore
run: |
@@ -48,6 +52,10 @@ jobs:
./gradlew \
--no-daemon \
--no-build-cache \
-PGEO_NAMES_USERNAME="${{ secrets.GEO_NAMES_USERNAME }}" \
-PMF_KEY="${{ secrets.MF_KEY }}" \
-PACCU_KEY="${{ secrets.ACCU_KEY }}" \
-PWEATHERAPI_KEY="${{ secrets.WEATHERAPI_KEY }}" \
clean assembleRelease
- name: Upload APK
+66
View File
@@ -0,0 +1,66 @@
# Contributing to WeatherMaster
Thanks for contributing to WeatherMaster :P Before opening a PR, please read
through the guidelines below. They are intended to keep the codebase
consistent and make contributions easier to review and maintain
## Before Contributing
Before starting work on a contribution, please open an issue first and
describe what you would like to change.
For small changes like typo fixe or other
obvious minor fixes, opening an issue is optional
## General stuff
- Keep changes focused and avoid unrelated refactors.
- Follow the existing architecture and patterns used in the project.
- Prefer reusing existing abstractions over introducing new ones.
- Don't introduce a new pattern or framework for a single feature.
- Keep platform-independent logic independent of UI code where
possible
- Avoid unnecessary changes to existing behavior.
## Adding a New Weather Source
The goal is that adding a new source should primarily require changes to the
source itself, rather than adding special cases throughout the codebase
When implementing a new source:
- Use the existing source abstractions and interfaces.
- Do not add source-specific UI.
- Do not add source-specific logic to existing UI components.
- If the source requires information that the existing architecture cannot
represent, discuss the change before implementing a
source-specific workaround
## AI-Assisted Contributions
AI tools are allowed, but contributors are expected to understand and take
ownership of the code they submit
Please disclose AI usage in your PR description, including what the AI was
used for
PRs that appear to be largely or entirely AI-generated without meaningful
review, understanding, or contribution from the author will be closed
## Attributions
Add your attribution above the feature you implemented. Attribution should only be added for feature
implementations
For example:
```kt
/**
* Initial YOUR_FEATURE integration implemented by https://github.com/YOUR_GITHUB
*/
```
_Thanks :P_
+57
View File
@@ -0,0 +1,57 @@
# Privacy Policy
WeatherMaster is an open-source application.
We respect your privacy. The application itself does **not**:
- Collect, store, or share personal information.
- Track your IP address, usage data, or device identifiers.
- Send personal data to us directly.
---
## Third-Party Services & APIs
WeatherMaster relies on external weather and geolocation services to provide forecasts and
location-based functionality.
These third-party services may process certain technical information, including:
- IP address
- Approximate or precise location data
- Device or network-related information required for API requests
This data processing is handled by the respective service providers under their own privacy
policies. WeatherMaster itself does not control or store this data.
---
## Location Permission
The app may request access to your device's location to display local weather information.
- Granting location permission is optional.
- Your precise location is used locally within the app to fetch weather data from external APIs.
- WeatherMaster does not store your precise location.
---
## Children
This application is not directed toward children under the age of 13 and does not knowingly collect
personal information.
---
## Changes
This Privacy Policy may be updated from time to time. Continued use of the app after changes become
effective constitutes acceptance of the revised policy.
---
## Contact
If you have any questions about privacy, please contact:
**Email:** <pranshul.devmain@gmail.com>
+71 -10
View File
@@ -31,8 +31,10 @@
</div>
<div align="center">
<a href="https://github.com/PranshulGG/WeatherMaster/releases"><img alt="GitHub" src="https://user-images.githubusercontent.com/69304392/148696068-0cfea65d-b18f-4685-82b5-329a330b1c0d.png" height="80"/></a>
<a href="https://apt.izzysoft.de/fdroid/index/apk/com.pranshulgg.weather_master_app"><img alt="GitHub" src="preview/download_Btn.png" height="80"/></a></div>
<a href="https://github.com/PranshulGG/WeatherMaster/releases"><img alt="GitHub" src="preview/get_on_github_btn.png" height="80"/></a>
<a href="https://apt.izzysoft.de/fdroid/index/apk/com.pranshulgg.weather_master_app"><img alt="GitHub" src="preview/get_on_izzy_btn.png" height="80"/></a>
<a href="https://play.google.com/store/apps/details?id=com.pranshulgg.weather_master"><img alt="GitHub" src="preview/get_on_googleplay_btn.png" height="80"/></a></div>
<br>
![app_thumbnail](preview/new_thumbnail.png)
@@ -44,28 +46,87 @@
<img src="preview/preview_2.png" width="250">
<img src="preview/preview_3.png" width="250">
<img src="preview/preview_4.png" width="250">
<img src="preview/preview_5.png" width="250">
</div>
<br>
# 🌐 Translate the app on [Crowdin](https://crowdin.com/project/weathermaster)
- **Feel free to open an issue if you want to request a language**
<a href="https://crowdin.com/project/weathermaster"><img src="https://badges.crowdin.net/weathermaster/localized.svg" width="200"> </a>
# 🌦️ Supported weather sources
- **Open Meteo**
- **Met Norway**
- **National Weather Service (NWS)**
- **NWS**
- **SMHI**
- **DWD**
- **Meteo-France**
- **FMI**
- **ECCC**
- **BMKG**
- **China**
- **AccuWeather**
- **Meteo AM**
- **IPMA**
- **WeatherApi.com**
- **Gismeteo**
- **Met Office** _(requires your own API key — sign up [here](https://www.metoffice.gov.uk/))_
- **AEMET** _(requires your own API key — sign
up [here](https://opendata.aemet.es/centrodedescargas/altaUsuario))_
- **IMD**
- **WMO Severe Weather Information Centre**
- **FOSS Public Alert Server**
- **CWA**
- **Pirate Weather**
- **JMA**
- **IMET**
- **OpenWeather**
- _**And more to be added**_
Some sources need a free API key from the provider before you can select them — add yours from a
location's weather source picker, or from **Settings → Weather Sources → API key config**.
# 🌐 Translate the app on [Crowdin](https://crowdin.com/project/weathermaster)
_**Feel free to open an issue if you want to request a language**_
<a href="https://crowdin.com/project/weathermaster" style="background-color: red"></a>
[![ar-SA translation](https://img.shields.io/badge/dynamic/json?color=blue&label=ar-SA&style=flat&logo=crowdin&query=%24.progress.0.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![az translation](https://img.shields.io/badge/dynamic/json?color=blue&label=az&style=flat&logo=crowdin&query=%24.progress.1.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![bg translation](https://img.shields.io/badge/dynamic/json?color=blue&label=bg&style=flat&logo=crowdin&query=%24.progress.2.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![ca translation](https://img.shields.io/badge/dynamic/json?color=blue&label=ca&style=flat&logo=crowdin&query=%24.progress.3.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![cs translation](https://img.shields.io/badge/dynamic/json?color=blue&label=cs&style=flat&logo=crowdin&query=%24.progress.4.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![de translation](https://img.shields.io/badge/dynamic/json?color=blue&label=de&style=flat&logo=crowdin&query=%24.progress.5.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![el translation](https://img.shields.io/badge/dynamic/json?color=blue&label=el&style=flat&logo=crowdin&query=%24.progress.6.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![es-ES translation](https://img.shields.io/badge/dynamic/json?color=blue&label=es-ES&style=flat&logo=crowdin&query=%24.progress.7.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![fa translation](https://img.shields.io/badge/dynamic/json?color=blue&label=fa&style=flat&logo=crowdin&query=%24.progress.8.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![fi translation](https://img.shields.io/badge/dynamic/json?color=blue&label=fi&style=flat&logo=crowdin&query=%24.progress.9.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![fil translation](https://img.shields.io/badge/dynamic/json?color=blue&label=fil&style=flat&logo=crowdin&query=%24.progress.10.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![fr translation](https://img.shields.io/badge/dynamic/json?color=blue&label=fr&style=flat&logo=crowdin&query=%24.progress.11.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![hu translation](https://img.shields.io/badge/dynamic/json?color=blue&label=hu&style=flat&logo=crowdin&query=%24.progress.12.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![id translation](https://img.shields.io/badge/dynamic/json?color=blue&label=id&style=flat&logo=crowdin&query=%24.progress.13.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![it translation](https://img.shields.io/badge/dynamic/json?color=blue&label=it&style=flat&logo=crowdin&query=%24.progress.14.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![ja translation](https://img.shields.io/badge/dynamic/json?color=blue&label=ja&style=flat&logo=crowdin&query=%24.progress.15.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![ko translation](https://img.shields.io/badge/dynamic/json?color=blue&label=ko&style=flat&logo=crowdin&query=%24.progress.16.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![lt translation](https://img.shields.io/badge/dynamic/json?color=blue&label=lt&style=flat&logo=crowdin&query=%24.progress.17.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![nl translation](https://img.shields.io/badge/dynamic/json?color=blue&label=nl&style=flat&logo=crowdin&query=%24.progress.18.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![pl translation](https://img.shields.io/badge/dynamic/json?color=blue&label=pl&style=flat&logo=crowdin&query=%24.progress.19.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![pt-BR translation](https://img.shields.io/badge/dynamic/json?color=blue&label=pt-BR&style=flat&logo=crowdin&query=%24.progress.20.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![pt-PT translation](https://img.shields.io/badge/dynamic/json?color=blue&label=pt-PT&style=flat&logo=crowdin&query=%24.progress.21.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![ro translation](https://img.shields.io/badge/dynamic/json?color=blue&label=ro&style=flat&logo=crowdin&query=%24.progress.22.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![ru translation](https://img.shields.io/badge/dynamic/json?color=blue&label=ru&style=flat&logo=crowdin&query=%24.progress.23.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![sl translation](https://img.shields.io/badge/dynamic/json?color=blue&label=sl&style=flat&logo=crowdin&query=%24.progress.24.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![sr translation](https://img.shields.io/badge/dynamic/json?color=blue&label=sr&style=flat&logo=crowdin&query=%24.progress.25.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![sr-CS translation](https://img.shields.io/badge/dynamic/json?color=blue&label=sr-CS&style=flat&logo=crowdin&query=%24.progress.26.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![sv-SE translation](https://img.shields.io/badge/dynamic/json?color=blue&label=sv-SE&style=flat&logo=crowdin&query=%24.progress.27.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![th translation](https://img.shields.io/badge/dynamic/json?color=blue&label=th&style=flat&logo=crowdin&query=%24.progress.28.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![tr translation](https://img.shields.io/badge/dynamic/json?color=blue&label=tr&style=flat&logo=crowdin&query=%24.progress.29.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![uk translation](https://img.shields.io/badge/dynamic/json?color=blue&label=uk&style=flat&logo=crowdin&query=%24.progress.30.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![vi translation](https://img.shields.io/badge/dynamic/json?color=blue&label=vi&style=flat&logo=crowdin&query=%24.progress.31.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![zh-CN translation](https://img.shields.io/badge/dynamic/json?color=blue&label=zh-CN&style=flat&logo=crowdin&query=%24.progress.32.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![zh-TW translation](https://img.shields.io/badge/dynamic/json?color=blue&label=zh-TW&style=flat&logo=crowdin&query=%24.progress.33.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![ar-SA translation](https://img.shields.io/badge/dynamic/json?color=blue&label=ar-SA&style=flat&logo=crowdin&query=%24.progress.0.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![lt translation](https://img.shields.io/badge/dynamic/json?color=blue&label=lt&style=flat&logo=crowdin&query=%24.progress.18.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
[![he translation](https://img.shields.io/badge/dynamic/json?color=blue&label=he&style=flat&logo=crowdin&query=%24.progress.12.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16727791-741419.json)](https://crowdin.com/project/weathermaster)
# ✉️ Contact
For any questions or feedback, feel free to open an issue on GitHub or contact
+51 -8
View File
@@ -3,7 +3,7 @@ import java.util.Properties
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.compose)
id("com.google.devtools.ksp") version "2.3.4"
id("com.google.devtools.ksp") version "2.3.6"
id("com.google.dagger.hilt.android")
id("androidx.room")
kotlin("plugin.serialization") version "2.3.21"
@@ -22,10 +22,18 @@ val geoNamesUserNameKey =
val mfKey = providers.gradleProperty("MF_KEY").orNull ?: System.getenv("MF_KEY")
?: ""
val accuKey = providers.gradleProperty("ACCU_KEY").orNull ?: System.getenv("ACCU_KEY")
?: ""
val weatherapiKey =
providers.gradleProperty("WEATHERAPI_KEY").orNull ?: System.getenv("WEATHERAPI_KEY")
?: ""
val keystoreFile = file("../keystore/release.jks")
val hasKeystore = keystoreFile.exists()
val versionNameString = "3.11.0"
val playStore = false
android {
namespace = "com.pranshulgg.weather_master_app"
compileSdk {
@@ -34,11 +42,15 @@ android {
android.buildFeatures.buildConfig = true
defaultConfig {
applicationId = "com.pranshulgg.weather_master_app"
minSdk = 24
applicationId = if (playStore) {
"com.pranshulgg.weather_master"
} else {
"com.pranshulgg.weather_master_app"
}
minSdk = 26
targetSdk = 36
versionCode = 51
versionName = "3.3.0"
versionCode = 68
versionName = versionNameString
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -53,6 +65,30 @@ android {
"MF_KEY",
"\"$mfKey\""
)
buildConfigField(
"String",
"ACCU_KEY",
"\"$accuKey\""
)
buildConfigField(
"String",
"WEATHERAPI_KEY",
"\"$weatherapiKey\""
)
buildConfigField(
"String",
"APP_VERSION",
"\"v${versionNameString}\""
)
buildConfigField(
"boolean",
"IS_PLAYSTORE_BUILD",
playStore.toString()
)
}
signingConfigs {
@@ -83,7 +119,7 @@ android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
isCoreLibraryDesugaringEnabled = true
// isCoreLibraryDesugaringEnabled = true
}
buildFeatures {
compose = true
@@ -130,8 +166,14 @@ dependencies {
implementation(libs.common.suncalc)
implementation(libs.androidx.appcompat)
coreLibraryDesugaring(libs.desugar.jdk.libs)
implementation(libs.jts.core)
implementation(libs.jts.io.common)
implementation(libs.jackson.module.kotlin)
// coreLibraryDesugaring(libs.desugar.jdk.libs) // Not sure but it causes timezone crashes on some devices
implementation(libs.androidx.hilt.navigation.compose)
implementation(libs.converter.jaxb)
ksp(libs.room.compiler)
implementation(libs.hilt.android)
ksp(libs.hilt.android.compiler)
@@ -143,6 +185,7 @@ dependencies {
implementation(libs.androidx.work.runtime)
implementation(libs.hilt.work)
ksp(libs.hilt.metadata.jvm)
implementation(libs.androidx.glance)
-37
View File
@@ -1,37 +0,0 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.pranshulgg.weather_master_app",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 50,
"versionName": "3.2.0",
"outputFile": "app-release.apk"
}
],
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/app-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/app-release.dm"
]
}
],
"minSdkVersionForDexing": 24
}
@@ -0,0 +1,747 @@
{
"formatVersion": 1,
"database": {
"version": 43,
"identityHash": "3498b6cf93a31e50cf1bef443490315f",
"entities": [
{
"tableName": "weather_locations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `country` TEXT NOT NULL, `lat` REAL NOT NULL, `lon` REAL NOT NULL, `timezone` TEXT NOT NULL, `source` TEXT NOT NULL, `state` TEXT, `isFavorite` INTEGER NOT NULL, `isPinned` INTEGER NOT NULL, `countryCode` TEXT, `isDefault` INTEGER NOT NULL, `isDeviceLocation` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "country",
"columnName": "country",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lat",
"columnName": "lat",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "lon",
"columnName": "lon",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "timezone",
"columnName": "timezone",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "source",
"columnName": "source",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "state",
"affinity": "TEXT"
},
{
"fieldPath": "isFavorite",
"columnName": "isFavorite",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isPinned",
"columnName": "isPinned",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "countryCode",
"columnName": "countryCode",
"affinity": "TEXT"
},
{
"fieldPath": "isDefault",
"columnName": "isDefault",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDeviceLocation",
"columnName": "isDeviceLocation",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `humidity` REAL NOT NULL, `windSpeed` REAL, `windDirection` TEXT, `pressureMsl` REAL, `visibility` INTEGER, `cloudCover` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `feelsLike` REAL, `time` INTEGER NOT NULL, `dewPoint` REAL, `utcOffsetSeconds` INTEGER, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "cloudCover",
"columnName": "cloudCover",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "feelsLike",
"columnName": "feelsLike",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "utcOffsetSeconds",
"columnName": "utcOffsetSeconds",
"affinity": "INTEGER"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_weather_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_hourly",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `windSpeed` REAL, `windDirection` TEXT, `rain` REAL NOT NULL, `snowfall` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `time` INTEGER NOT NULL, `precipitationProbability` INTEGER, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rain",
"columnName": "rain",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfall",
"columnName": "snowfall",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbability",
"columnName": "precipitationProbability",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_hourly_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_hourly_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_daily",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperatureMin` REAL, `temperatureMax` REAL, `windSpeed` REAL, `windDirection` TEXT, `rainSum` REAL NOT NULL, `snowfallSum` REAL, `uvIndexMax` REAL, `weatherCondition` TEXT NOT NULL, `time` INTEGER NOT NULL, `precipitationProbabilityMax` INTEGER, `sunrise` INTEGER NOT NULL, `sunset` INTEGER NOT NULL, `moonrise` INTEGER NOT NULL, `moonset` INTEGER NOT NULL, `moonPhase` TEXT NOT NULL, `dawn` INTEGER NOT NULL, `dusk` INTEGER NOT NULL, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperatureMin",
"columnName": "temperatureMin",
"affinity": "REAL"
},
{
"fieldPath": "temperatureMax",
"columnName": "temperatureMax",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rainSum",
"columnName": "rainSum",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfallSum",
"columnName": "snowfallSum",
"affinity": "REAL"
},
{
"fieldPath": "uvIndexMax",
"columnName": "uvIndexMax",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbabilityMax",
"columnName": "precipitationProbabilityMax",
"affinity": "INTEGER"
},
{
"fieldPath": "sunrise",
"columnName": "sunrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "sunset",
"columnName": "sunset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonrise",
"columnName": "moonrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonset",
"columnName": "moonset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonPhase",
"columnName": "moonPhase",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "dawn",
"columnName": "dawn",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dusk",
"columnName": "dusk",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_daily_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_daily_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_units",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tempUnit` TEXT NOT NULL, `windUnit` TEXT NOT NULL, `distanceUnit` TEXT NOT NULL, `pressureUnit` TEXT NOT NULL, `precipitationUnit` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tempUnit",
"columnName": "tempUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "windUnit",
"columnName": "windUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "distanceUnit",
"columnName": "distanceUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureUnit",
"columnName": "pressureUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "precipitationUnit",
"columnName": "precipitationUnit",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_blocks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `isDaily` INTEGER NOT NULL, `type` TEXT NOT NULL, `isHidden` INTEGER NOT NULL, `position` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDaily",
"columnName": "isDaily",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isHidden",
"columnName": "isHidden",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "position",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
}
},
{
"tableName": "air_quality_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `usAqi` INTEGER, `pm10` REAL, `pm25` REAL, `carbonMonoxide` REAL, `nitrogenDioxide` REAL, `sulphurDioxide` REAL, `ozone` REAL, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "usAqi",
"columnName": "usAqi",
"affinity": "INTEGER"
},
{
"fieldPath": "pm10",
"columnName": "pm10",
"affinity": "REAL"
},
{
"fieldPath": "pm25",
"columnName": "pm25",
"affinity": "REAL"
},
{
"fieldPath": "carbonMonoxide",
"columnName": "carbonMonoxide",
"affinity": "REAL"
},
{
"fieldPath": "nitrogenDioxide",
"columnName": "nitrogenDioxide",
"affinity": "REAL"
},
{
"fieldPath": "sulphurDioxide",
"columnName": "sulphurDioxide",
"affinity": "REAL"
},
{
"fieldPath": "ozone",
"columnName": "ozone",
"affinity": "REAL"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_air_quality_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_air_quality_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "nws_location_gridpoints",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `officeId` TEXT NOT NULL, `gridX` INTEGER NOT NULL, `gridY` INTEGER NOT NULL, `stationIdentifier` TEXT NOT NULL, `lastUpdatedMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "officeId",
"columnName": "officeId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "gridX",
"columnName": "gridX",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gridY",
"columnName": "gridY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "stationIdentifier",
"columnName": "stationIdentifier",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastUpdatedMilli",
"columnName": "lastUpdatedMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_nws_location_gridpoints_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_nws_location_gridpoints_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "github",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `currentTag` TEXT NOT NULL, `lastFetchedTag` TEXT NOT NULL, `lastFetchedTime` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "currentTag",
"columnName": "currentTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTag",
"columnName": "lastFetchedTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTime",
"columnName": "lastFetchedTime",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3498b6cf93a31e50cf1bef443490315f')"
]
}
}
@@ -0,0 +1,767 @@
{
"formatVersion": 1,
"database": {
"version": 44,
"identityHash": "80da71ec25bcf07ba0d22811005aa37f",
"entities": [
{
"tableName": "weather_locations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `country` TEXT NOT NULL, `lat` REAL NOT NULL, `lon` REAL NOT NULL, `timezone` TEXT NOT NULL, `source` TEXT NOT NULL, `state` TEXT, `isFavorite` INTEGER NOT NULL, `isPinned` INTEGER NOT NULL, `countryCode` TEXT, `isDefault` INTEGER NOT NULL, `isDeviceLocation` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "country",
"columnName": "country",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lat",
"columnName": "lat",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "lon",
"columnName": "lon",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "timezone",
"columnName": "timezone",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "source",
"columnName": "source",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "state",
"affinity": "TEXT"
},
{
"fieldPath": "isFavorite",
"columnName": "isFavorite",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isPinned",
"columnName": "isPinned",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "countryCode",
"columnName": "countryCode",
"affinity": "TEXT"
},
{
"fieldPath": "isDefault",
"columnName": "isDefault",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDeviceLocation",
"columnName": "isDeviceLocation",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `humidity` REAL NOT NULL, `windSpeed` REAL, `windDirection` TEXT, `pressureMsl` REAL, `visibility` INTEGER, `cloudCover` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `feelsLike` REAL, `time` INTEGER NOT NULL, `dewPoint` REAL, `utcOffsetSeconds` INTEGER, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "cloudCover",
"columnName": "cloudCover",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "feelsLike",
"columnName": "feelsLike",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "utcOffsetSeconds",
"columnName": "utcOffsetSeconds",
"affinity": "INTEGER"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_weather_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_hourly",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `windSpeed` REAL, `windDirection` TEXT, `rain` REAL NOT NULL, `snowfall` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `time` INTEGER NOT NULL, `precipitationProbability` INTEGER, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rain",
"columnName": "rain",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfall",
"columnName": "snowfall",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbability",
"columnName": "precipitationProbability",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_hourly_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_hourly_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_daily",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperatureMin` REAL, `temperatureMax` REAL, `windSpeed` REAL, `windDirection` TEXT, `rainSum` REAL NOT NULL, `snowfallSum` REAL, `uvIndexMax` REAL, `weatherCondition` TEXT NOT NULL, `time` INTEGER NOT NULL, `precipitationProbabilityMax` INTEGER, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `sunrise` INTEGER NOT NULL, `sunset` INTEGER NOT NULL, `moonrise` INTEGER NOT NULL, `moonset` INTEGER NOT NULL, `moonPhase` TEXT NOT NULL, `dawn` INTEGER NOT NULL, `dusk` INTEGER NOT NULL, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperatureMin",
"columnName": "temperatureMin",
"affinity": "REAL"
},
{
"fieldPath": "temperatureMax",
"columnName": "temperatureMax",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rainSum",
"columnName": "rainSum",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfallSum",
"columnName": "snowfallSum",
"affinity": "REAL"
},
{
"fieldPath": "uvIndexMax",
"columnName": "uvIndexMax",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbabilityMax",
"columnName": "precipitationProbabilityMax",
"affinity": "INTEGER"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "sunrise",
"columnName": "sunrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "sunset",
"columnName": "sunset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonrise",
"columnName": "moonrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonset",
"columnName": "moonset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonPhase",
"columnName": "moonPhase",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "dawn",
"columnName": "dawn",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dusk",
"columnName": "dusk",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_daily_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_daily_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_units",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tempUnit` TEXT NOT NULL, `windUnit` TEXT NOT NULL, `distanceUnit` TEXT NOT NULL, `pressureUnit` TEXT NOT NULL, `precipitationUnit` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tempUnit",
"columnName": "tempUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "windUnit",
"columnName": "windUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "distanceUnit",
"columnName": "distanceUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureUnit",
"columnName": "pressureUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "precipitationUnit",
"columnName": "precipitationUnit",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_blocks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `isDaily` INTEGER NOT NULL, `type` TEXT NOT NULL, `isHidden` INTEGER NOT NULL, `position` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDaily",
"columnName": "isDaily",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isHidden",
"columnName": "isHidden",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "position",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
}
},
{
"tableName": "air_quality_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `usAqi` INTEGER, `pm10` REAL, `pm25` REAL, `carbonMonoxide` REAL, `nitrogenDioxide` REAL, `sulphurDioxide` REAL, `ozone` REAL, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "usAqi",
"columnName": "usAqi",
"affinity": "INTEGER"
},
{
"fieldPath": "pm10",
"columnName": "pm10",
"affinity": "REAL"
},
{
"fieldPath": "pm25",
"columnName": "pm25",
"affinity": "REAL"
},
{
"fieldPath": "carbonMonoxide",
"columnName": "carbonMonoxide",
"affinity": "REAL"
},
{
"fieldPath": "nitrogenDioxide",
"columnName": "nitrogenDioxide",
"affinity": "REAL"
},
{
"fieldPath": "sulphurDioxide",
"columnName": "sulphurDioxide",
"affinity": "REAL"
},
{
"fieldPath": "ozone",
"columnName": "ozone",
"affinity": "REAL"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_air_quality_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_air_quality_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "nws_location_gridpoints",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `officeId` TEXT NOT NULL, `gridX` INTEGER NOT NULL, `gridY` INTEGER NOT NULL, `stationIdentifier` TEXT NOT NULL, `lastUpdatedMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "officeId",
"columnName": "officeId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "gridX",
"columnName": "gridX",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gridY",
"columnName": "gridY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "stationIdentifier",
"columnName": "stationIdentifier",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastUpdatedMilli",
"columnName": "lastUpdatedMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_nws_location_gridpoints_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_nws_location_gridpoints_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "github",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `currentTag` TEXT NOT NULL, `lastFetchedTag` TEXT NOT NULL, `lastFetchedTime` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "currentTag",
"columnName": "currentTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTag",
"columnName": "lastFetchedTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTime",
"columnName": "lastFetchedTime",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '80da71ec25bcf07ba0d22811005aa37f')"
]
}
}
@@ -0,0 +1,851 @@
{
"formatVersion": 1,
"database": {
"version": 45,
"identityHash": "b2ca5c75db987a1d27628fc45eac72bf",
"entities": [
{
"tableName": "weather_locations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `country` TEXT NOT NULL, `lat` REAL NOT NULL, `lon` REAL NOT NULL, `timezone` TEXT NOT NULL, `source` TEXT NOT NULL, `state` TEXT, `isFavorite` INTEGER NOT NULL, `isPinned` INTEGER NOT NULL, `countryCode` TEXT, `isDefault` INTEGER NOT NULL, `isDeviceLocation` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "country",
"columnName": "country",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lat",
"columnName": "lat",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "lon",
"columnName": "lon",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "timezone",
"columnName": "timezone",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "source",
"columnName": "source",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "state",
"affinity": "TEXT"
},
{
"fieldPath": "isFavorite",
"columnName": "isFavorite",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isPinned",
"columnName": "isPinned",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "countryCode",
"columnName": "countryCode",
"affinity": "TEXT"
},
{
"fieldPath": "isDefault",
"columnName": "isDefault",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDeviceLocation",
"columnName": "isDeviceLocation",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `humidity` REAL NOT NULL, `windSpeed` REAL, `windDirection` TEXT, `pressureMsl` REAL, `visibility` INTEGER, `cloudCover` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `feelsLike` REAL, `time` INTEGER NOT NULL, `dewPoint` REAL, `utcOffsetSeconds` INTEGER, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "cloudCover",
"columnName": "cloudCover",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "feelsLike",
"columnName": "feelsLike",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "utcOffsetSeconds",
"columnName": "utcOffsetSeconds",
"affinity": "INTEGER"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_weather_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_hourly",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `windSpeed` REAL, `windDirection` TEXT, `rain` REAL NOT NULL, `snowfall` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `time` INTEGER NOT NULL, `precipitationProbability` INTEGER, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rain",
"columnName": "rain",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfall",
"columnName": "snowfall",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbability",
"columnName": "precipitationProbability",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_hourly_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_hourly_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_daily",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperatureMin` REAL, `temperatureMax` REAL, `windSpeed` REAL, `windDirection` TEXT, `rainSum` REAL NOT NULL, `snowfallSum` REAL, `uvIndexMax` REAL, `weatherCondition` TEXT NOT NULL, `time` INTEGER NOT NULL, `precipitationProbabilityMax` INTEGER, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `sunrise` INTEGER NOT NULL, `sunset` INTEGER NOT NULL, `moonrise` INTEGER NOT NULL, `moonset` INTEGER NOT NULL, `moonPhase` TEXT NOT NULL, `dawn` INTEGER NOT NULL, `dusk` INTEGER NOT NULL, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperatureMin",
"columnName": "temperatureMin",
"affinity": "REAL"
},
{
"fieldPath": "temperatureMax",
"columnName": "temperatureMax",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rainSum",
"columnName": "rainSum",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfallSum",
"columnName": "snowfallSum",
"affinity": "REAL"
},
{
"fieldPath": "uvIndexMax",
"columnName": "uvIndexMax",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbabilityMax",
"columnName": "precipitationProbabilityMax",
"affinity": "INTEGER"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "sunrise",
"columnName": "sunrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "sunset",
"columnName": "sunset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonrise",
"columnName": "moonrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonset",
"columnName": "moonset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonPhase",
"columnName": "moonPhase",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "dawn",
"columnName": "dawn",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dusk",
"columnName": "dusk",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_daily_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_daily_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_units",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tempUnit` TEXT NOT NULL, `windUnit` TEXT NOT NULL, `distanceUnit` TEXT NOT NULL, `pressureUnit` TEXT NOT NULL, `precipitationUnit` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tempUnit",
"columnName": "tempUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "windUnit",
"columnName": "windUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "distanceUnit",
"columnName": "distanceUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureUnit",
"columnName": "pressureUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "precipitationUnit",
"columnName": "precipitationUnit",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_blocks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `isDaily` INTEGER NOT NULL, `type` TEXT NOT NULL, `isHidden` INTEGER NOT NULL, `position` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDaily",
"columnName": "isDaily",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isHidden",
"columnName": "isHidden",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "position",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
}
},
{
"tableName": "air_quality_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `usAqi` INTEGER, `pm10` REAL, `pm25` REAL, `carbonMonoxide` REAL, `nitrogenDioxide` REAL, `sulphurDioxide` REAL, `ozone` REAL, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "usAqi",
"columnName": "usAqi",
"affinity": "INTEGER"
},
{
"fieldPath": "pm10",
"columnName": "pm10",
"affinity": "REAL"
},
{
"fieldPath": "pm25",
"columnName": "pm25",
"affinity": "REAL"
},
{
"fieldPath": "carbonMonoxide",
"columnName": "carbonMonoxide",
"affinity": "REAL"
},
{
"fieldPath": "nitrogenDioxide",
"columnName": "nitrogenDioxide",
"affinity": "REAL"
},
{
"fieldPath": "sulphurDioxide",
"columnName": "sulphurDioxide",
"affinity": "REAL"
},
{
"fieldPath": "ozone",
"columnName": "ozone",
"affinity": "REAL"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_air_quality_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_air_quality_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "nws_location_gridpoints",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `officeId` TEXT NOT NULL, `gridX` INTEGER NOT NULL, `gridY` INTEGER NOT NULL, `stationIdentifier` TEXT NOT NULL, `lastUpdatedMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "officeId",
"columnName": "officeId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "gridX",
"columnName": "gridX",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gridY",
"columnName": "gridY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "stationIdentifier",
"columnName": "stationIdentifier",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastUpdatedMilli",
"columnName": "lastUpdatedMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_nws_location_gridpoints_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_nws_location_gridpoints_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "github",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `currentTag` TEXT NOT NULL, `lastFetchedTag` TEXT NOT NULL, `lastFetchedTime` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "currentTag",
"columnName": "currentTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTag",
"columnName": "lastFetchedTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTime",
"columnName": "lastFetchedTime",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "air_quality_hourly",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `locationId` TEXT NOT NULL, `pm10` REAL, `pm25` REAL, `carbonMonoxide` REAL, `nitrogenDioxide` REAL, `sulphurDioxide` REAL, `ozone` REAL, `time` INTEGER NOT NULL, FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pm10",
"columnName": "pm10",
"affinity": "REAL"
},
{
"fieldPath": "pm25",
"columnName": "pm25",
"affinity": "REAL"
},
{
"fieldPath": "carbonMonoxide",
"columnName": "carbonMonoxide",
"affinity": "REAL"
},
{
"fieldPath": "nitrogenDioxide",
"columnName": "nitrogenDioxide",
"affinity": "REAL"
},
{
"fieldPath": "sulphurDioxide",
"columnName": "sulphurDioxide",
"affinity": "REAL"
},
{
"fieldPath": "ozone",
"columnName": "ozone",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_air_quality_hourly_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_air_quality_hourly_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'b2ca5c75db987a1d27628fc45eac72bf')"
]
}
}
@@ -0,0 +1,863 @@
{
"formatVersion": 1,
"database": {
"version": 46,
"identityHash": "fd66b7531bfe72f6bcac04b8fe26dc9e",
"entities": [
{
"tableName": "weather_locations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `country` TEXT NOT NULL, `lat` REAL NOT NULL, `lon` REAL NOT NULL, `timezone` TEXT NOT NULL, `source` TEXT NOT NULL, `state` TEXT, `isFavorite` INTEGER NOT NULL, `isPinned` INTEGER NOT NULL, `countryCode` TEXT, `isDefault` INTEGER NOT NULL, `isDeviceLocation` INTEGER NOT NULL, `alertSource` TEXT NOT NULL, `airQualitySource` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "country",
"columnName": "country",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lat",
"columnName": "lat",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "lon",
"columnName": "lon",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "timezone",
"columnName": "timezone",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "source",
"columnName": "source",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "state",
"affinity": "TEXT"
},
{
"fieldPath": "isFavorite",
"columnName": "isFavorite",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isPinned",
"columnName": "isPinned",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "countryCode",
"columnName": "countryCode",
"affinity": "TEXT"
},
{
"fieldPath": "isDefault",
"columnName": "isDefault",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDeviceLocation",
"columnName": "isDeviceLocation",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "alertSource",
"columnName": "alertSource",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "airQualitySource",
"columnName": "airQualitySource",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `humidity` REAL NOT NULL, `windSpeed` REAL, `windDirection` TEXT, `pressureMsl` REAL, `visibility` INTEGER, `cloudCover` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `feelsLike` REAL, `time` INTEGER NOT NULL, `dewPoint` REAL, `utcOffsetSeconds` INTEGER, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "cloudCover",
"columnName": "cloudCover",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "feelsLike",
"columnName": "feelsLike",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "utcOffsetSeconds",
"columnName": "utcOffsetSeconds",
"affinity": "INTEGER"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_weather_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_hourly",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `windSpeed` REAL, `windDirection` TEXT, `rain` REAL NOT NULL, `snowfall` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `time` INTEGER NOT NULL, `precipitationProbability` INTEGER, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rain",
"columnName": "rain",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfall",
"columnName": "snowfall",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbability",
"columnName": "precipitationProbability",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_hourly_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_hourly_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_daily",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperatureMin` REAL, `temperatureMax` REAL, `windSpeed` REAL, `windDirection` TEXT, `rainSum` REAL NOT NULL, `snowfallSum` REAL, `uvIndexMax` REAL, `weatherCondition` TEXT NOT NULL, `time` INTEGER NOT NULL, `precipitationProbabilityMax` INTEGER, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `sunrise` INTEGER NOT NULL, `sunset` INTEGER NOT NULL, `moonrise` INTEGER NOT NULL, `moonset` INTEGER NOT NULL, `moonPhase` TEXT NOT NULL, `dawn` INTEGER NOT NULL, `dusk` INTEGER NOT NULL, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperatureMin",
"columnName": "temperatureMin",
"affinity": "REAL"
},
{
"fieldPath": "temperatureMax",
"columnName": "temperatureMax",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rainSum",
"columnName": "rainSum",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfallSum",
"columnName": "snowfallSum",
"affinity": "REAL"
},
{
"fieldPath": "uvIndexMax",
"columnName": "uvIndexMax",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbabilityMax",
"columnName": "precipitationProbabilityMax",
"affinity": "INTEGER"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "sunrise",
"columnName": "sunrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "sunset",
"columnName": "sunset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonrise",
"columnName": "moonrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonset",
"columnName": "moonset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonPhase",
"columnName": "moonPhase",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "dawn",
"columnName": "dawn",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dusk",
"columnName": "dusk",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_daily_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_daily_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_units",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tempUnit` TEXT NOT NULL, `windUnit` TEXT NOT NULL, `distanceUnit` TEXT NOT NULL, `pressureUnit` TEXT NOT NULL, `precipitationUnit` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tempUnit",
"columnName": "tempUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "windUnit",
"columnName": "windUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "distanceUnit",
"columnName": "distanceUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureUnit",
"columnName": "pressureUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "precipitationUnit",
"columnName": "precipitationUnit",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_blocks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `isDaily` INTEGER NOT NULL, `type` TEXT NOT NULL, `isHidden` INTEGER NOT NULL, `position` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDaily",
"columnName": "isDaily",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isHidden",
"columnName": "isHidden",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "position",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
}
},
{
"tableName": "air_quality_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `usAqi` INTEGER, `pm10` REAL, `pm25` REAL, `carbonMonoxide` REAL, `nitrogenDioxide` REAL, `sulphurDioxide` REAL, `ozone` REAL, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "usAqi",
"columnName": "usAqi",
"affinity": "INTEGER"
},
{
"fieldPath": "pm10",
"columnName": "pm10",
"affinity": "REAL"
},
{
"fieldPath": "pm25",
"columnName": "pm25",
"affinity": "REAL"
},
{
"fieldPath": "carbonMonoxide",
"columnName": "carbonMonoxide",
"affinity": "REAL"
},
{
"fieldPath": "nitrogenDioxide",
"columnName": "nitrogenDioxide",
"affinity": "REAL"
},
{
"fieldPath": "sulphurDioxide",
"columnName": "sulphurDioxide",
"affinity": "REAL"
},
{
"fieldPath": "ozone",
"columnName": "ozone",
"affinity": "REAL"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_air_quality_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_air_quality_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "nws_location_gridpoints",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `officeId` TEXT NOT NULL, `gridX` INTEGER NOT NULL, `gridY` INTEGER NOT NULL, `stationIdentifier` TEXT NOT NULL, `lastUpdatedMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "officeId",
"columnName": "officeId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "gridX",
"columnName": "gridX",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gridY",
"columnName": "gridY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "stationIdentifier",
"columnName": "stationIdentifier",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastUpdatedMilli",
"columnName": "lastUpdatedMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_nws_location_gridpoints_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_nws_location_gridpoints_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "github",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `currentTag` TEXT NOT NULL, `lastFetchedTag` TEXT NOT NULL, `lastFetchedTime` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "currentTag",
"columnName": "currentTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTag",
"columnName": "lastFetchedTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTime",
"columnName": "lastFetchedTime",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "air_quality_hourly",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `locationId` TEXT NOT NULL, `pm10` REAL, `pm25` REAL, `carbonMonoxide` REAL, `nitrogenDioxide` REAL, `sulphurDioxide` REAL, `ozone` REAL, `time` INTEGER NOT NULL, FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pm10",
"columnName": "pm10",
"affinity": "REAL"
},
{
"fieldPath": "pm25",
"columnName": "pm25",
"affinity": "REAL"
},
{
"fieldPath": "carbonMonoxide",
"columnName": "carbonMonoxide",
"affinity": "REAL"
},
{
"fieldPath": "nitrogenDioxide",
"columnName": "nitrogenDioxide",
"affinity": "REAL"
},
{
"fieldPath": "sulphurDioxide",
"columnName": "sulphurDioxide",
"affinity": "REAL"
},
{
"fieldPath": "ozone",
"columnName": "ozone",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_air_quality_hourly_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_air_quality_hourly_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'fd66b7531bfe72f6bcac04b8fe26dc9e')"
]
}
}
@@ -0,0 +1,863 @@
{
"formatVersion": 1,
"database": {
"version": 47,
"identityHash": "fd66b7531bfe72f6bcac04b8fe26dc9e",
"entities": [
{
"tableName": "weather_locations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `country` TEXT NOT NULL, `lat` REAL NOT NULL, `lon` REAL NOT NULL, `timezone` TEXT NOT NULL, `source` TEXT NOT NULL, `state` TEXT, `isFavorite` INTEGER NOT NULL, `isPinned` INTEGER NOT NULL, `countryCode` TEXT, `isDefault` INTEGER NOT NULL, `isDeviceLocation` INTEGER NOT NULL, `alertSource` TEXT NOT NULL, `airQualitySource` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "country",
"columnName": "country",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lat",
"columnName": "lat",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "lon",
"columnName": "lon",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "timezone",
"columnName": "timezone",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "source",
"columnName": "source",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "state",
"affinity": "TEXT"
},
{
"fieldPath": "isFavorite",
"columnName": "isFavorite",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isPinned",
"columnName": "isPinned",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "countryCode",
"columnName": "countryCode",
"affinity": "TEXT"
},
{
"fieldPath": "isDefault",
"columnName": "isDefault",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDeviceLocation",
"columnName": "isDeviceLocation",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "alertSource",
"columnName": "alertSource",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "airQualitySource",
"columnName": "airQualitySource",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `humidity` REAL NOT NULL, `windSpeed` REAL, `windDirection` TEXT, `pressureMsl` REAL, `visibility` INTEGER, `cloudCover` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `feelsLike` REAL, `time` INTEGER NOT NULL, `dewPoint` REAL, `utcOffsetSeconds` INTEGER, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "cloudCover",
"columnName": "cloudCover",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "feelsLike",
"columnName": "feelsLike",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "utcOffsetSeconds",
"columnName": "utcOffsetSeconds",
"affinity": "INTEGER"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_weather_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_hourly",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `windSpeed` REAL, `windDirection` TEXT, `rain` REAL NOT NULL, `snowfall` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `time` INTEGER NOT NULL, `precipitationProbability` INTEGER, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rain",
"columnName": "rain",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfall",
"columnName": "snowfall",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbability",
"columnName": "precipitationProbability",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_hourly_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_hourly_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_daily",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperatureMin` REAL, `temperatureMax` REAL, `windSpeed` REAL, `windDirection` TEXT, `rainSum` REAL NOT NULL, `snowfallSum` REAL, `uvIndexMax` REAL, `weatherCondition` TEXT NOT NULL, `time` INTEGER NOT NULL, `precipitationProbabilityMax` INTEGER, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `sunrise` INTEGER NOT NULL, `sunset` INTEGER NOT NULL, `moonrise` INTEGER NOT NULL, `moonset` INTEGER NOT NULL, `moonPhase` TEXT NOT NULL, `dawn` INTEGER NOT NULL, `dusk` INTEGER NOT NULL, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperatureMin",
"columnName": "temperatureMin",
"affinity": "REAL"
},
{
"fieldPath": "temperatureMax",
"columnName": "temperatureMax",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rainSum",
"columnName": "rainSum",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfallSum",
"columnName": "snowfallSum",
"affinity": "REAL"
},
{
"fieldPath": "uvIndexMax",
"columnName": "uvIndexMax",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbabilityMax",
"columnName": "precipitationProbabilityMax",
"affinity": "INTEGER"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "sunrise",
"columnName": "sunrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "sunset",
"columnName": "sunset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonrise",
"columnName": "moonrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonset",
"columnName": "moonset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonPhase",
"columnName": "moonPhase",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "dawn",
"columnName": "dawn",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dusk",
"columnName": "dusk",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_daily_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_daily_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_units",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tempUnit` TEXT NOT NULL, `windUnit` TEXT NOT NULL, `distanceUnit` TEXT NOT NULL, `pressureUnit` TEXT NOT NULL, `precipitationUnit` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tempUnit",
"columnName": "tempUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "windUnit",
"columnName": "windUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "distanceUnit",
"columnName": "distanceUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureUnit",
"columnName": "pressureUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "precipitationUnit",
"columnName": "precipitationUnit",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_blocks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `isDaily` INTEGER NOT NULL, `type` TEXT NOT NULL, `isHidden` INTEGER NOT NULL, `position` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDaily",
"columnName": "isDaily",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isHidden",
"columnName": "isHidden",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "position",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
}
},
{
"tableName": "air_quality_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `usAqi` INTEGER, `pm10` REAL, `pm25` REAL, `carbonMonoxide` REAL, `nitrogenDioxide` REAL, `sulphurDioxide` REAL, `ozone` REAL, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "usAqi",
"columnName": "usAqi",
"affinity": "INTEGER"
},
{
"fieldPath": "pm10",
"columnName": "pm10",
"affinity": "REAL"
},
{
"fieldPath": "pm25",
"columnName": "pm25",
"affinity": "REAL"
},
{
"fieldPath": "carbonMonoxide",
"columnName": "carbonMonoxide",
"affinity": "REAL"
},
{
"fieldPath": "nitrogenDioxide",
"columnName": "nitrogenDioxide",
"affinity": "REAL"
},
{
"fieldPath": "sulphurDioxide",
"columnName": "sulphurDioxide",
"affinity": "REAL"
},
{
"fieldPath": "ozone",
"columnName": "ozone",
"affinity": "REAL"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_air_quality_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_air_quality_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "nws_location_gridpoints",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `officeId` TEXT NOT NULL, `gridX` INTEGER NOT NULL, `gridY` INTEGER NOT NULL, `stationIdentifier` TEXT NOT NULL, `lastUpdatedMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "officeId",
"columnName": "officeId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "gridX",
"columnName": "gridX",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gridY",
"columnName": "gridY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "stationIdentifier",
"columnName": "stationIdentifier",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastUpdatedMilli",
"columnName": "lastUpdatedMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_nws_location_gridpoints_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_nws_location_gridpoints_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "github",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `currentTag` TEXT NOT NULL, `lastFetchedTag` TEXT NOT NULL, `lastFetchedTime` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "currentTag",
"columnName": "currentTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTag",
"columnName": "lastFetchedTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTime",
"columnName": "lastFetchedTime",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "air_quality_hourly",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `locationId` TEXT NOT NULL, `pm10` REAL, `pm25` REAL, `carbonMonoxide` REAL, `nitrogenDioxide` REAL, `sulphurDioxide` REAL, `ozone` REAL, `time` INTEGER NOT NULL, FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pm10",
"columnName": "pm10",
"affinity": "REAL"
},
{
"fieldPath": "pm25",
"columnName": "pm25",
"affinity": "REAL"
},
{
"fieldPath": "carbonMonoxide",
"columnName": "carbonMonoxide",
"affinity": "REAL"
},
{
"fieldPath": "nitrogenDioxide",
"columnName": "nitrogenDioxide",
"affinity": "REAL"
},
{
"fieldPath": "sulphurDioxide",
"columnName": "sulphurDioxide",
"affinity": "REAL"
},
{
"fieldPath": "ozone",
"columnName": "ozone",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_air_quality_hourly_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_air_quality_hourly_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'fd66b7531bfe72f6bcac04b8fe26dc9e')"
]
}
}
@@ -0,0 +1,868 @@
{
"formatVersion": 1,
"database": {
"version": 48,
"identityHash": "5ca7c9b34ef5941f3d7515379d9646f9",
"entities": [
{
"tableName": "weather_locations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `country` TEXT NOT NULL, `lat` REAL NOT NULL, `lon` REAL NOT NULL, `timezone` TEXT NOT NULL, `source` TEXT NOT NULL, `state` TEXT, `isFavorite` INTEGER NOT NULL, `isPinned` INTEGER NOT NULL, `countryCode` TEXT, `isDefault` INTEGER NOT NULL, `isDeviceLocation` INTEGER NOT NULL, `alertSource` TEXT NOT NULL, `airQualitySource` TEXT NOT NULL, `customName` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "country",
"columnName": "country",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lat",
"columnName": "lat",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "lon",
"columnName": "lon",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "timezone",
"columnName": "timezone",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "source",
"columnName": "source",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "state",
"affinity": "TEXT"
},
{
"fieldPath": "isFavorite",
"columnName": "isFavorite",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isPinned",
"columnName": "isPinned",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "countryCode",
"columnName": "countryCode",
"affinity": "TEXT"
},
{
"fieldPath": "isDefault",
"columnName": "isDefault",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDeviceLocation",
"columnName": "isDeviceLocation",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "alertSource",
"columnName": "alertSource",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "airQualitySource",
"columnName": "airQualitySource",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "customName",
"columnName": "customName",
"affinity": "TEXT"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `humidity` REAL NOT NULL, `windSpeed` REAL, `windDirection` TEXT, `pressureMsl` REAL, `visibility` INTEGER, `cloudCover` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `feelsLike` REAL, `time` INTEGER NOT NULL, `dewPoint` REAL, `utcOffsetSeconds` INTEGER, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "cloudCover",
"columnName": "cloudCover",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "feelsLike",
"columnName": "feelsLike",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "utcOffsetSeconds",
"columnName": "utcOffsetSeconds",
"affinity": "INTEGER"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_weather_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_hourly",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `windSpeed` REAL, `windDirection` TEXT, `rain` REAL NOT NULL, `snowfall` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `time` INTEGER NOT NULL, `precipitationProbability` INTEGER, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rain",
"columnName": "rain",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfall",
"columnName": "snowfall",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbability",
"columnName": "precipitationProbability",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_hourly_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_hourly_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_daily",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperatureMin` REAL, `temperatureMax` REAL, `windSpeed` REAL, `windDirection` TEXT, `rainSum` REAL NOT NULL, `snowfallSum` REAL, `uvIndexMax` REAL, `weatherCondition` TEXT NOT NULL, `time` INTEGER NOT NULL, `precipitationProbabilityMax` INTEGER, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `sunrise` INTEGER NOT NULL, `sunset` INTEGER NOT NULL, `moonrise` INTEGER NOT NULL, `moonset` INTEGER NOT NULL, `moonPhase` TEXT NOT NULL, `dawn` INTEGER NOT NULL, `dusk` INTEGER NOT NULL, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperatureMin",
"columnName": "temperatureMin",
"affinity": "REAL"
},
{
"fieldPath": "temperatureMax",
"columnName": "temperatureMax",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rainSum",
"columnName": "rainSum",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfallSum",
"columnName": "snowfallSum",
"affinity": "REAL"
},
{
"fieldPath": "uvIndexMax",
"columnName": "uvIndexMax",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbabilityMax",
"columnName": "precipitationProbabilityMax",
"affinity": "INTEGER"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "sunrise",
"columnName": "sunrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "sunset",
"columnName": "sunset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonrise",
"columnName": "moonrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonset",
"columnName": "moonset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonPhase",
"columnName": "moonPhase",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "dawn",
"columnName": "dawn",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dusk",
"columnName": "dusk",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_daily_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_daily_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_units",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tempUnit` TEXT NOT NULL, `windUnit` TEXT NOT NULL, `distanceUnit` TEXT NOT NULL, `pressureUnit` TEXT NOT NULL, `precipitationUnit` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tempUnit",
"columnName": "tempUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "windUnit",
"columnName": "windUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "distanceUnit",
"columnName": "distanceUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureUnit",
"columnName": "pressureUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "precipitationUnit",
"columnName": "precipitationUnit",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_blocks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `isDaily` INTEGER NOT NULL, `type` TEXT NOT NULL, `isHidden` INTEGER NOT NULL, `position` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDaily",
"columnName": "isDaily",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isHidden",
"columnName": "isHidden",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "position",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
}
},
{
"tableName": "air_quality_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `usAqi` INTEGER, `pm10` REAL, `pm25` REAL, `carbonMonoxide` REAL, `nitrogenDioxide` REAL, `sulphurDioxide` REAL, `ozone` REAL, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "usAqi",
"columnName": "usAqi",
"affinity": "INTEGER"
},
{
"fieldPath": "pm10",
"columnName": "pm10",
"affinity": "REAL"
},
{
"fieldPath": "pm25",
"columnName": "pm25",
"affinity": "REAL"
},
{
"fieldPath": "carbonMonoxide",
"columnName": "carbonMonoxide",
"affinity": "REAL"
},
{
"fieldPath": "nitrogenDioxide",
"columnName": "nitrogenDioxide",
"affinity": "REAL"
},
{
"fieldPath": "sulphurDioxide",
"columnName": "sulphurDioxide",
"affinity": "REAL"
},
{
"fieldPath": "ozone",
"columnName": "ozone",
"affinity": "REAL"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_air_quality_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_air_quality_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "nws_location_gridpoints",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `officeId` TEXT NOT NULL, `gridX` INTEGER NOT NULL, `gridY` INTEGER NOT NULL, `stationIdentifier` TEXT NOT NULL, `lastUpdatedMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "officeId",
"columnName": "officeId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "gridX",
"columnName": "gridX",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gridY",
"columnName": "gridY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "stationIdentifier",
"columnName": "stationIdentifier",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastUpdatedMilli",
"columnName": "lastUpdatedMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_nws_location_gridpoints_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_nws_location_gridpoints_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "github",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `currentTag` TEXT NOT NULL, `lastFetchedTag` TEXT NOT NULL, `lastFetchedTime` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "currentTag",
"columnName": "currentTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTag",
"columnName": "lastFetchedTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTime",
"columnName": "lastFetchedTime",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "air_quality_hourly",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `locationId` TEXT NOT NULL, `pm10` REAL, `pm25` REAL, `carbonMonoxide` REAL, `nitrogenDioxide` REAL, `sulphurDioxide` REAL, `ozone` REAL, `time` INTEGER NOT NULL, FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pm10",
"columnName": "pm10",
"affinity": "REAL"
},
{
"fieldPath": "pm25",
"columnName": "pm25",
"affinity": "REAL"
},
{
"fieldPath": "carbonMonoxide",
"columnName": "carbonMonoxide",
"affinity": "REAL"
},
{
"fieldPath": "nitrogenDioxide",
"columnName": "nitrogenDioxide",
"affinity": "REAL"
},
{
"fieldPath": "sulphurDioxide",
"columnName": "sulphurDioxide",
"affinity": "REAL"
},
{
"fieldPath": "ozone",
"columnName": "ozone",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_air_quality_hourly_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_air_quality_hourly_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5ca7c9b34ef5941f3d7515379d9646f9')"
]
}
}
@@ -0,0 +1,916 @@
{
"formatVersion": 1,
"database": {
"version": 49,
"identityHash": "41f3af0cd4a758a20290098071993b9c",
"entities": [
{
"tableName": "weather_locations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `country` TEXT NOT NULL, `lat` REAL NOT NULL, `lon` REAL NOT NULL, `timezone` TEXT NOT NULL, `source` TEXT NOT NULL, `state` TEXT, `isFavorite` INTEGER NOT NULL, `isPinned` INTEGER NOT NULL, `countryCode` TEXT, `isDefault` INTEGER NOT NULL, `isDeviceLocation` INTEGER NOT NULL, `alertSource` TEXT NOT NULL, `airQualitySource` TEXT NOT NULL, `customName` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "country",
"columnName": "country",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lat",
"columnName": "lat",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "lon",
"columnName": "lon",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "timezone",
"columnName": "timezone",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "source",
"columnName": "source",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "state",
"affinity": "TEXT"
},
{
"fieldPath": "isFavorite",
"columnName": "isFavorite",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isPinned",
"columnName": "isPinned",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "countryCode",
"columnName": "countryCode",
"affinity": "TEXT"
},
{
"fieldPath": "isDefault",
"columnName": "isDefault",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDeviceLocation",
"columnName": "isDeviceLocation",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "alertSource",
"columnName": "alertSource",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "airQualitySource",
"columnName": "airQualitySource",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "customName",
"columnName": "customName",
"affinity": "TEXT"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `humidity` REAL NOT NULL, `windSpeed` REAL, `windDirection` TEXT, `pressureMsl` REAL, `visibility` INTEGER, `cloudCover` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `feelsLike` REAL, `time` INTEGER NOT NULL, `dewPoint` REAL, `utcOffsetSeconds` INTEGER, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "cloudCover",
"columnName": "cloudCover",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "feelsLike",
"columnName": "feelsLike",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "utcOffsetSeconds",
"columnName": "utcOffsetSeconds",
"affinity": "INTEGER"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_weather_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_hourly",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperature` REAL, `windSpeed` REAL, `windDirection` TEXT, `rain` REAL NOT NULL, `snowfall` REAL, `uvIndex` REAL, `weatherCondition` TEXT NOT NULL, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `time` INTEGER NOT NULL, `precipitationProbability` INTEGER, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperature",
"columnName": "temperature",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rain",
"columnName": "rain",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfall",
"columnName": "snowfall",
"affinity": "REAL"
},
{
"fieldPath": "uvIndex",
"columnName": "uvIndex",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbability",
"columnName": "precipitationProbability",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_hourly_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_hourly_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_daily",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `temperatureMin` REAL, `temperatureMax` REAL, `windSpeed` REAL, `windDirection` TEXT, `rainSum` REAL NOT NULL, `snowfallSum` REAL, `uvIndexMax` REAL, `weatherCondition` TEXT NOT NULL, `time` INTEGER NOT NULL, `precipitationProbabilityMax` INTEGER, `pressureMsl` REAL, `visibility` INTEGER, `humidity` REAL, `dewPoint` REAL, `sunrise` INTEGER NOT NULL, `sunset` INTEGER NOT NULL, `moonrise` INTEGER NOT NULL, `moonset` INTEGER NOT NULL, `moonPhase` TEXT NOT NULL, `dawn` INTEGER NOT NULL, `dusk` INTEGER NOT NULL, PRIMARY KEY(`locationId`, `time`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "temperatureMin",
"columnName": "temperatureMin",
"affinity": "REAL"
},
{
"fieldPath": "temperatureMax",
"columnName": "temperatureMax",
"affinity": "REAL"
},
{
"fieldPath": "windSpeed",
"columnName": "windSpeed",
"affinity": "REAL"
},
{
"fieldPath": "windDirection",
"columnName": "windDirection",
"affinity": "TEXT"
},
{
"fieldPath": "rainSum",
"columnName": "rainSum",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "snowfallSum",
"columnName": "snowfallSum",
"affinity": "REAL"
},
{
"fieldPath": "uvIndexMax",
"columnName": "uvIndexMax",
"affinity": "REAL"
},
{
"fieldPath": "weatherCondition",
"columnName": "weatherCondition",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "precipitationProbabilityMax",
"columnName": "precipitationProbabilityMax",
"affinity": "INTEGER"
},
{
"fieldPath": "pressureMsl",
"columnName": "pressureMsl",
"affinity": "REAL"
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER"
},
{
"fieldPath": "humidity",
"columnName": "humidity",
"affinity": "REAL"
},
{
"fieldPath": "dewPoint",
"columnName": "dewPoint",
"affinity": "REAL"
},
{
"fieldPath": "sunrise",
"columnName": "sunrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "sunset",
"columnName": "sunset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonrise",
"columnName": "moonrise",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonset",
"columnName": "moonset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "moonPhase",
"columnName": "moonPhase",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "dawn",
"columnName": "dawn",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dusk",
"columnName": "dusk",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId",
"time"
]
},
"indices": [
{
"name": "index_weather_daily_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_weather_daily_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "weather_units",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tempUnit` TEXT NOT NULL, `windUnit` TEXT NOT NULL, `distanceUnit` TEXT NOT NULL, `pressureUnit` TEXT NOT NULL, `precipitationUnit` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tempUnit",
"columnName": "tempUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "windUnit",
"columnName": "windUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "distanceUnit",
"columnName": "distanceUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pressureUnit",
"columnName": "pressureUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "precipitationUnit",
"columnName": "precipitationUnit",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "weather_blocks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `isDaily` INTEGER NOT NULL, `type` TEXT NOT NULL, `isHidden` INTEGER NOT NULL, `position` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isDaily",
"columnName": "isDaily",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isHidden",
"columnName": "isHidden",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "position",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
}
},
{
"tableName": "air_quality_current",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `usAqi` INTEGER, `pm10` REAL, `pm25` REAL, `carbonMonoxide` REAL, `nitrogenDioxide` REAL, `sulphurDioxide` REAL, `ozone` REAL, `lastUpdatedInMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "usAqi",
"columnName": "usAqi",
"affinity": "INTEGER"
},
{
"fieldPath": "pm10",
"columnName": "pm10",
"affinity": "REAL"
},
{
"fieldPath": "pm25",
"columnName": "pm25",
"affinity": "REAL"
},
{
"fieldPath": "carbonMonoxide",
"columnName": "carbonMonoxide",
"affinity": "REAL"
},
{
"fieldPath": "nitrogenDioxide",
"columnName": "nitrogenDioxide",
"affinity": "REAL"
},
{
"fieldPath": "sulphurDioxide",
"columnName": "sulphurDioxide",
"affinity": "REAL"
},
{
"fieldPath": "ozone",
"columnName": "ozone",
"affinity": "REAL"
},
{
"fieldPath": "lastUpdatedInMilli",
"columnName": "lastUpdatedInMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_air_quality_current_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_air_quality_current_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "nws_location_gridpoints",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `officeId` TEXT NOT NULL, `gridX` INTEGER NOT NULL, `gridY` INTEGER NOT NULL, `stationIdentifier` TEXT NOT NULL, `lastUpdatedMilli` INTEGER NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "officeId",
"columnName": "officeId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "gridX",
"columnName": "gridX",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gridY",
"columnName": "gridY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "stationIdentifier",
"columnName": "stationIdentifier",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastUpdatedMilli",
"columnName": "lastUpdatedMilli",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_nws_location_gridpoints_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_nws_location_gridpoints_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "github",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `currentTag` TEXT NOT NULL, `lastFetchedTag` TEXT NOT NULL, `lastFetchedTime` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "currentTag",
"columnName": "currentTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTag",
"columnName": "lastFetchedTag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastFetchedTime",
"columnName": "lastFetchedTime",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
}
},
{
"tableName": "air_quality_hourly",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `locationId` TEXT NOT NULL, `pm10` REAL, `pm25` REAL, `carbonMonoxide` REAL, `nitrogenDioxide` REAL, `sulphurDioxide` REAL, `ozone` REAL, `time` INTEGER NOT NULL, FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pm10",
"columnName": "pm10",
"affinity": "REAL"
},
{
"fieldPath": "pm25",
"columnName": "pm25",
"affinity": "REAL"
},
{
"fieldPath": "carbonMonoxide",
"columnName": "carbonMonoxide",
"affinity": "REAL"
},
{
"fieldPath": "nitrogenDioxide",
"columnName": "nitrogenDioxide",
"affinity": "REAL"
},
{
"fieldPath": "sulphurDioxide",
"columnName": "sulphurDioxide",
"affinity": "REAL"
},
{
"fieldPath": "ozone",
"columnName": "ozone",
"affinity": "REAL"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_air_quality_hourly_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_air_quality_hourly_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "accu_locations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` TEXT NOT NULL, `cityKey` TEXT NOT NULL, PRIMARY KEY(`locationId`), FOREIGN KEY(`locationId`) REFERENCES `weather_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "locationId",
"columnName": "locationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "cityKey",
"columnName": "cityKey",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"locationId"
]
},
"indices": [
{
"name": "index_accu_locations_locationId",
"unique": false,
"columnNames": [
"locationId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_accu_locations_locationId` ON `${TABLE_NAME}` (`locationId`)"
}
],
"foreignKeys": [
{
"table": "weather_locations",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"locationId"
],
"referencedColumns": [
"id"
]
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '41f3af0cd4a758a20290098071993b9c')"
]
}
}
+133 -4
View File
@@ -6,9 +6,9 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<application
android:name=".WeatherMasterApplication"
@@ -31,7 +31,13 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".widgets.config.WidgetConfigActivity"
android:theme="@style/Theme.WeatherMaster"
android:exported="true" />
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
@@ -54,10 +60,14 @@
tools:node="remove" />
</provider>
<receiver
android:name=".feature.notifications.scheduled.ScheduledNotification"
android:enabled="true" />
<!--WIDGETS-->
<receiver
android:name=".widgets.weather.WeatherWidgetReceiver"
android:label="Weather"
android:label="Weather 1"
android:exported="true">
<intent-filter>
@@ -71,7 +81,7 @@
<receiver
android:name=".widgets.pill.WidgetPillReceiver"
android:label="Weather"
android:label="Pill"
android:exported="true">
<intent-filter>
@@ -85,7 +95,7 @@
<receiver
android:name=".widgets.summary.SummaryWidgetReceiver"
android:label="Summary"
android:label="Day Summary"
android:exported="true">
<intent-filter>
@@ -96,6 +106,125 @@
android:name="android.appwidget.provider"
android:resource="@xml/summary_widget_info" />
</receiver>
<receiver
android:name=".widgets.weatherhorizontal.WeatherHorizontalWidgetReceiver"
android:label="Weather 2"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/weather_widget_horizontal_info" />
</receiver>
<receiver
android:name=".widgets.glance.GlanceWidgetReceiver"
android:label="Glance"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/glance_widget_info" />
</receiver>
<receiver
android:name=".widgets.weather3.Weather3WidgetReceiver"
android:label="Weather 3"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/weather3_widget_info" />
</receiver>
<receiver
android:name=".widgets.weather4.Weather4WidgerReceiver"
android:label="Weather 4"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/weather4_widget_info" />
</receiver>
<receiver
android:name=".widgets.hourly.WidgetHourlyReceiver"
android:label="Hourly"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/hourly_widget_info" />
</receiver>
<receiver
android:name=".widgets.uvindex.UvIndexWidgetReceiver"
android:label="UV index"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/uv_index_widget_info" />
</receiver>
<receiver
android:name=".widgets.weather5.Weather5WidgetReceiver"
android:label="Weather 5"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/weather5_widget_info" />
</receiver>
<receiver
android:name=".widgets.froggy.FroggyWidgetReceiver"
android:label="Froggy"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/froggy_widget_info" />
</receiver>
</application>
<queries>
<intent>
<action android:name="nodomain.freeyourgadget.gadgetbridge.ACTION_GENERIC_WEATHER" />
</intent>
</queries>
</manifest>
+1
View File
@@ -0,0 +1 @@
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"featurecla":"Admin-0 country","scalerank":1,"labelrank":2,"sovereignt":"China","sov_a3":"CH1","adm0_dif":1,"level":2,"type":"Country","tlc":"1","admin":"China","adm0_a3":"CHN","geou_dif":0,"geounit":"China","gu_a3":"CHN","su_dif":0,"subunit":"China","su_a3":"CHN","brk_diff":0,"name":"China","name_long":"China","brk_a3":"CHN","brk_name":"China","brk_group":null,"abbrev":"China","postal":"CN","formal_en":"People's Republic of China","formal_fr":null,"name_ciawf":"China","note_adm0":null,"note_brk":null,"name_sort":"China","name_alt":null,"mapcolor7":4,"mapcolor8":4,"mapcolor9":4,"mapcolor13":3,"pop_est":1397715000,"pop_rank":18,"pop_year":2019,"gdp_md":14342903,"gdp_year":2019,"economy":"3. Emerging region: BRIC","income_grp":"3. Upper middle income","fips_10":"CH","iso_a2":"CN","iso_a2_eh":"CN","iso_a3":"CHN","iso_a3_eh":"CHN","iso_n3":"156","iso_n3_eh":"156","un_a3":"156","wb_a2":"CN","wb_a3":"CHN","woe_id":23424781,"woe_id_eh":23424781,"woe_note":"Exact WOE match as country","adm0_iso":"CHN","adm0_diff":null,"adm0_tlc":"CHN","adm0_a3_us":"CHN","adm0_a3_fr":"CHN","adm0_a3_ru":"CHN","adm0_a3_es":"CHN","adm0_a3_cn":"CHN","adm0_a3_tw":"TWN","adm0_a3_in":"CHN","adm0_a3_np":"CHN","adm0_a3_pk":"CHN","adm0_a3_de":"CHN","adm0_a3_gb":"CHN","adm0_a3_br":"CHN","adm0_a3_il":"CHN","adm0_a3_ps":"CHN","adm0_a3_sa":"CHN","adm0_a3_eg":"CHN","adm0_a3_ma":"CHN","adm0_a3_pt":"CHN","adm0_a3_ar":"CHN","adm0_a3_jp":"CHN","adm0_a3_ko":"CHN","adm0_a3_vn":"CHN","adm0_a3_tr":"CHN","adm0_a3_id":"CHN","adm0_a3_pl":"CHN","adm0_a3_gr":"CHN","adm0_a3_it":"CHN","adm0_a3_nl":"CHN","adm0_a3_se":"CHN","adm0_a3_bd":"CHN","adm0_a3_ua":"CHN","adm0_a3_un":-99,"adm0_a3_wb":-99,"continent":"Asia","region_un":"Asia","subregion":"Eastern Asia","region_wb":"East Asia & Pacific","name_len":5,"long_len":5,"abbrev_len":5,"tiny":-99,"homepart":1,"min_zoom":0,"min_label":1.7,"max_label":5.7,"label_x":106.337289,"label_y":32.498178,"ne_id":1159320471,"wikidataid":"Q148","name_ar":"الصين","name_bn":"গণচীন","name_de":"Volksrepublik China","name_en":"People's Republic of China","name_es":"China","name_fa":"جمهوری خلق چین","name_fr":"République populaire de Chine","name_el":"Λαϊκή Δημοκρατία της Κίνας","name_he":"הרפובליקה העממית של סין","name_hi":"चीनी जनवादी गणराज्य","name_hu":"Kína","name_id":"Republik Rakyat Tiongkok","name_it":"Cina","name_ja":"中華人民共和国","name_ko":"중화인민공화국","name_nl":"Volksrepubliek China","name_pl":"Chińska Republika Ludowa","name_pt":"China","name_ru":"Китайская Народная Республика","name_sv":"Kina","name_tr":"Çin Halk Cumhuriyeti","name_uk":"Китайська Народна Республіка","name_ur":"عوامی جمہوریہ چین","name_vi":"Trung Quốc","name_zh":"中华人民共和国","name_zht":"中華人民共和國","fclass_iso":"Admin-0 country","tlc_diff":null,"fclass_tlc":"Admin-0 country","fclass_us":null,"fclass_fr":null,"fclass_ru":null,"fclass_es":null,"fclass_cn":null,"fclass_tw":"Unrecognized","fclass_in":null,"fclass_np":null,"fclass_pk":null,"fclass_de":null,"fclass_gb":null,"fclass_br":null,"fclass_il":null,"fclass_ps":null,"fclass_sa":null,"fclass_eg":null,"fclass_ma":null,"fclass_pt":null,"fclass_ar":null,"fclass_jp":null,"fclass_ko":null,"fclass_vn":null,"fclass_tr":null,"fclass_id":null,"fclass_pl":null,"fclass_gr":null,"fclass_it":null,"fclass_nl":null,"fclass_se":null,"fclass_bd":null,"fclass_ua":null,"filename":"CHN.geojson"},"geometry":{"type":"MultiPolygon","coordinates":[[[[109.47520958866365,18.197700913968575],[108.65520796105616,18.507681993071387],[108.62621748254044,19.367887885001906],[109.11905561730804,19.821038519769345],[110.21159874882281,20.101253973872033],[110.78655073450221,20.077534491450052],[111.01005130416458,19.69592987719072],[110.57064660038677,19.25587921800927],[110.33918786015147,18.678395087147592],[109.47520958866365,18.197700913968575]]],[[[80.2599902688853,42.34999929459906],[80.1801501809943,42.92006785742694],[80.86620649610126,43.18036204688101],[79.96610639844141,44.91751699480463],[81.9470707539181,45.31702749285312],[82.45892581576906,45.539649563166506],[83.18048383986047,47.33003123635086],[85.16429039911324,47.0009557155161],[85.72048383987067,47.452969468773105],[85.7682328633083,48.45575063739699],[86.59877648310336,48.549181626980626],[87.35997033076265,49.21498078062912],[87.75126427607671,49.297197984405486],[88.01383222855173,48.599462795600616],[88.85429772334676,48.069081732772965],[90.28082563676392,47.69354909930793],[90.97080936072501,46.88814606382293],[90.58576826371828,45.71971609148753],[90.9455395853343,45.28607330991028],[92.13389082231822,45.11507599545646],[93.4807336771413,44.975472113619965],[94.68892866412533,44.35233185482842],[95.30687544147153,44.24133087826547],[95.76245486855669,43.319449164394605],[96.Line truncated
@@ -1,37 +1,74 @@
package com.pranshulgg.weather_master_app
import android.content.Context
import android.graphics.Color
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.SystemBarStyle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.pranshulgg.weather_master_app.core.prefs.AppPrefs
import com.pranshulgg.weather_master_app.core.prefs.AppPrefs.initPrefs
import com.pranshulgg.weather_master_app.core.prefs.helper.PreferencesHelper
import com.pranshulgg.weather_master_app.core.ui.theme.isThemeDark
import com.pranshulgg.weather_master_app.data.provider.devicelocation.GetDeviceLocation
import com.pranshulgg.weather_master_app.data.store.InitializationStoreState
import com.pranshulgg.weather_master_app.data.worker.WeatherWorker
import com.pranshulgg.weather_master_app.feature.shared.WeatherViewModel
import dagger.hilt.android.AndroidEntryPoint
import java.util.concurrent.TimeUnit
import com.pranshulgg.weather_master_app.data.store.InitializationStore
import javax.inject.Inject
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val viewModel: WeatherViewModel by viewModels()
@Inject
lateinit var initializationStore: InitializationStore
override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen()
val startTime = System.currentTimeMillis()
splashScreen.setKeepOnScreenCondition {
val initialized = viewModel.uiState.value.isInitialized
val initialized = initializationStore.data.value.isInitialized
val timedOut = System.currentTimeMillis() - startTime > 5000
!initialized && !timedOut
}
initPrefs(this)
super.onCreate(savedInstanceState)
enableEdgeToEdge()
val theme = PreferencesHelper.getString("app_theme") ?: "Dark"
val isDark = resolveThemeDark(
theme,
resources.configuration.uiMode and
android.content.res.Configuration.UI_MODE_NIGHT_MASK ==
android.content.res.Configuration.UI_MODE_NIGHT_YES
)
enableEdgeToEdge(
navigationBarStyle = if (isDark) {
SystemBarStyle.dark(Color.TRANSPARENT)
} else {
SystemBarStyle.light(
Color.TRANSPARENT, Color.TRANSPARENT
)
}
)
setContent {
WeatherMasterApp()
}
}
val locationHelper = GetDeviceLocation()
@@ -40,6 +77,19 @@ class MainActivity : AppCompatActivity() {
locationHelper.stopUpdates()
}
private fun resolveThemeDark(
appTheme: String,
systemDark: Boolean
): Boolean {
return when (appTheme) {
"Dark" -> true
"Light" -> false
"System" -> systemDark
else -> systemDark
}
}
}
@@ -2,7 +2,6 @@ package com.pranshulgg.weather_master_app
import android.annotation.SuppressLint
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult
import androidx.compose.runtime.Composable
@@ -40,7 +39,7 @@ fun WeatherMasterApp() {
),
actionLabel = if (event.actionLabel != null) context.getString(event.actionLabel) else null,
withDismissAction = event.actionLabel == null,
duration = SnackbarDuration.Short
duration = event.duration
)
if (result == SnackbarResult.ActionPerformed) {
@@ -71,4 +70,5 @@ fun WeatherMasterApp() {
}
}
}
@@ -3,18 +3,13 @@ package com.pranshulgg.weather_master_app
import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import androidx.hilt.work.HiltWorkerFactory
import androidx.lifecycle.ProcessLifecycleOwner
import dagger.hilt.android.HiltAndroidApp
import androidx.work.Configuration
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.pranshulgg.weather_master_app.data.worker.AppVisibility
import com.pranshulgg.weather_master_app.data.worker.WeatherWorker
import com.pranshulgg.weather_master_app.data.worker.notification.WeatherNotificationConfig
import java.util.concurrent.TimeUnit
import com.pranshulgg.weather_master_app.data.worker.notification.BackgroundUpdateNotificationConfig
import com.pranshulgg.weather_master_app.feature.notifications.NotificationChannels
import dagger.hilt.android.HiltAndroidApp
import javax.inject.Inject
@HiltAndroidApp
@@ -40,17 +35,7 @@ class WeatherMasterApplication : Application(), Configuration.Provider {
.lifecycle
.addObserver(visibilityTracker)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
WeatherNotificationConfig.CHANNEL_ID,
"WeatherMaster Updates",
NotificationManager.IMPORTANCE_HIGH
)
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(channel)
}
NotificationChannels.createAll(this)
}
@@ -1,41 +1,46 @@
package com.pranshulgg.weather_master_app.core.di
import android.content.Context
import com.pranshulgg.weather_master_app.core.managers.ExternalManager
import com.pranshulgg.weather_master_app.core.managers.LocationManager
import com.pranshulgg.weather_master_app.core.managers.SourceManager
import com.pranshulgg.weather_master_app.core.managers.WeatherBlocksManager
import com.pranshulgg.weather_master_app.core.managers.WeatherManager
import com.pranshulgg.weather_master_app.core.managers.WeatherUnitsManager
import com.pranshulgg.weather_master_app.core.managers.requests.PendingRequests
import com.pranshulgg.weather_master_app.core.network.github.GithubApi
import com.pranshulgg.weather_master_app.core.network.github.GithubRepository
import com.pranshulgg.weather_master_app.core.network.sources.address.nominatim.NominatimApi
import com.pranshulgg.weather_master_app.core.network.sources.address.nominatim.json.NominatimRepository
import com.pranshulgg.weather_master_app.core.network.sources.airquality.openmeteo.OpenMeteoAqiApi
import com.pranshulgg.weather_master_app.core.network.sources.airquality.openmeteo.OpenMeteoAqiRepository
import com.pranshulgg.weather_master_app.core.network.sources.search.geonames.GeoNamesSearchApi
import com.pranshulgg.weather_master_app.core.network.sources.search.geonames.GeoNamesSearchRepository
import com.pranshulgg.weather_master_app.core.network.sources.search.geonames.timezone.GeoNamesTimezoneApi
import com.pranshulgg.weather_master_app.core.network.sources.search.geonames.GeoNamesTimezoneRepository
import com.pranshulgg.weather_master_app.core.network.sources.search.openmeteo.OpenMeteoSearchApi
import com.pranshulgg.weather_master_app.core.network.sources.search.openmeteo.OpenMeteoSearchRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.metnorway.MetNorwayApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.metnorway.MetNorwayRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.nws.NwsApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.nws.NwsRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.openmeteo.OpenMeteoApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.openmeteo.OpenMeteoRepository
import com.pranshulgg.weather_master_app.data.local.WeatherMasterDatabase
import com.pranshulgg.weather_master_app.data.local.dao.airquality.AirQualityDao
import com.pranshulgg.weather_master_app.data.local.dao.location.LocationsDao
import com.pranshulgg.weather_master_app.data.local.dao.alerts.AlertsDao
import com.pranshulgg.weather_master_app.data.local.dao.github.GithubDao
import com.pranshulgg.weather_master_app.data.local.dao.location.LocationKeysDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherContextDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.ApiKeysDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherBlocksDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherUnitsDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.nws.NwsDao
import com.pranshulgg.weather_master_app.data.repository.LocationsRepository
import com.pranshulgg.weather_master_app.data.provider.devicelocation.ChinaOfflineGeocoder
import com.pranshulgg.weather_master_app.data.repository.ApiKeysRepository
import com.pranshulgg.weather_master_app.data.repository.WeatherContextRepository
import com.pranshulgg.weather_master_app.data.repository.WeatherBlocksRepository
import com.pranshulgg.weather_master_app.data.repository.WeatherDataReconcilerRepository
import com.pranshulgg.weather_master_app.data.repository.WeatherUnitsRepository
import com.pranshulgg.weather_master_app.data.repository.data.SourceDataRepository
import com.pranshulgg.weather_master_app.data.store.InitializationStore
import com.pranshulgg.weather_master_app.data.store.LocationStore
import com.pranshulgg.weather_master_app.data.store.WeatherBlocksStore
import com.pranshulgg.weather_master_app.data.store.WeatherStore
import com.pranshulgg.weather_master_app.data.store.WeatherUnitsStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
import dagger.Lazy
import javax.inject.Provider
@Module
@InstallIn(SingletonComponent::class)
@@ -51,12 +56,23 @@ object AppModule {
@Provides
@Singleton
fun provideLocationsRepository(
dao: LocationsDao,
fun provideWeatherContextRepository(
dao: WeatherContextDao,
airQualityDao: AirQualityDao,
nominatimRepository: NominatimRepository,
@ApplicationContext context: Context
): LocationsRepository = LocationsRepository(dao, airQualityDao, context, nominatimRepository)
@ApplicationContext context: Context,
alertsDao: AlertsDao,
sourceManager: SourceManager,
chinaOfflineGeocoder: ChinaOfflineGeocoder
): WeatherContextRepository = WeatherContextRepository(
dao,
airQualityDao,
context,
nominatimRepository,
alertsDao,
sourceManager,
chinaOfflineGeocoder
)
@Provides
@@ -71,22 +87,101 @@ object AppModule {
): WeatherBlocksRepository =
WeatherBlocksRepository(weatherBlocksDao)
@Provides
@Singleton
fun provideWeatherDataReconcilerRepository(
nwsDao: NwsDao,
locationsDao: LocationsDao
): WeatherDataReconcilerRepository = WeatherDataReconcilerRepository(nwsDao, locationsDao)
@Provides
@Singleton
fun provideGithubRepository(
api: GithubApi
): GithubRepository = GithubRepository(api)
api: GithubApi,
dao: GithubDao
): GithubRepository = GithubRepository(api, dao)
@Provides
@Singleton
fun provideNominatimRepository(api: NominatimApi): NominatimRepository =
NominatimRepository(api)
@Provides
@Singleton
fun provideApiKeysRepository(dao: ApiKeysDao): ApiKeysRepository = ApiKeysRepository(dao)
@Provides
@Singleton
fun provideSourceManager(
nwsDao: NwsDao,
locationKeysDao: LocationKeysDao,
airQualityDao: AirQualityDao,
alertsDao: AlertsDao,
weatherContextRepository: Provider<WeatherContextRepository>,
pendingRequests: PendingRequests,
locationStore: LocationStore
): SourceManager {
return SourceManager(
nwsDao,
locationKeysDao,
airQualityDao,
alertsDao,
weatherContextRepository,
pendingRequests,
locationStore
)
}
@Provides
@Singleton
fun provideLocationManager(
weatherContextRepository: WeatherContextRepository,
locationStore: LocationStore,
initializationStore: InitializationStore,
pendingRequests: PendingRequests
): LocationManager {
return LocationManager(
weatherContextRepository,
locationStore,
initializationStore,
pendingRequests
)
}
@Provides
@Singleton
fun provideWeatherBlocksManager(
weatherBlocksRepository: WeatherBlocksRepository,
weatherBlocksStore: WeatherBlocksStore
): WeatherBlocksManager {
return WeatherBlocksManager(
weatherBlocksRepository,
weatherBlocksStore
)
}
@Provides
@Singleton
fun provideWeatherManager(
weatherContextRepository: WeatherContextRepository,
sourceDataRepository: SourceDataRepository,
weatherStore: WeatherStore,
locationStore: LocationStore,
initializationStore: InitializationStore,
externalManager: ExternalManager
): WeatherManager {
return WeatherManager(
weatherContextRepository,
sourceDataRepository,
weatherStore,
locationStore,
initializationStore,
externalManager
)
}
@Provides
@Singleton
fun provideWeatherUnitsManager(
weatherUnitsStore: WeatherUnitsStore,
weatherUnitsRepository: WeatherUnitsRepository
): WeatherUnitsManager {
return WeatherUnitsManager(
weatherUnitsStore,
weatherUnitsRepository
)
}
}
@@ -1,6 +1,7 @@
package com.pranshulgg.weather_master_app.core.di.db
import com.pranshulgg.weather_master_app.data.local.WeatherMasterDatabase
import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherContextDao
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@@ -11,8 +12,8 @@ import dagger.hilt.components.SingletonComponent
@InstallIn(SingletonComponent::class)
object DaoModule {
@Provides
fun provideLocationDao(db: WeatherMasterDatabase) =
db.locationsDao()
fun provideWeatherContextDao(db: WeatherMasterDatabase) =
db.weatherContextDao()
@Provides
fun provideWeatherDataDao(db: WeatherMasterDatabase) =
@@ -31,4 +32,16 @@ object DaoModule {
@Provides
fun provideNwsDao(db: WeatherMasterDatabase) = db.nwsDao()
@Provides
fun provideGithubDao(db: WeatherMasterDatabase) = db.githubDao()
@Provides
fun provideLocationKeysDao(db: WeatherMasterDatabase) = db.locationKeysDao()
@Provides
fun provideAlertsDao(db: WeatherMasterDatabase) = db.alertsDao()
@Provides
fun provideApiKeysDao(db: WeatherMasterDatabase) = db.apiKeysDao()
}
@@ -2,15 +2,42 @@ package com.pranshulgg.weather_master_app.core.di.network
import com.pranshulgg.weather_master_app.core.network.github.GithubApi
import com.pranshulgg.weather_master_app.core.network.sources.address.nominatim.NominatimApi
import com.pranshulgg.weather_master_app.core.network.sources.airquality.openmeteo.OpenMeteoAqiApi
import com.pranshulgg.weather_master_app.core.network.sources.airquality.moenv.MoenvApi
import com.pranshulgg.weather_master_app.core.network.sources.alerts.fpas.FpasApi
import com.pranshulgg.weather_master_app.core.network.sources.alerts.weatherapi.AlertsWeatherApi
import com.pranshulgg.weather_master_app.core.network.sources.alerts.wmosevereweather.WmoSevereWeatherApi
import com.pranshulgg.weather_master_app.core.network.sources.search.accu.AccuSearchApi
import com.pranshulgg.weather_master_app.core.network.sources.search.geonames.GeoNamesSearchApi
import com.pranshulgg.weather_master_app.core.network.sources.search.geonames.timezone.GeoNamesTimezoneApi
import com.pranshulgg.weather_master_app.core.network.sources.search.openmeteo.OpenMeteoSearchApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.accu.AccuApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.aemet.AemetApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.bmkg.BmkgApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.china.ChinaApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.cwa.CwaApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.jma.JmaApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.dwd.DwdApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.eccc.EcccApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.fmi.FmiApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.gismeteo.GismeteoApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.imd.ImdApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.IbgeApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.InmetAvisosApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.InmetForecastApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.InmetObservationApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.ipma.IpmaApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.kmi.KmiApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.meteoam.MeteoamApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.meteofrance.MeteoFranceApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.metnorway.MetNorwayApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.metoffice.MetOfficeApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.mgm.MgmApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.nws.NwsApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.openmeteo.OpenMeteoApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.openmeteo.airquality.OpenMeteoAqiApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.openweather.OpenWeatherApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.openweather.OpenWeatherOneCallApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.pirateweather.PirateWeatherApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.smhi.SmhiApi
import dagger.Module
import dagger.Provides
@@ -69,4 +96,113 @@ object ApiModule {
@Provides
@Singleton
fun provideMeteoFranceApi(): MeteoFranceApi = MeteoFranceApi.create()
}
@Provides
@Singleton
fun provideEcccApi(): EcccApi = EcccApi.create()
@Provides
@Singleton
fun provideFmiApi(): FmiApi = FmiApi.create()
@Provides
@Singleton
fun provideChinaApi(): ChinaApi = ChinaApi.create()
@Provides
@Singleton
fun provideBmkgApi(): BmkgApi = BmkgApi.create()
@Provides
@Singleton
fun provideAccuApi(): AccuApi = AccuApi.create()
@Provides
@Singleton
fun provideMeteoamApi(): MeteoamApi = MeteoamApi.create()
@Provides
@Singleton
fun provideAlertsWeatherApi(): AlertsWeatherApi = AlertsWeatherApi.create()
@Provides
@Singleton
fun provideIpmaApi(): IpmaApi = IpmaApi.create()
@Provides
@Singleton
fun provideAccuSearchApi(): AccuSearchApi = AccuSearchApi.create()
@Provides
@Singleton
fun provideWmoSevereWeatherAlertsApi(): WmoSevereWeatherApi = WmoSevereWeatherApi.create()
@Provides
@Singleton
fun provideFpasAlertsApi(): FpasApi = FpasApi.create()
@Provides
@Singleton
fun provideGismeteoApi(): GismeteoApi = GismeteoApi.create()
@Provides
@Singleton
fun provideMetOfficeApi(): MetOfficeApi = MetOfficeApi.create()
@Provides
@Singleton
fun provideAemetApi(): AemetApi = AemetApi.create()
@Provides
@Singleton
fun provideImdApi(): ImdApi = ImdApi.create()
@Provides
@Singleton
fun providePirateWeatherApi(): PirateWeatherApi = PirateWeatherApi.create()
@Provides
@Singleton
fun provideCwaApi(): CwaApi = CwaApi.create()
@Provides
@Singleton
fun provideJmaApi(): JmaApi = JmaApi.create()
@Provides
@Singleton
fun provideInmetForecastApi(): InmetForecastApi = InmetForecastApi.create()
@Provides
@Singleton
fun provideInmetAvisosApi(): InmetAvisosApi = InmetAvisosApi.create()
@Provides
@Singleton
fun provideInmetObservationApi(): InmetObservationApi = InmetObservationApi.create()
@Provides
@Singleton
fun provideIbgeApi(): IbgeApi = IbgeApi.create()
@Provides
@Singleton
fun provideOpenWeatherApi(): OpenWeatherApi = OpenWeatherApi.create()
@Provides
@Singleton
fun provideOpenWeatherOneCallApi(): OpenWeatherOneCallApi = OpenWeatherOneCallApi.create()
@Provides
@Singleton
fun provideMgmApi(): MgmApi = MgmApi.create()
@Provides
@Singleton
fun provideKmiApi(): KmiApi = KmiApi.create()
@Provides
@Singleton
fun provideMoenvApi(): MoenvApi = MoenvApi.create()
}
@@ -1,5 +1,7 @@
package com.pranshulgg.weather_master_app.core.di.search
import com.pranshulgg.weather_master_app.core.network.sources.search.accu.AccuSearchApi
import com.pranshulgg.weather_master_app.core.network.sources.search.accu.AccuSearchRepository
import com.pranshulgg.weather_master_app.core.network.sources.search.geonames.GeoNamesSearchApi
import com.pranshulgg.weather_master_app.core.network.sources.search.geonames.GeoNamesSearchRepository
import com.pranshulgg.weather_master_app.core.network.sources.search.geonames.GeoNamesTimezoneRepository
@@ -32,4 +34,10 @@ object SearchRepositoryModule {
fun provideGeoNamesTimezoneRepository(api: GeoNamesTimezoneApi): GeoNamesTimezoneRepository =
GeoNamesTimezoneRepository(api)
@Provides
@Singleton
fun provideAccuSearchRepository(
api: AccuSearchApi
): AccuSearchRepository = AccuSearchRepository(api)
}
@@ -1,21 +1,64 @@
package com.pranshulgg.weather_master_app.core.di.weather
import com.pranshulgg.weather_master_app.core.network.sources.airquality.openmeteo.OpenMeteoAqiApi
import com.pranshulgg.weather_master_app.core.network.sources.airquality.openmeteo.OpenMeteoAqiRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.openmeteo.airquality.OpenMeteoAqiApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.accu.AccuApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.accu.AccuRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.aemet.AemetApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.aemet.AemetRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.bmkg.BmkgApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.bmkg.BmkgRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.china.ChinaApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.china.ChinaRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.cwa.CwaApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.cwa.CwaRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.dwd.DwdApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.dwd.DwdRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.eccc.EcccApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.eccc.EcccRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.fmi.FmiApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.fmi.FmiRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.gismeteo.GismeteoApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.gismeteo.GismeteoRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.meteofor.MeteoforRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.imd.ImdApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.imd.ImdRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.IbgeApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.InmetAvisosApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.InmetForecastApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.InmetObservationApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.InmetRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.jma.JmaApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.jma.JmaRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.ipma.IpmaApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.ipma.IpmaRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.kmi.KmiApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.kmi.KmiRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.meteoam.MeteoamApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.meteoam.MeteoamRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.meteofrance.MeteoFranceApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.meteofrance.MeteoFranceRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.metnorway.MetNorwayApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.metnorway.MetNorwayRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.metoffice.MetOfficeApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.metoffice.MetOfficeRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.mgm.MgmApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.mgm.MgmRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.nws.NwsApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.nws.NwsRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.openmeteo.OpenMeteoApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.openmeteo.OpenMeteoRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.openweather.OpenWeatherApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.openweather.OpenWeatherOneCallApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.openweather.OpenWeatherRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.pirateweather.PirateWeatherApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.pirateweather.PirateWeatherRepository
import com.pranshulgg.weather_master_app.core.network.sources.weather.smhi.SmhiApi
import com.pranshulgg.weather_master_app.core.network.sources.weather.smhi.SmhiRepository
import com.pranshulgg.weather_master_app.data.local.dao.airquality.AirQualityDao
import com.pranshulgg.weather_master_app.data.local.dao.location.LocationsDao
import com.pranshulgg.weather_master_app.data.local.dao.alerts.AlertsDao
import com.pranshulgg.weather_master_app.data.local.dao.location.LocationKeysDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherContextDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.ApiKeysDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.nws.NwsDao
import dagger.Module
@@ -30,32 +73,28 @@ object WeatherRepositoryModule {
@Provides
@Singleton
fun provideOpenMeteoRepository(
dao: LocationsDao,
dao: WeatherContextDao,
api: OpenMeteoApi,
weatherDao: WeatherDao
): OpenMeteoRepository = OpenMeteoRepository(dao, weatherDao, api)
weatherDao: WeatherDao,
airQualityDao: AirQualityDao,
airQualityApi: OpenMeteoAqiApi
): OpenMeteoRepository = OpenMeteoRepository(dao, weatherDao, api, airQualityApi, airQualityDao)
@Provides
@Singleton
fun provideOpenMeteoAqiRepository(
api: OpenMeteoAqiApi,
dao: AirQualityDao
): OpenMeteoAqiRepository =
OpenMeteoAqiRepository(api, dao)
@Provides
@Singleton
fun provideNwsRepository(
api: NwsApi,
dao: LocationsDao,
dao: WeatherContextDao,
weatherDao: WeatherDao,
nwsDao: NwsDao
): NwsRepository = NwsRepository(dao, weatherDao, nwsDao, api)
nwsDao: NwsDao,
alertsDao: AlertsDao
): NwsRepository = NwsRepository(dao, weatherDao, nwsDao, api, alertsDao)
@Provides
@Singleton
fun provideMetNorwayRepository(
dao: LocationsDao,
dao: WeatherContextDao,
api: MetNorwayApi,
weatherDao: WeatherDao
): MetNorwayRepository = MetNorwayRepository(dao, weatherDao, api)
@@ -63,7 +102,7 @@ object WeatherRepositoryModule {
@Provides
@Singleton
fun provideSmhiRepository(
dao: LocationsDao,
dao: WeatherContextDao,
api: SmhiApi,
weatherDao: WeatherDao
): SmhiRepository = SmhiRepository(dao, weatherDao, api)
@@ -71,7 +110,7 @@ object WeatherRepositoryModule {
@Provides
@Singleton
fun provideDwdRepository(
dao: LocationsDao,
dao: WeatherContextDao,
api: DwdApi,
weatherDao: WeatherDao
): DwdRepository = DwdRepository(dao, weatherDao, api)
@@ -79,8 +118,211 @@ object WeatherRepositoryModule {
@Provides
@Singleton
fun provideMeteoFranceRepository(
dao: LocationsDao,
dao: WeatherContextDao,
api: MeteoFranceApi,
weatherDao: WeatherDao
): MeteoFranceRepository = MeteoFranceRepository(dao, weatherDao, api)
@Provides
@Singleton
fun provideEcccRepository(
dao: WeatherContextDao,
api: EcccApi,
weatherDao: WeatherDao
): EcccRepository = EcccRepository(dao, weatherDao, api)
@Provides
@Singleton
fun provideFmiRepository(
dao: WeatherContextDao,
api: FmiApi,
weatherDao: WeatherDao
): FmiRepository = FmiRepository(dao, weatherDao, api)
@Provides
@Singleton
fun provideChinaRepository(
dao: WeatherContextDao,
api: ChinaApi,
weatherDao: WeatherDao
): ChinaRepository = ChinaRepository(dao, weatherDao, api)
@Provides
@Singleton
fun provideBmkgRepository(
dao: WeatherContextDao,
api: BmkgApi,
weatherDao: WeatherDao
): BmkgRepository = BmkgRepository(dao, weatherDao, api)
@Provides
@Singleton
fun provideAccuRepository(
dao: WeatherContextDao,
api: AccuApi,
weatherDao: WeatherDao,
locationKeysDao: LocationKeysDao,
airQualityDao: AirQualityDao,
alertsDao: AlertsDao,
weatherContextDao: WeatherContextDao
): AccuRepository = AccuRepository(
dao,
weatherDao,
api,
locationKeysDao,
airQualityDao,
weatherContextDao,
alertsDao
)
@Provides
@Singleton
fun provideMeteoamRepository(
dao: WeatherContextDao,
api: MeteoamApi,
weatherDao: WeatherDao
): MeteoamRepository = MeteoamRepository(dao, weatherDao, api)
@Provides
@Singleton
fun provideIpmaRepository(
dao: WeatherContextDao,
api: IpmaApi,
weatherDao: WeatherDao,
locationKeysDao: LocationKeysDao
): IpmaRepository = IpmaRepository(dao, weatherDao, api, locationKeysDao)
@Provides
@Singleton
fun provideGismeteoRepository(
dao: WeatherContextDao,
api: GismeteoApi,
weatherDao: WeatherDao,
locationKeysDao: LocationKeysDao
): GismeteoRepository = GismeteoRepository(dao, weatherDao, api, locationKeysDao)
@Provides
@Singleton
fun provideMeteoforRepository(
dao: WeatherContextDao,
api: GismeteoApi,
weatherDao: WeatherDao,
locationKeysDao: LocationKeysDao
): MeteoforRepository = MeteoforRepository(dao, weatherDao, api, locationKeysDao)
@Provides
@Singleton
fun provideMetOfficeRepository(
dao: WeatherContextDao,
api: MetOfficeApi,
weatherDao: WeatherDao,
apiKeysDao: ApiKeysDao
): MetOfficeRepository = MetOfficeRepository(dao, weatherDao, api, apiKeysDao)
@Provides
@Singleton
fun provideAemetRepository(
dao: WeatherContextDao,
api: AemetApi,
weatherDao: WeatherDao,
apiKeysDao: ApiKeysDao,
locationKeysDao: LocationKeysDao
): AemetRepository = AemetRepository(dao, weatherDao, api, apiKeysDao, locationKeysDao)
@Provides
@Singleton
fun provideImdRepository(
dao: WeatherContextDao,
weatherDao: WeatherDao,
api: ImdApi
): ImdRepository = ImdRepository(dao, weatherDao, api)
@Provides
@Singleton
fun providePirateWeatherRepository(
dao: WeatherContextDao,
api: PirateWeatherApi,
weatherDao: WeatherDao,
apiKeysDao: ApiKeysDao,
alertsDao: AlertsDao
): PirateWeatherRepository =
PirateWeatherRepository(dao, weatherDao, api, apiKeysDao, alertsDao)
@Provides
@Singleton
fun provideCwaRepository(
dao: WeatherContextDao,
api: CwaApi,
weatherDao: WeatherDao,
apiKeysDao: ApiKeysDao,
locationKeysDao: LocationKeysDao
): CwaRepository = CwaRepository(dao, weatherDao, api, apiKeysDao, locationKeysDao)
@Provides
@Singleton
fun provideJmaRepository(
dao: WeatherContextDao,
weatherDao: WeatherDao,
api: JmaApi,
locationKeysDao: LocationKeysDao,
alertsDao: AlertsDao
): JmaRepository = JmaRepository(dao, weatherDao, api, locationKeysDao, alertsDao)
@Provides
@Singleton
fun provideInmetRepository(
dao: WeatherContextDao,
weatherDao: WeatherDao,
forecastApi: InmetForecastApi,
observationApi: InmetObservationApi,
ibgeApi: IbgeApi,
avisosApi: InmetAvisosApi,
locationKeysDao: LocationKeysDao,
alertsDao: AlertsDao
): InmetRepository = InmetRepository(
dao,
weatherDao,
forecastApi,
observationApi,
ibgeApi,
avisosApi,
locationKeysDao,
alertsDao
)
@Provides
@Singleton
fun provideOpenWeatherRepository(
dao: WeatherContextDao,
weatherDao: WeatherDao,
api: OpenWeatherApi,
airQualityDao: AirQualityDao,
apiKeysDao: ApiKeysDao,
oneCallApi: OpenWeatherOneCallApi
): OpenWeatherRepository =
OpenWeatherRepository(dao, weatherDao, api, oneCallApi, airQualityDao, apiKeysDao)
@Provides
@Singleton
fun provideMgmRepository(
dao: WeatherContextDao,
weatherDao: WeatherDao,
api: MgmApi,
apiKeysDao: ApiKeysDao,
locationKeysDao: LocationKeysDao,
alertsDao: AlertsDao
): MgmRepository = MgmRepository(dao, weatherDao, api, apiKeysDao, locationKeysDao, alertsDao)
@Provides
@Singleton
fun provideKmiRepository(
dao: WeatherContextDao,
weatherDao: WeatherDao,
api: KmiApi,
apiKeysDao: ApiKeysDao,
locationKeysDao: LocationKeysDao,
alertsDao: AlertsDao
): KmiRepository = KmiRepository(dao, weatherDao, api, apiKeysDao, locationKeysDao, alertsDao)
}
@@ -0,0 +1,21 @@
package com.pranshulgg.weather_master_app.core.di.weather.airquality
import com.pranshulgg.weather_master_app.core.network.sources.airquality.moenv.MoenvApi
import com.pranshulgg.weather_master_app.core.network.sources.airquality.moenv.MoenvRepository
import com.pranshulgg.weather_master_app.data.local.dao.airquality.AirQualityDao
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object AirQualityRepositoryModule {
@Provides
@Singleton
fun provideMoenvRepository(
api: MoenvApi,
airQualityDao: AirQualityDao
): MoenvRepository = MoenvRepository(api, airQualityDao)
}
@@ -0,0 +1,48 @@
package com.pranshulgg.weather_master_app.core.di.weather.alerts
import com.pranshulgg.weather_master_app.core.network.sources.alerts.fpas.FpasApi
import com.pranshulgg.weather_master_app.core.network.sources.alerts.fpas.FpasRepository
import com.pranshulgg.weather_master_app.core.network.sources.alerts.weatherapi.AlertsWeatherApi
import com.pranshulgg.weather_master_app.core.network.sources.alerts.weatherapi.AlertsWeatherApiRepository
import com.pranshulgg.weather_master_app.core.network.sources.alerts.wmosevereweather.WmoSevereWeatherApi
import com.pranshulgg.weather_master_app.core.network.sources.alerts.wmosevereweather.WmoSevereWeatherRepository
import com.pranshulgg.weather_master_app.data.local.dao.alerts.AlertsDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherContextDao
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object AlertsRepositoryModule {
@Provides
@Singleton
fun provideWmoSevereWeatherAlertsRepository(
api: WmoSevereWeatherApi,
dao: AlertsDao,
weatherContextDao: WeatherContextDao
): WmoSevereWeatherRepository = WmoSevereWeatherRepository(api, dao, weatherContextDao)
@Provides
@Singleton
fun provideFpasAlertsRepository(
api: FpasApi,
dao: AlertsDao,
weatherContextDao: WeatherContextDao
): FpasRepository = FpasRepository(api, dao, weatherContextDao)
@Provides
@Singleton
fun provideWeatherApiAlertsRepository(
api: AlertsWeatherApi,
dao: AlertsDao,
weatherContextDao: WeatherContextDao
): AlertsWeatherApiRepository = AlertsWeatherApiRepository(api, dao, weatherContextDao)
}
@@ -0,0 +1,56 @@
package com.pranshulgg.weather_master_app.core.managers
import android.content.Context
import com.pranshulgg.weather_master_app.core.model.domain.weather.Weather
import com.pranshulgg.weather_master_app.core.model.domain.weather.WeatherUnits
import com.pranshulgg.weather_master_app.core.prefs.helper.PreferencesHelper
import com.pranshulgg.weather_master_app.data.store.LocationStore
import com.pranshulgg.weather_master_app.data.store.WeatherStore
import com.pranshulgg.weather_master_app.data.store.WeatherUnitsStore
import com.pranshulgg.weather_master_app.data.worker.WeatherBackgroundUpdateScheduler
import com.pranshulgg.weather_master_app.feature.notifications.ongoing.OnGoingNotification
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import javax.inject.Singleton
// UPDATES NOTIFICATION/WIDGETS
// APP SIDE ONLY!!!
@Singleton
class ExternalManager @Inject constructor(
private val weatherStore: WeatherStore,
private val weatherUnitsStore: WeatherUnitsStore,
@ApplicationContext val context: Context
) {
suspend fun refreshWidgets() {
val weather = weatherStore.data.value.weather
val units = weatherUnitsStore.data.value.units
if (weather != null && weather.location.isDefault) {
WeatherBackgroundUpdateScheduler.updateAllWidgets(
context = context,
data = weather,
units = units
)
}
}
fun refreshNotifications() {
val units = weatherUnitsStore.data.value.units
val weather = weatherStore.data.value.weather
val isOnGoingNotificationEnabled = PreferencesHelper.getBool(
"isOnGoingNotificationEnabled"
) ?: false
if (weather != null && weather.location.isDefault && isOnGoingNotificationEnabled) {
OnGoingNotification.update(
context = context,
weather = weather,
units = units
)
}
}
}
@@ -0,0 +1,93 @@
package com.pranshulgg.weather_master_app.core.managers
import android.util.Log
import com.pranshulgg.weather_master_app.core.managers.requests.PendingRequests
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.core.model.sources.Source
import com.pranshulgg.weather_master_app.core.model.weather.openmeteo.OpenMeteoModel
import com.pranshulgg.weather_master_app.data.repository.WeatherContextRepository
import com.pranshulgg.weather_master_app.data.store.InitializationStore
import com.pranshulgg.weather_master_app.data.store.LocationStore
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class LocationManager @Inject constructor(
private val weatherContextRepository: WeatherContextRepository,
private val locationStore: LocationStore,
private val initializationStore: InitializationStore,
private val pendingRequests: PendingRequests
) {
suspend fun initialize(scope: CoroutineScope) {
if (!initializationStore.data.value.isInitialized && locationStore.data.value.activeLocation == null) {
if (weatherContextRepository.isLocationsEmpty()) {
initializationStore.setInitialized()
}
val default = weatherContextRepository
.getDefaultLocation()
.filterNotNull()
.first()
setActive(default, skipLoading = false)
}
weatherContextRepository.getLocations().distinctUntilChanged()
.onEach { locations ->
writeLocations(
locations = locations,
isLoading = locationStore.data.value.isActiveLocationLoading
)
}.launchIn(scope)
}
private fun writeLocations(locations: List<Location>, isLoading: Boolean) {
val previous = locationStore.data.value.locations
if (previous.isNotEmpty()) {
val newLocation = locations.firstOrNull { new ->
previous.none { it.id == new.id }
}
newLocation?.let {
if (!isLoading) {
setActive(newLocation, skipLoading = false)
}
}
}
locationStore.setLocations(locations = locations)
}
suspend fun deleteLocation(id: String) {
weatherContextRepository.deleteLocation(id)
if (locationStore.data.value.activeLocation?.id == id) {
val defaultLocation = locationStore.data.value.locations
.first { it.isDefault }
setActive(defaultLocation, skipLoading = false)
}
}
fun setActive(location: Location, skipLoading: Boolean) {
if (!skipLoading) {
setActiveLoading()
}
locationStore.setActiveLocation(location)
pendingRequests.queueRequest(location)
}
fun setActiveLoading() {
locationStore.setLoading(true)
}
}
@@ -0,0 +1,186 @@
package com.pranshulgg.weather_master_app.core.managers
import com.pranshulgg.weather_master_app.core.managers.requests.PendingRequests
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.core.model.sources.Source
import com.pranshulgg.weather_master_app.core.model.weather.openmeteo.OpenMeteoModel
import com.pranshulgg.weather_master_app.data.local.dao.airquality.AirQualityDao
import com.pranshulgg.weather_master_app.data.local.dao.alerts.AlertsDao
import com.pranshulgg.weather_master_app.data.local.dao.location.LocationKeysDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.nws.NwsDao
import com.pranshulgg.weather_master_app.data.repository.WeatherContextRepository
import com.pranshulgg.weather_master_app.data.store.LocationStore
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Singleton
@Singleton
class SourceManager @Inject constructor(
private val nwsDao: NwsDao,
private val locationKeysDao: LocationKeysDao,
private val airQualityDao: AirQualityDao,
private val alertsDao: AlertsDao,
private val weatherContextRepository: Provider<WeatherContextRepository>,
private val pendingRequests: PendingRequests,
private val locationStore: LocationStore
) {
suspend fun updateSources(
location: Location,
source: Source,
airQualitySource: Source,
alertSource: Source,
openMeteoModel: OpenMeteoModel
) {
val updatedLocation = location.copy(
source = source,
airQualitySource = airQualitySource,
alertSource = alertSource,
openMeteoModel = openMeteoModel
)
val weatherContextRepository = weatherContextRepository.get()
weatherContextRepository.updateSourceForLocation(location.id, source)
weatherContextRepository.updateAirQualitySourceForLocation(location.id, airQualitySource)
weatherContextRepository.updateAlertSourceForLocation(location.id, alertSource)
weatherContextRepository.updateOpenMeteoModelForLocation(location.id, openMeteoModel)
val forceRefreshForWeather = location.source != source
|| location.openMeteoModel != openMeteoModel
val forceRefreshForAirQuality = location.airQualitySource != airQualitySource
val forceRefreshForAlerts = location.alertSource != alertSource
reconcileSourceChange(
previous = location,
updated = updatedLocation
)
if (location != updatedLocation) {
locationStore.setLoading(true)
locationStore.setActiveLocation(updatedLocation)
}
pendingRequests.queueRequest(
location = updatedLocation,
isForceRefresh = forceRefreshForWeather,
isForceRefreshForAirQuality = forceRefreshForAirQuality,
isForceRefreshForAlerts = forceRefreshForAlerts
)
}
/**
* Removes cached data that is no longer needed after a location's
* weather, air quality, or alert source changes.
*/
suspend fun reconcileSourceChange(
previous: Location,
updated: Location
) {
val locationId = previous.id
if (previous.source != updated.source) {
cleanWeatherData(
locationId = locationId,
previousSource = previous.source,
airQualitySource = updated.airQualitySource,
alertSource = updated.alertSource
)
}
if (previous.airQualitySource != updated.airQualitySource) {
cleanAirQualityData(
locationId = locationId,
currentWeatherSource = updated.source,
currentAlertSource = updated.alertSource
)
}
if (previous.alertSource != updated.alertSource) {
cleanAlertsData(
locationId = locationId,
currentWeatherSource = updated.source,
currentAirQualitySource = updated.airQualitySource
)
}
}
/**
* Removes source-specific data that is no longer valid for the location.
*/
suspend fun cleanLocationExtras(locationId: String) {
nwsDao.deleteGridPointsForLocation(locationId)
locationKeysDao.deleteCityKeyForLocation(locationId)
}
private suspend fun cleanWeatherData(
locationId: String,
previousSource: Source,
airQualitySource: Source,
alertSource: Source
) {
when (previousSource) {
Source.NWS -> {
nwsDao.deleteGridPointsForLocation(locationId)
}
Source.ACCU_WEATHER -> {
cleanAccuWeatherData(
locationId = locationId,
airQualitySource = airQualitySource,
alertSource = alertSource
)
}
else -> Unit
}
}
private suspend fun cleanAccuWeatherData(
locationId: String,
airQualitySource: Source,
alertSource: Source
) {
if (
airQualitySource != Source.ACCU_WEATHER &&
alertSource != Source.ACCU_WEATHER
) {
locationKeysDao.deleteCityKeyForLocation(locationId)
}
}
private suspend fun cleanAirQualityData(
locationId: String,
currentWeatherSource: Source,
currentAlertSource: Source
) {
airQualityDao.deleteCurrentAirQuality(locationId)
airQualityDao.deleteHourlyAirQuality(locationId)
if (
currentWeatherSource != Source.ACCU_WEATHER &&
currentAlertSource != Source.ACCU_WEATHER
) {
locationKeysDao.deleteCityKeyForLocation(locationId)
}
}
private suspend fun cleanAlertsData(
locationId: String,
currentWeatherSource: Source,
currentAirQualitySource: Source
) {
alertsDao.deleteAlertsForLocation(locationId)
if (
currentWeatherSource != Source.ACCU_WEATHER &&
currentAirQualitySource != Source.ACCU_WEATHER
) {
locationKeysDao.deleteCityKeyForLocation(locationId)
}
}
}
@@ -0,0 +1,43 @@
package com.pranshulgg.weather_master_app.core.managers
import com.pranshulgg.weather_master_app.core.model.domain.weather.WeatherBlock
import com.pranshulgg.weather_master_app.data.repository.WeatherBlocksRepository
import com.pranshulgg.weather_master_app.data.store.WeatherBlocksStore
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class WeatherBlocksManager @Inject constructor(
private val weatherBlocksRepository: WeatherBlocksRepository,
private val weatherBlocksStore: WeatherBlocksStore
) {
suspend fun initialize() {
val blocks = weatherBlocksRepository.loadBlocks()
val dailyBlocks = weatherBlocksRepository.loadBlocks(isDaily = true)
weatherBlocksStore.set(blocks)
weatherBlocksStore.setForDaily(dailyBlocks)
}
suspend fun saveBlocks(
items: List<WeatherBlock>,
isDaily: Boolean = false
) {
if (isDaily) {
weatherBlocksStore.setForDaily(items)
} else {
weatherBlocksStore.set(items)
}
weatherBlocksRepository.saveBlocks(items.map {
WeatherBlock(
type = it.type,
isHidden = false,
position = it.position,
isDaily = isDaily,
id = it.id
)
}, isDaily)
}
}
@@ -0,0 +1,202 @@
package com.pranshulgg.weather_master_app.core.managers
import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.pranshulgg.weather_master_app.core.model.domain.AppException
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.core.model.domain.toAppException
import com.pranshulgg.weather_master_app.core.model.sources.isGlobal
import com.pranshulgg.weather_master_app.core.model.sources.isSourceSupportedFor
import com.pranshulgg.weather_master_app.core.model.weather.WeatherResult
import com.pranshulgg.weather_master_app.core.model.weather.airquality.AirQualityResult
import com.pranshulgg.weather_master_app.core.model.weather.alerts.AlertResult
import com.pranshulgg.weather_master_app.data.repository.WeatherContextRepository
import com.pranshulgg.weather_master_app.data.repository.data.SourceDataRepository
import com.pranshulgg.weather_master_app.data.store.InitializationStore
import com.pranshulgg.weather_master_app.data.store.LocationStore
import com.pranshulgg.weather_master_app.data.store.WeatherStore
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.cancel
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.time.Duration.Companion.milliseconds
@Singleton
class WeatherManager @Inject constructor(
private val weatherContextRepository: WeatherContextRepository,
private val sourceDataRepository: SourceDataRepository,
private val weatherStore: WeatherStore,
private val locationStore: LocationStore,
private val initializationStore: InitializationStore,
private val externalManager: ExternalManager
) {
private val scope = CoroutineScope(SupervisorJob())
private val _errors = MutableSharedFlow<AppException>(
extraBufferCapacity = 1
)
/**
* Lets the UI know that the source for this location
* isn't supported in the region
*/
var isUnsupportedSource by mutableStateOf(false)
private set
val errors = _errors.asSharedFlow()
private var weatherJob: Job? = null
operator fun invoke(
location: Location,
isManualRefresh: Boolean = false,
isForceRefresh: Boolean = false,
isForceRefreshForAirQuality: Boolean = false,
isForceRefreshForAlerts: Boolean = false,
skipDeviceLocationCheck: Boolean = false
) {
isUnsupportedSource = false
val startTime = System.currentTimeMillis()
weatherJob?.cancel()
weatherJob = scope.launch {
try {
var effectiveLocation = location
var effectiveForceRefresh = isForceRefresh
var effectiveForceRefreshForAirQuality = isForceRefreshForAirQuality
var effectiveForceRefreshForAlerts = isForceRefreshForAlerts
if (location.isDeviceLocation && !skipDeviceLocationCheck) {
val positionChanged = try {
weatherContextRepository.updateDeviceLocationPosition()
} catch (e: AppException.CurrentLocationUnavailable) {
false
}
if (positionChanged) {
effectiveLocation = weatherContextRepository.getLocationForId(location.id)
effectiveForceRefresh = true
effectiveForceRefreshForAirQuality = true
effectiveForceRefreshForAlerts = true
locationStore.setActiveLocation(effectiveLocation)
}
}
sourceDataRepository.getData(
location = effectiveLocation,
isManualRefresh = isManualRefresh,
isForceRefresh = effectiveForceRefresh,
isForceRefreshForAirQuality = effectiveForceRefreshForAirQuality,
isForceRefreshForAlerts = effectiveForceRefreshForAlerts,
onWeather = { result ->
writeWeather(result, effectiveLocation)
},
onAlerts = { result ->
writeAlerts(result)
},
onAirQuality = { result ->
writeAirQuality(result)
},
)
val elapsed = System.currentTimeMillis() - startTime
val minLoadingTime = 1000L
// Prevents loader flicker when responses return too quickly
if (elapsed < minLoadingTime) {
delay(duration = (minLoadingTime - elapsed).milliseconds)
}
} finally {
externalManager.refreshWidgets()
externalManager.refreshNotifications()
locationStore.setLoading(false)
}
}
}
private fun writeWeather(
result: WeatherResult,
location: Location
) {
when (result) {
is WeatherResult.Success -> {
weatherStore.setWeather(weather = result.weather)
initializationStore.setInitialized()
}
is WeatherResult.Error -> {
weatherStore.setWeather(weather = result.weather)
isUnsupportedSource = !location.source.isGlobal()
&& !location.source.isSourceSupportedFor(
countryCode = location.countryCode?.uppercase()
)
_errors.tryEmit(result.exception.toAppException())
}
is WeatherResult.RefreshNotAvailable -> {
weatherStore.setWeather(result.weather)
_errors.tryEmit(AppException.RefreshNotAvailable())
}
is WeatherResult.NotSupported -> {}
}
}
private fun writeAirQuality(result: AirQualityResult?) {
if (result == null) {
weatherStore.setAirQuality(airQuality = null)
return
}
when (result) {
is AirQualityResult.Success -> {
weatherStore.setAirQuality(airQuality = result.airQuality)
}
// Fail silently, we just won't show the Air quality in the UI if null
is AirQualityResult.Error -> {
weatherStore.setAirQuality(airQuality = result.airQuality)
}
is AirQualityResult.NotSupported -> {
weatherStore.setAirQuality(null)
}
}
}
private fun writeAlerts(result: AlertResult?) {
if (result == null) {
weatherStore.setAlerts(alerts = emptyList())
return
}
when (result) {
is AlertResult.Success -> {
weatherStore.setAlerts(alerts = result.alerts)
}
// Fail silently, we just won't show the alerts in the UI if null
is AlertResult.Error -> {
weatherStore.setAlerts(alerts = result.alerts)
}
is AlertResult.NotSupported -> {
weatherStore.setAlerts(alerts = emptyList())
}
}
}
}
@@ -0,0 +1,26 @@
package com.pranshulgg.weather_master_app.core.managers
import androidx.lifecycle.viewModelScope
import com.pranshulgg.weather_master_app.core.model.domain.weather.WeatherUnits
import com.pranshulgg.weather_master_app.data.repository.WeatherUnitsRepository
import com.pranshulgg.weather_master_app.data.store.WeatherUnitsStore
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class WeatherUnitsManager @Inject constructor(
private val weatherUnitsStore: WeatherUnitsStore,
private val weatherUnitsRepository: WeatherUnitsRepository
) {
fun initialize(scope: CoroutineScope) {
weatherUnitsRepository.getUnits().distinctUntilChanged().onEach {
weatherUnitsStore.set(it)
}.launchIn(scope)
}
}
@@ -0,0 +1,56 @@
package com.pranshulgg.weather_master_app.core.managers.requests
import android.util.Log
import androidx.lifecycle.viewModelScope
import com.pranshulgg.weather_master_app.core.managers.LocationManager
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.core.model.sources.Source
import com.pranshulgg.weather_master_app.data.store.LocationStore
import com.pranshulgg.weather_master_app.data.store.WeatherStore
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.time.Duration.Companion.minutes
@Singleton
class AutoRefreshes @Inject constructor(
private val locationStore: LocationStore,
private val weatherStore: WeatherStore,
private val pendingRequests: PendingRequests,
private val locationManager: LocationManager
) {
private var autoRefreshJob: Job? = null
private val scope = CoroutineScope(SupervisorJob())
fun start() {
if (autoRefreshJob?.isActive == true) return
autoRefreshJob = scope.launch {
while (isActive) {
delay(45.minutes)
if (locationStore.data.value.isActiveLocationLoading || weatherStore.data.value.weather == null) {
continue
}
locationStore.data.value.activeLocation?.let {
locationManager.setActiveLoading()
pendingRequests.queueRequest(location = it, skipDeviceLocationCheck = true)
}
}
}
}
fun stop() {
autoRefreshJob?.cancel()
autoRefreshJob = null
}
}
@@ -0,0 +1,50 @@
package com.pranshulgg.weather_master_app.core.managers.requests
import android.util.Log
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject
import javax.inject.Singleton
data class WeatherRefreshRequestState(
val location: Location,
val isManualRefresh: Boolean,
val forceRefresh: Boolean,
val forceRefreshForAirQuality: Boolean,
val forceRefreshForAlerts: Boolean,
val skipDeviceLocationCheck: Boolean = false
)
@Singleton
class PendingRequests @Inject constructor() {
private val _pendingRequest =
MutableStateFlow<WeatherRefreshRequestState?>(null)
val pendingRequest = _pendingRequest.asStateFlow()
fun queueRequest(
location: Location,
isManualRefresh: Boolean = false,
isForceRefresh: Boolean = false,
isForceRefreshForAirQuality: Boolean = false,
isForceRefreshForAlerts: Boolean = false,
skipDeviceLocationCheck: Boolean = false
) {
_pendingRequest.tryEmit(
WeatherRefreshRequestState(
location = location,
forceRefresh = isForceRefresh,
forceRefreshForAirQuality = isForceRefreshForAirQuality,
forceRefreshForAlerts = isForceRefreshForAlerts,
isManualRefresh = isManualRefresh,
skipDeviceLocationCheck = skipDeviceLocationCheck
)
)
}
}
@@ -28,7 +28,9 @@ enum class MoonPhase(val displayName: Int, val icon: Int) {
R.string.moonphase_last_quarter,
R.drawable.moonphase_third_quarter
), // TODO: FIX NAMING
WANING_CRESCENT(R.string.moonphase_waning_crescent, R.drawable.moonphase_waning_crescent)
WANING_CRESCENT(R.string.moonphase_waning_crescent, R.drawable.moonphase_waning_crescent),
UNKNOWN(R.string.weather_no_data, R.drawable.weather_not_available)
}
fun getMoonPhase(phase: Double): MoonPhase {
@@ -1,26 +1,70 @@
package com.pranshulgg.weather_master_app.core.model.domain
import coil.network.HttpException
import com.pranshulgg.weather_master_app.R
import java.io.IOException
import java.net.ConnectException
import java.net.NoRouteToHostException
import java.net.SocketException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import javax.net.ssl.SSLHandshakeException
import javax.net.ssl.SSLPeerUnverifiedException
import kotlin.coroutines.cancellation.CancellationException
import retrofit2.HttpException
sealed class AppException(message: String? = null) : Exception(message) {
class Network : AppException()
class CurrentLocationUnavailable : AppException()
class BadRequest : AppException()
class Unauthorized : AppException()
class Forbidden : AppException()
class NotFound : AppException()
class RequestTimeout : AppException()
class TooManyRequests : AppException()
class Server : AppException()
class Unknown : AppException()
class NoApiKeyError : AppException()
// A key was provided but the provider rejected it (invalid, revoked, or expired) -
// sources can't tell those apart from an HTTP 401 alone, so the message stays generic.
class ApiKeyRejectedError : AppException()
class SecureConnection : AppException()
class EmptyResponseBody : AppException()
class BackupSchemaVersionUnsupported : AppException()
class BackupFileCorrupted : AppException()
class BackupFileIOError : AppException()
class BackupMissingDefaultLocation : AppException()
class RefreshNotAvailable : AppException()
}
fun AppException.toMessageRes(): Int {
return when (this) {
is AppException.Network -> R.string.error_network
is AppException.CurrentLocationUnavailable -> R.string.current_location_not_found
is AppException.BadRequest -> R.string.error_bad_request
is AppException.Unauthorized -> R.string.error_unauthorized
is AppException.Forbidden -> R.string.error_forbidden
is AppException.NotFound -> R.string.error_not_found
is AppException.RequestTimeout -> R.string.error_request_timeout
is AppException.TooManyRequests -> R.string.error_too_many_requests
is AppException.Server -> R.string.error_server
is AppException.Unknown -> R.string.error_generic
is AppException.NoApiKeyError -> R.string.error_no_api_key
is AppException.ApiKeyRejectedError -> R.string.error_api_key_rejected
is AppException.SecureConnection -> R.string.error_secure_connection_failed
is AppException.EmptyResponseBody -> R.string.error_empty_response_body
is AppException.BackupSchemaVersionUnsupported -> R.string.error_backup_schema_unsupported
is AppException.BackupFileCorrupted -> R.string.error_backup_file_corrupted
is AppException.BackupFileIOError -> R.string.error_backup_file_io
is AppException.BackupMissingDefaultLocation -> R.string.error_backup_missing_default_location
is AppException.RefreshNotAvailable -> R.string.weather_refresh_delay_fixed
}
}
@@ -28,11 +72,31 @@ fun Throwable.toAppException(): AppException {
if (this is CancellationException) throw this
return when (this) {
is UnknownHostException,
is SocketTimeoutException,
is AppException -> this
is SSLHandshakeException -> AppException.SecureConnection()
is SSLPeerUnverifiedException -> AppException.SecureConnection()
is UnknownHostException -> AppException.Network()
is ConnectException -> AppException.Network()
is NoRouteToHostException -> AppException.Network()
is SocketException -> AppException.Network()
is SocketTimeoutException -> AppException.RequestTimeout()
is IOException -> AppException.Network()
is HttpException -> AppException.Server()
is HttpException -> when (this.code()) {
400 -> AppException.BadRequest()
401 -> AppException.Unauthorized()
403 -> AppException.Forbidden()
404 -> AppException.NotFound()
408 -> AppException.RequestTimeout()
429 -> AppException.TooManyRequests()
in 500..599 -> AppException.Server()
else -> AppException.Unknown()
}
else -> AppException.Unknown()
}
@@ -11,7 +11,8 @@ import kotlin.math.roundToInt
* We only display air quality if it's available
*/
data class AirQuality(
val current: AirQualityCurrent
val current: AirQualityCurrent,
val hourly: List<AirQualityHourly>
) {
companion object {
@@ -78,6 +79,29 @@ data class AirQuality(
)
}
fun getAqiFromValues(
carbonMonoxideMicrogramsPerCubicMeter: Double?,
pm25: Double?,
nitrogenDioxide: Double?,
ozone: Double?,
pm10: Double?,
sulphurDioxide: Double?
): Int {
// Open-Meteo provides "carbon_monoxide" in MicrogramsPerCubicMeter so we convert to Milligrams
val coInMilligramsPerCubicMeter = (carbonMonoxideMicrogramsPerCubicMeter!! / 1000)
return maxOf(
getAqi(pm25!!, pm25Thresholds),
getAqi(nitrogenDioxide!!, no2Thresholds),
getAqi(ozone!!, o3Thresholds),
getAqi(pm10!!, pm10Thresholds),
getAqi(coInMilligramsPerCubicMeter, coThresholds),
getAqi(sulphurDioxide!!, so2Thresholds)
)
}
// For AQI bars
fun getAqiBarValue(aqi: Int): Float {
return (aqi / 250f).coerceIn(0f, 1f)
@@ -105,11 +129,48 @@ data class AirQuality(
data class AirQualityCurrent(
val usAqi: Int?,
/** µg/m³. */
val pm10: Double?,
/** µg/m³. */
val pm25: Double?,
/** µg/m³. */
val carbonMonoxide: Double?,
/** µg/m³. */
val nitrogenDioxide: Double?,
/** µg/m³. */
val sulphurDioxide: Double?,
/** µg/m³. */
val ozone: Double?,
/** Milliseconds */
val lastUpdatedInMilli: Long
)
data class AirQualityHourly(
/** µg/m³. */
val pm10: Double?,
/** µg/m³. */
val pm25: Double?,
/** µg/m³. */
val carbonMonoxide: Double?,
/** µg/m³. */
val nitrogenDioxide: Double?,
/** µg/m³. */
val sulphurDioxide: Double?,
/** µg/m³. */
val ozone: Double?,
/** Seconds */
val time: Long,
)
@@ -0,0 +1,15 @@
package com.pranshulgg.weather_master_app.core.model.domain.alerts
import com.pranshulgg.weather_master_app.core.model.weather.alerts.AlertSeverity
data class Alert(
val locationId: String,
val event: String,
val severity: AlertSeverity?,
val effective: Long?,
val expires: Long?,
val description: String,
val source: String?,
val lastUpdatedInMilli: Long
)
@@ -2,5 +2,6 @@ package com.pranshulgg.weather_master_app.core.model.domain.location
data class Address(
val city: String?,
val country: String
val country: String,
val countryCode: String?
)
@@ -1,6 +1,7 @@
package com.pranshulgg.weather_master_app.core.model.domain.location
import com.pranshulgg.weather_master_app.core.model.sources.WeatherSource
import com.pranshulgg.weather_master_app.core.model.sources.Source
import com.pranshulgg.weather_master_app.core.model.weather.openmeteo.OpenMeteoModel
data class Location(
val id: String,
@@ -11,9 +12,14 @@ data class Location(
val timezone: String,
val countryCode: String?,
val state: String,
val source: WeatherSource = WeatherSource.OPEN_METEO,
val source: Source = Source.OPEN_METEO,
val isFavorite: Boolean = false,
val isPinned: Boolean = false,
val isDefault: Boolean,
val isDeviceLocation: Boolean = false
val isDeviceLocation: Boolean = false,
val alertSource: Source = Source.NONE,
val airQualitySource: Source = Source.OPEN_METEO,
val customName: String? = null,
val openMeteoModel: OpenMeteoModel = OpenMeteoModel.BEST_MATCH,
val alertsLastFetchedAt: Long? = null
)
@@ -0,0 +1,6 @@
package com.pranshulgg.weather_master_app.core.model.domain.location
data class LocationKey(
val locationId: String,
val cityKey: String
)
@@ -0,0 +1,10 @@
package com.pranshulgg.weather_master_app.core.model.domain.weather
import com.pranshulgg.weather_master_app.core.model.sources.Source
import com.pranshulgg.weather_master_app.data.local.entity.weather.ApiKeyEntity
data class ApiKey(
val id: Long,
val source: Source,
val apiKey: String? = null
)
@@ -14,7 +14,7 @@ data class Weather(
data class WeatherCurrent(
val temperature: Double?, // NOTE: ALWAYS C
val humidity: Double,
val humidity: Double?,
val windSpeed: Double?, // NOTE: ALWAYS KMH
val windDirection: WindDirection?, // NOTE: ALWAYS DOMINANT
val pressureMsl: Double?, // NOTE: ALWAYS HPA
@@ -23,7 +23,6 @@ data class WeatherCurrent(
val uvIndex: Double?,
val weatherCondition: WeatherCondition,
val feelsLike: Double?,
val time: Long, // NOTE: ALWAYS MILLISECONDS
val dewPoint: Double?,
val utcOffsetSeconds: Long?,
val lastUpdatedInMilli: Long
@@ -52,6 +51,11 @@ data class WeatherCurrent(
fun isUvIndexValid(): Boolean {
return uvIndex != null
}
fun isHumidityValid(): Boolean {
return humidity != null
}
}
data class WeatherHourly(
@@ -85,7 +89,7 @@ data class WeatherHourly(
data class WeatherDaily(
val temperatureMin: Double?, // NOTE: ALWAYS C
val temperatureMax: Double?, // NOTE: ALWAYS C
val windSpeed: Double?, // NOTE: ALWAYS KMH
val windSpeed: Double?, // NOTE: ALWAYS KMH (Average)
val windDirection: WindDirection?, // NOTE: ALWAYS DOMINANT
val rainSum: Double, // NOTE: ALWAYS MM
val snowfallSum: Double?, // NOTE: ALWAYS CM
@@ -93,13 +97,17 @@ data class WeatherDaily(
val weatherCondition: WeatherCondition,
val time: Long, // NOTE: ALWAYS MILLISECONDS
val precipitationProbabilityMax: Int?,
val sunrise: Long, // NOTE: ALWAYS MILLISECONDS
val sunset: Long, // NOTE: ALWAYS MILLISECONDS
val moonrise: Long, // NOTE: ALWAYS MILLISECONDS
val moonset: Long, // NOTE: ALWAYS MILLISECONDS
val pressureMsl: Double?, // NOTE: ALWAYS HPA (Average)
val visibility: Int?, // NOTE: ALWAYS METERS (Minimum)
val humidity: Double?, // (Average)
val dewPoint: Double?, // (Average)
val sunrise: Long?, // NOTE: ALWAYS MILLISECONDS
val sunset: Long?, // NOTE: ALWAYS MILLISECONDS
val moonrise: Long?, // NOTE: ALWAYS MILLISECONDS
val moonset: Long?, // NOTE: ALWAYS MILLISECONDS
val moonPhase: MoonPhase,
val dawn: Long,
val dusk: Long
val dawn: Long?,
val dusk: Long?
) {
fun isWindSpeedValid(): Boolean {
@@ -117,4 +125,29 @@ data class WeatherDaily(
fun isUvIndexMaxValid(): Boolean {
return uvIndexMax != null
}
fun isVisibilityValid(): Boolean {
return visibility != null && visibility != -1
}
fun isHumidityValid(): Boolean {
return humidity != null && humidity != -1.0
}
fun isDewPointValid(): Boolean {
return dewPoint != null
}
fun isPressureValid(): Boolean {
return pressureMsl != null && pressureMsl != -1.0
}
fun isMoonValid(): Boolean {
return moonrise != null && moonset != null
}
fun isSunValid(): Boolean {
return sunrise != null && sunset != null
}
}
@@ -142,7 +142,29 @@ data class WeatherBlock(
isDaily = true,
id = (999L..2000L).random()
),
WeatherBlock(
type = WeatherBlockType.HUMIDITY_BLOCK,
isHidden = false,
position = 6,
isDaily = true,
id = (999L..2000L).random()
),
WeatherBlock(
type = WeatherBlockType.PRESSURE_BLOCK,
isHidden = false,
position = 7,
isDaily = true,
id = (999L..2000L).random()
),
WeatherBlock(
type = WeatherBlockType.VISIBILITY_BLOCK,
isHidden = false,
position = 8,
isDaily = true,
id = (999L..2000L).random()
),
)
}
}
@@ -2,5 +2,6 @@ package com.pranshulgg.weather_master_app.core.model.sources
enum class SearchSource(val displayName: String) {
OPEN_METEO("Open Meteo"),
GEO_NAMES("GeoNames")
GEO_NAMES("GeoNames"),
ACCU_WEATHER("AccuWeather")
}
@@ -0,0 +1,333 @@
package com.pranshulgg.weather_master_app.core.model.sources
import com.pranshulgg.weather_master_app.R
// TODO: implement alerts / air quality for sources that support it
enum class Source(
val displayName: String,
val hourlyAggregationLimitHours: Int = 24, // stupid and should be removed
val displayLink: String,
val fullName: String,
val countryNameRes: Int? = null,
val requiresUserApiKey: Boolean = false, // Source must not be selectable until the user has provided their API key
val signupLink: String? = null, // Shown instead of displayLink on the API key entry screen, when set
val apiKeyNote: String? = null, // Optional hint shown under the link on the API key entry screen
val regionalButWorldwideSupport: Boolean = false,
val capabilities: Set<Capability>,
// val providesAlerts: Boolean = false,
// val providesAirQuality: Boolean = false,
) {
OPEN_METEO(
displayName = "Open Meteo",
fullName = "Open Meteo",
displayLink = "https://open-meteo.com/",
capabilities = setOf(Capability.WEATHER, Capability.AIR_QUALITY)
),
NWS(
displayName = "NWS",
fullName = "National Weather Service",
displayLink = "https://www.weather.gov/documentation/services-web-api",
countryNameRes = R.string.country_usa,
capabilities = setOf(Capability.WEATHER, Capability.ALERTS)
),
SMHI(
displayName = "SMHI",
fullName = "Swedish Meteorological and Hydrological Institute",
displayLink = "https://opendata.smhi.se",
countryNameRes = R.string.country_sweden,
capabilities = setOf(Capability.WEATHER)
),
DWD(
displayName = "DWD",
fullName = "Bright Sky DWD",
displayLink = "https://brightsky.dev",
countryNameRes = R.string.country_germany,
capabilities = setOf(Capability.WEATHER)
),
METEO_FRANCE(
displayName = "Météo-France",
fullName = "Météo-France",
displayLink = "https://meteofrance.com/",
regionalButWorldwideSupport = true,
capabilities = setOf(Capability.WEATHER)
),
ECCC(
displayName = "ECCC",
fullName = "Environment and Climate Change Canada",
displayLink = "https://app.weather.gc.ca/",
countryNameRes = R.string.country_canada,
capabilities = setOf(Capability.WEATHER)
),
FMI(
displayName = "FMI",
fullName = "Finnish Meteorological Institute",
displayLink = "https://en.ilmatieteenlaitos.fi/",
countryNameRes = R.string.country_finland,
capabilities = setOf(Capability.WEATHER)
),
CHINA(
displayName = "China",
fullName = "China National Environmental Monitoring Centre",
displayLink = "https://www.cnemc.cn/",
capabilities = setOf(Capability.WEATHER)
),
BMKG(
displayName = "BMKG",
fullName = "Badan Meteorologi, Klimatologi, dan Geofisika",
displayLink = "https://www.bmkg.go.id/",
countryNameRes = R.string.country_indonesia,
capabilities = setOf(Capability.WEATHER)
),
ACCU_WEATHER(
displayName = "AccuWeather",
fullName = "AccuWeather",
displayLink = "https://www.accuweather.com/",
capabilities = setOf(Capability.WEATHER, Capability.ALERTS, Capability.AIR_QUALITY)
),
METEO_AM(
displayName = "Meteo AM",
fullName = "Meteorologia Aeronautica Militare",
displayLink = "https://www.meteoam.it/",
countryNameRes = R.string.country_italy,
capabilities = setOf(Capability.WEATHER)
),
IPMA(
displayName = "IPMA",
fullName = "Instituto Português do Mar e da Atmosfera",
displayLink = "https://api.ipma.pt/",
countryNameRes = R.string.country_portugal,
capabilities = setOf(Capability.WEATHER)
),
GISMETEO(
displayName = "Gismeteo",
fullName = "Gismeteo",
displayLink = "https://www.gismeteo.ru/",
countryNameRes = R.string.country_russia,
regionalButWorldwideSupport = true,
capabilities = setOf(Capability.WEATHER)
),
METEOFOR(
displayName = "Meteofor",
fullName = "Meteofor",
displayLink = "https://meteofor.com.ua/",
countryNameRes = R.string.country_ukraine,
capabilities = setOf(Capability.WEATHER)
),
MET_OFFICE(
displayName = "Met Office",
fullName = "Meteorological Office",
displayLink = "https://www.metoffice.gov.uk/",
countryNameRes = R.string.country_united_kingdom,
requiresUserApiKey = true,
signupLink = "https://datahub.metoffice.gov.uk/pricing/site-specific",
apiKeyNote = "Subscribe to the \"Global Spot\" option",
regionalButWorldwideSupport = true,
capabilities = setOf(Capability.WEATHER)
),
PIRATE_WEATHER(
displayName = "Pirate Weather",
fullName = "Pirate Weather",
displayLink = "https://pirateweather.net/",
requiresUserApiKey = true,
regionalButWorldwideSupport = false,
capabilities = setOf(Capability.WEATHER, Capability.ALERTS)
),
IMD(
displayName = "IMD",
fullName = "India Meteorological Department",
displayLink = "https://mausam.imd.gov.in/",
countryNameRes = R.string.country_india,
capabilities = setOf(Capability.WEATHER)
),
MET_NORWAY(
displayName = "Met Norway",
fullName = "Met Norway",
displayLink = "https://api.met.no/",
regionalButWorldwideSupport = true,
capabilities = setOf(Capability.WEATHER)
),
AEMET(
displayName = "AEMET",
fullName = "Agencia Estatal de Meteorología",
displayLink = "https://opendata.aemet.es/centrodedescargas/altaUsuario",
countryNameRes = R.string.country_spain,
requiresUserApiKey = true,
capabilities = setOf(Capability.WEATHER)
),
WEATHER_API(
displayName = "Weather API",
fullName = "Weather API",
displayLink = "https://www.weatherapi.com/",
capabilities = setOf(Capability.ALERTS)
),
WMO_SEVERE_WEATHER(
displayName = "WMO Severe Weather",
fullName = "WMO Severe Weather Information Centre",
displayLink = "https://www.wmo.int/",
capabilities = setOf(Capability.ALERTS)
),
FPAS(
displayName = "FOSS Public Alert Server",
fullName = "FOSS Public Alert Server",
displayLink = "https://invent.kde.org/webapps/foss-public-alert-server",
capabilities = setOf(Capability.ALERTS)
),
NONE(
displayName = "None",
fullName = "",
displayLink = "",
capabilities = setOf(Capability.ALERTS, Capability.AIR_QUALITY)
),
CWA(
displayName = "CWA",
fullName = "Central Weather Administration",
displayLink = "https://opendata.cwa.gov.tw/",
countryNameRes = R.string.country_taiwan,
requiresUserApiKey = true,
capabilities = setOf(Capability.WEATHER)
),
JMA(
displayName = "JMA",
fullName = "Japan Meteorological Agency",
displayLink = "https://www.jma.go.jp/bosai/",
countryNameRes = R.string.country_japan,
capabilities = setOf(Capability.WEATHER, Capability.ALERTS)
),
INMET(
displayName = "INMET",
fullName = "Instituto Nacional de Meteorologia",
displayLink = "https://portal.inmet.gov.br/",
countryNameRes = R.string.country_brazil,
capabilities = setOf(Capability.WEATHER, Capability.ALERTS)
),
MGM(
displayName = "MGM",
fullName = "Meteoroloji Genel Müdürlüğü",
displayLink = "https://www.mgm.gov.tr/",
countryNameRes = R.string.country_turkey,
capabilities = setOf(Capability.WEATHER, Capability.ALERTS)
),
KMI(
displayName = "KMI",
fullName = "Royal Meteorological Institute of Belgium",
displayLink = "https://www.meteo.be/",
countryNameRes = R.string.country_belgium,
capabilities = setOf(Capability.WEATHER, Capability.ALERTS)
),
OPEN_WEATHER(
displayName = "OpenWeather",
fullName = "OpenWeather",
apiKeyNote = "To use One Call 4.0, append '&one_call_4' to the end of your API key (e.g., your_api_key&one_call_4). This requires an active One Call 4.0 subscription",
displayLink = "https://openweathermap.org/",
capabilities = setOf(Capability.WEATHER, Capability.AIR_QUALITY),
requiresUserApiKey = true
),
MOENV(
displayName = "MOENV",
fullName = "Ministry of Environment",
displayLink = "https://data.moenv.gov.tw/en/dataset/detail/aqx_p_432",
countryNameRes = R.string.country_taiwan,
requiresUserApiKey = true,
signupLink = "https://data.moenv.gov.tw/api_term",
apiKeyNote = "Check \"Atmosphere\" under Follow dataset categories when signing up",
capabilities = setOf(Capability.AIR_QUALITY)
);
// Sources that provide snow/rain as precipitation
fun providesSnowFall(): Boolean {
return when (this) {
MET_NORWAY -> false
DWD -> false
CHINA -> false
BMKG -> false
IMD -> false
CWA -> false
JMA -> false
INMET -> false
else -> true
}
}
}
// WE MAP EVERY WEATHER SOURCE HERE, AS THEY GET ADDED
private val sourcesByCountry = buildMap {
put("US", listOf(Source.NWS))
put("SE", listOf(Source.SMHI))
put("DE", listOf(Source.DWD))
put("CA", listOf(Source.ECCC))
put("FI", listOf(Source.FMI))
put("CN", listOf(Source.CHINA))
put("ID", listOf(Source.BMKG))
listOf("IT", "VA").forEach { put(it, listOf(Source.METEO_AM)) }
put("PT", listOf(Source.IPMA))
put("RU", listOf(Source.GISMETEO))
put("UA", listOf(Source.METEOFOR))
listOf("GB", "UK").forEach { put(it, listOf(Source.MET_OFFICE)) }
put("NO", listOf(Source.MET_NORWAY))
put("FR", listOf(Source.METEO_FRANCE))
put("ES", listOf(Source.AEMET))
put("IN", listOf(Source.IMD))
put("TW", listOf(Source.CWA, Source.MOENV))
put("JP", listOf(Source.JMA))
put("BR", listOf(Source.INMET))
put("TR", listOf(Source.MGM))
put("BE", listOf(Source.KMI))
}
fun getSourcesForCountry(countryCode: String?): List<Source> {
return sourcesByCountry[countryCode] ?: emptyList()
}
/**
* Any source that has global coverage,
* including regional sources with global data,
* must be added here.
*/
private val sourcesGlobal = listOf(
// GLOBAL
Source.OPEN_METEO,
Source.ACCU_WEATHER,
Source.PIRATE_WEATHER,
Source.OPEN_WEATHER,
// REGIONAL WITH GLOBAL
Source.GISMETEO,
Source.MET_OFFICE,
Source.MET_NORWAY,
Source.METEO_FRANCE,
// ALERTS
Source.WEATHER_API,
Source.WMO_SEVERE_WEATHER,
Source.FPAS,
// Yes, "NONE" is a global source :P
Source.NONE
)
fun getSourcesGlobal(): List<Source> {
return sourcesGlobal
}
fun Source.isSourceSupportedFor(countryCode: String?): Boolean {
val source = sourcesByCountry[countryCode] ?: return false
return this in source
}
fun Source.isGlobal(): Boolean {
return this in sourcesGlobal
}
enum class Capability {
WEATHER,
ALERTS,
AIR_QUALITY
}
@@ -1,69 +0,0 @@
package com.pranshulgg.weather_master_app.core.model.sources
enum class WeatherSource(
val displayName: String,
val hourlyAggregationLimitHours: Int,
val displayLink: String
) {
OPEN_METEO(
displayName = "Open Meteo",
hourlyAggregationLimitHours = 24,
displayLink = "https://open-meteo.com/"
),
NWS(
displayName = "National Weather Service",
hourlyAggregationLimitHours = 24,
displayLink = "https://www.weather.gov/documentation/services-web-api"
),
SMHI(
displayName = "SMHI (Sweden)",
hourlyAggregationLimitHours = 24,
displayLink = "https://opendata.smhi.se"
),
DWD(
displayName = "Bright Sky DWD (Germany)",
hourlyAggregationLimitHours = 24,
displayLink = "https://brightsky.dev"
),
METEO_FRANCE(
displayName = "Météo-France",
hourlyAggregationLimitHours = 24,
displayLink = "https://meteofrance.com/"
),
MET_NORWAY(
displayName = "Met Norway",
hourlyAggregationLimitHours = 24,
"https://api.met.no/"
);
fun providesSnowFall(): Boolean {
return when (this) {
MET_NORWAY -> false
DWD -> false
else -> true
}
}
}
// WE MAP EVERY WEATHER SOURCE HERE, AS THEY GET ADDED
private val weatherSourcesByCountry = mapOf(
"US" to listOf(WeatherSource.NWS),
"SE" to listOf(WeatherSource.SMHI),
"DE" to listOf(WeatherSource.DWD)
)
fun getWeatherSourcesForCountry(countryCode: String?): List<WeatherSource> {
return weatherSourcesByCountry[countryCode] ?: emptyList()
}
// GLOBAL SOURCES
private val weatherSourcesGlobal = listOf(
WeatherSource.OPEN_METEO, WeatherSource.MET_NORWAY,
WeatherSource.METEO_FRANCE
)
fun getWeatherSourcesGlobal(): List<WeatherSource> {
return weatherSourcesGlobal
}
@@ -182,34 +182,56 @@ fun TemperatureUnit.toName(context: Context): String {
fun WindSpeedUnit.toName(context: Context, inShort: Boolean = false): String {
return when (this) {
MPS -> if (inShort) "m/s" else context.getString(R.string.unit_wind_mps)
MPH -> if (inShort) "mi/h" else context.getString(R.string.unit_wind_mph)
KPH -> if (inShort) "km/h" else context.getString(R.string.unit_wind_kph)
KT -> if (inShort) "kt" else context.getString(R.string.unit_wind_kt)
BFT -> if (inShort) "bft" else context.getString(R.string.unit_wind_bft)
MPS -> if (inShort) context.getString(R.string.unit_wind_mps_short) else context.getString(R.string.unit_wind_mps)
MPH -> if (inShort) context.getString(R.string.unit_wind_mph_short) else context.getString(R.string.unit_wind_mph)
KPH -> if (inShort) context.getString(R.string.unit_wind_kph_short) else context.getString(R.string.unit_wind_kph)
KT -> if (inShort) context.getString(R.string.unit_wind_kt_short) else context.getString(R.string.unit_wind_kt)
BFT -> if (inShort) context.getString(R.string.unit_wind_bft_short) else context.getString(R.string.unit_wind_bft)
}
}
fun PressureUnit.toName(inShort: Boolean = false, context: Context): String {
return when (this) {
HPA -> if (inShort) "hPa" else context.getString(R.string.unit_pressure_hpa)
INHG -> if (inShort) "inHG" else context.getString(R.string.unit_pressure_inhg)
PressureUnit.MMHG -> if (inShort) "mmHG" else context.getString(R.string.unit_pressure_mmhg)
HPA -> if (inShort) context.getString(R.string.unit_pressure_hpa_short) else context.getString(
R.string.unit_pressure_hpa
)
INHG -> if (inShort) context.getString(R.string.unit_pressure_inhg_short) else context.getString(
R.string.unit_pressure_inhg
)
PressureUnit.MMHG -> if (inShort) context.getString(R.string.unit_pressure_mmhg_short) else context.getString(
R.string.unit_pressure_mmhg
)
}
}
fun DistanceUnit.toName(inShort: Boolean = false, context: Context): String {
return when (this) {
KM -> if (inShort) "km" else context.getString(R.string.unit_distance_km)
MI -> if (inShort) "mi" else context.getString(R.string.unit_distance_mi)
M -> if (inShort) "m" else context.getString(R.string.unit_distance_m)
KM -> if (inShort) context.getString(R.string.unit_distance_km_short) else context.getString(
R.string.unit_distance_km
)
MI -> if (inShort) context.getString(R.string.unit_distance_mi_short) else context.getString(
R.string.unit_distance_mi
)
M -> if (inShort) context.getString(R.string.unit_distance_m_short) else context.getString(R.string.unit_distance_m)
}
}
fun PrecipitationUnit.toName(context: Context, inShort: Boolean = false): String {
return when (this) {
PrecipitationUnit.MM -> if (inShort) "mm" else context.getString(R.string.unit_precipitation_mm)
PrecipitationUnit.INCH -> if (inShort) "in" else context.getString(R.string.unit_precipitation_inch)
PrecipitationUnit.CM -> if (inShort) "cm" else context.getString(R.string.unit_precipitation_cm)
PrecipitationUnit.MM -> if (inShort) context.getString(R.string.unit_precipitation_mm_short) else context.getString(
R.string.unit_precipitation_mm
)
PrecipitationUnit.INCH -> if (inShort) context.getString(R.string.unit_precipitation_inch_short) else context.getString(
R.string.unit_precipitation_inch
)
PrecipitationUnit.CM -> if (inShort) context.getString(R.string.unit_precipitation_cm_short) else context.getString(
R.string.unit_precipitation_cm
)
}
}
@@ -5,7 +5,11 @@ import com.pranshulgg.weather_master_app.R
import com.pranshulgg.weather_master_app.core.model.domain.weather.WeatherDaily
// TODO: ADD SLEET, HAIL, WINDY, BLIZZARD, TORNADO, HURRICANE
// TODO: WINDY, BLIZZARD, TORNADO, HURRICANE
/**
* SLEET AND HAIL is supported but not mapped to many sources yet
* TODO: FIX IT
*/
enum class WeatherCondition {
CLEAR_SKY,
OVERCAST,
@@ -23,6 +27,10 @@ enum class WeatherCondition {
RAIN,
SLEET,
HAIL,
MIXED_PRECIPITATION,
NO_CONDITION_FOUND,
// USED FOR DAILY
@@ -64,7 +72,7 @@ enum class WeatherCondition {
// ------- MAP TO ICONS -------
fun WeatherCondition.toIcon(daily: WeatherDaily? = null, targetTimeMilli: Long): Int {
val isDay = if (daily != null) {
val isDay = if (daily != null && daily.sunrise != null && daily.sunset != null) {
targetTimeMilli in daily.sunrise..daily.sunset
} else {
true
@@ -78,7 +86,7 @@ fun WeatherCondition.toIcon(daily: WeatherDaily? = null, targetTimeMilli: Long):
WeatherCondition.PARTLY_CLOUDY -> if (isDay) R.drawable.weather_partly_cloudy_day else R.drawable.weather_partly_cloudy_night
WeatherCondition.HEAVY_RAIN -> R.drawable.weather_heavy_rain
WeatherCondition.LIGHT_RAIN -> if (isDay) R.drawable.weather_light_rain_day else R.drawable.weather_light_rain_night
WeatherCondition.LIGHT_RAIN -> R.drawable.weather_light_rain
WeatherCondition.LIGHT_SNOW -> if (isDay) R.drawable.weather_light_snow_day else R.drawable.weather_light_snow_night
WeatherCondition.SNOW -> R.drawable.weather_snow
@@ -97,6 +105,10 @@ fun WeatherCondition.toIcon(daily: WeatherDaily? = null, targetTimeMilli: Long):
WeatherCondition.RAIN -> R.drawable.weather_rain
WeatherCondition.SLEET, WeatherCondition.HAIL -> R.drawable.weather_sleet_hail
WeatherCondition.MIXED_PRECIPITATION -> R.drawable.weather_mixed_precipitation
WeatherCondition.CLEAR_WITH_CLOUDY -> R.drawable.clear_with_cloudy
WeatherCondition.CLEAR_WITH_RAIN -> R.drawable.clear_with_rain
WeatherCondition.CLEAR_WITH_SNOW -> R.drawable.clear_with_snow
@@ -169,6 +181,10 @@ fun WeatherCondition.toLabel(context: Context): String {
WeatherCondition.RAIN -> context.getString(R.string.weather_rain)
WeatherCondition.SLEET -> context.getString(R.string.weather_sleet)
WeatherCondition.HAIL -> context.getString(R.string.weather_hail)
WeatherCondition.MIXED_PRECIPITATION -> context.getString(R.string.weather_mixed_precipitation)
WeatherCondition.CLEAR_WITH_CLOUDY -> context.getString(R.string.weather_clear_with_cloudy)
WeatherCondition.CLEAR_WITH_RAIN -> context.getString(R.string.weather_clear_with_rain)
WeatherCondition.CLEAR_WITH_SNOW -> context.getString(R.string.weather_clear_with_snow)
@@ -212,7 +228,7 @@ fun WeatherCondition.toLabel(context: Context): String {
fun WeatherCondition.toFroggy(daily: WeatherDaily? = null, targetTimeMilli: Long): Int {
val isDay = if (daily != null) {
val isDay = if (daily != null && daily.sunrise != null && daily.sunset != null) {
targetTimeMilli in daily.sunrise..daily.sunset
} else {
true
@@ -225,7 +241,7 @@ fun WeatherCondition.toFroggy(daily: WeatherDaily? = null, targetTimeMilli: Long
WeatherCondition.PARTLY_CLOUDY -> R.drawable.froggy_partly_cloudy
WeatherCondition.HEAVY_RAIN -> R.drawable.froggy_rain
WeatherCondition.HEAVY_RAIN, WeatherCondition.HAIL, WeatherCondition.SLEET -> R.drawable.froggy_rain
WeatherCondition.LIGHT_RAIN -> R.drawable.froggy_light_rain
WeatherCondition.LIGHT_SNOW -> R.drawable.froggy_snow
@@ -245,9 +261,11 @@ fun WeatherCondition.toFroggy(daily: WeatherDaily? = null, targetTimeMilli: Long
WeatherCondition.RAIN -> R.drawable.froggy_rain
WeatherCondition.NO_CONDITION_FOUND -> R.drawable.weather_not_available
WeatherCondition.MIXED_PRECIPITATION -> R.drawable.froggy_mixed_precip
else -> R.drawable.weather_not_available
WeatherCondition.NO_CONDITION_FOUND -> R.drawable.froggy_no_condition_found
else -> R.drawable.froggy_no_condition_found
}
@@ -1,14 +1,37 @@
package com.pranshulgg.weather_master_app.core.model.weather
import com.pranshulgg.weather_master_app.core.model.domain.alerts.Alert
import com.pranshulgg.weather_master_app.core.model.domain.weather.Weather
import com.pranshulgg.weather_master_app.data.repository.data.WeatherAdditionalData
sealed class WeatherResult {
data class Success(val weather: Weather) : WeatherResult()
data object RefreshNotAvailable : WeatherResult()
sealed class WeatherResult(
) {
data class Success(
val weather: Weather, val alerts: List<Alert> = emptyList()
) : WeatherResult()
data class RefreshNotAvailable(val weather: Weather) : WeatherResult()
data class Error(
val exception: Exception,
val weather: Weather?,
val rawException: Exception? = null
) : WeatherResult()
class NotSupported : WeatherResult()
data class Error(val exception: Exception, val cacheWeather: Weather? = null) : WeatherResult()
}
data class WeatherDataPack(
val weather: Weather,
val additionalData: WeatherAdditionalData? = null
)
data class FinishedWeatherResult(
val weather: Weather
)
enum class WeatherResultType {
REFRESH_TOO_EARLY,
SUCCESS,
@@ -1,14 +1,31 @@
package com.pranshulgg.weather_master_app.core.model.weather.airquality
import com.pranshulgg.weather_master_app.core.model.domain.airquality.AirQuality
import com.pranshulgg.weather_master_app.core.model.domain.alerts.Alert
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.data.repository.data.AirQualityAdditionalData
import com.pranshulgg.weather_master_app.data.repository.data.AlertsAdditionalData
sealed class AirQualityResult {
data class Success(val airquality: AirQuality) : AirQualityResult()
data class Error(val exception: Exception, val cacheAirQuality: AirQuality? = null) :
data class Success(val airQuality: AirQuality) : AirQualityResult()
data class Error(val exception: Exception, val airQuality: AirQuality? = null) :
AirQualityResult()
class NotSupported : AirQualityResult()
}
data class FinishedAirQualityResult(
val airQuality: AirQuality
)
data class AirQualityDataPack(
val airQuality: AirQuality?,
val location: Location,
val additionalData: AirQualityAdditionalData? = null,
)
enum class AirQualityResultType {
RETURN_CACHE,
ERROR
@@ -18,7 +18,7 @@ enum class Pollutant(
companion object {
private fun getLevelIndex(value: Double, thresholds: List<Int>): Int {
fun getLevelIndex(value: Double, thresholds: List<Int>): Int {
val index = thresholds.indexOfLast { value >= it }
return if (index == -1) 0 else index
}
@@ -0,0 +1,32 @@
package com.pranshulgg.weather_master_app.core.model.weather.alerts
import com.pranshulgg.weather_master_app.core.model.domain.alerts.Alert
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.core.model.domain.weather.Weather
import com.pranshulgg.weather_master_app.data.repository.data.AlertsAdditionalData
import com.pranshulgg.weather_master_app.data.repository.data.WeatherAdditionalData
sealed class AlertResult {
data class Success(val alerts: List<Alert>) : AlertResult()
data class Error(val exception: Exception, val alerts: List<Alert> = emptyList()) :
AlertResult()
class NotSupported : AlertResult()
}
data class FinishedAlertsResult(
val alerts: List<Alert>
)
data class AlertsDataPack(
val alerts: List<Alert>,
val location: Location,
val additionalData: AlertsAdditionalData? = null,
)
enum class AlertResultType {
RETURN_CACHE,
ERROR
}
@@ -0,0 +1,42 @@
package com.pranshulgg.weather_master_app.core.model.weather.alerts
import androidx.compose.ui.graphics.Color
import com.pranshulgg.weather_master_app.R
enum class AlertSeverity(
val label: Int,
val color: Color,
val contentColor: Color,
val colorRes: Int
) {
CRITICAL(
R.string.alert_severity_critical,
Color(0xFFD32F2F),
Color(0xFFFFEBEE),
R.color.alert_CRITICAL
),
HIGH(
R.string.alert_severity_high,
Color(0xFFF57C00),
Color(0xFFFFF4E0),
R.color.alert_HIGH
),
MODERATE(
R.string.alert_severity_medium,
Color(0xFFFBC02D),
Color(0xFF5C4300),
R.color.alert_MODERATE
),
LOW(
R.string.alert_severity_low,
Color(0xFF388E3C),
Color(0xFF0F3D0F),
R.color.alert_LOW
),
UNKNOWN(
R.string.alert_severity_unknown,
Color(0xFF757575),
Color(0xFFF3E5F5),
R.color.alert_UNKNOWN
)
}
@@ -0,0 +1,320 @@
package com.pranshulgg.weather_master_app.core.model.weather.openmeteo
import com.pranshulgg.weather_master_app.R
enum class OpenMeteoModelType {
BEST_MATCH,
NCEP,
JMA,
KMA,
DWD,
GEM,
METEO_FRANCE,
ITALIA_METEO,
MET_NORWAY,
KNMI,
DMI,
UK_MET_OFFICE,
METEOSWISS,
GEOSPHERE,
CHMI,
UNDEFINED
}
enum class OpenMeteoModel(
val displayName: String,
val stringValue: Int? = null,
val modelId: String,
val modelType: OpenMeteoModelType = OpenMeteoModelType.UNDEFINED
) {
BEST_MATCH(
"Best Match",
R.string.open_meteo_model_best_match,
"best_match",
OpenMeteoModelType.BEST_MATCH
),
ECMWF_IFS_HRES_9KM(
"ECMWF IFS HRES 9km",
modelId = "ecmwf_ifs"
),
ECMWF_IFS_025(
"ECMWF IFS 0.25°",
modelId = "ecmwf_ifs025"
),
ECMWF_AIFS_025_SINGLE(
"ECMWF AIFS 0.25° Single",
modelId = "ecmwf_aifs025_single"
),
CMA_GRAPES_GLOBAL(
"CMA GRAPES Global",
modelId = "cma_grapes_global"
),
BOM_ACCESS_GLOBAL(
"BOM ACCESS Global",
modelId = "bom_access_global"
),
NCEP_GFS_SEAMLESS(
"NCEP GFS Seamless",
R.string.open_meteo_model_seamless,
"ncep_gfs_seamless",
OpenMeteoModelType.NCEP
),
NCEP_GFS_GLOBAL_011_025(
"NCEP GFS Global 0.11°/0.25°",
modelId = "ncep_gfs_global",
modelType = OpenMeteoModelType.NCEP
),
NCEP_HRRR_US_CONUS(
"NCEP HRRR U.S. Conus",
modelId = "ncep_hrrr_conus",
modelType = OpenMeteoModelType.NCEP
),
NCEP_NBM_US_CONUS(
"NCEP NBM U.S. Conus",
modelId = "ncep_nbm_conus",
modelType = OpenMeteoModelType.NCEP
),
NCEP_NAM_US_CONUS(
"NCEP NAM U.S. Conus",
modelId = "ncep_nam_conus",
modelType = OpenMeteoModelType.NCEP
),
NCEP_AIGFS_025(
"NCEP AIGFS 0.25°",
modelId = "ncep_aigfs025",
modelType = OpenMeteoModelType.NCEP
),
NCEP_HGEFS_025_ENSEMBLE_MEAN(
"NCEP HGEFS 0.25° Ensemble Mean",
modelId = "ncep_hgefs025_ensemble_mean",
modelType = OpenMeteoModelType.NCEP
),
JMA_SEAMLESS(
"JMA Seamless",
R.string.open_meteo_model_seamless,
"jma_seamless",
modelType = OpenMeteoModelType.JMA
),
JMA_MSM(
"JMA MSM",
modelId = "jma_msm",
modelType = OpenMeteoModelType.JMA
),
JMA_GSM(
"JMA GSM",
modelId = "jma_gsm",
modelType = OpenMeteoModelType.JMA
),
KMA_SEAMLESS(
"KMA Seamless",
R.string.open_meteo_model_seamless,
"kma_seamless",
modelType = OpenMeteoModelType.KMA
),
KMA_LDPS(
"KMA LDPS",
modelId = "kma_ldps",
modelType = OpenMeteoModelType.KMA
),
KMA_GDPS(
"KMA GDPS",
modelId = "kma_gdps",
modelType = OpenMeteoModelType.KMA
),
DWD_ICON_SEAMLESS(
"DWD ICON Seamless",
R.string.open_meteo_model_seamless,
"dwd_icon_seamless",
modelType = OpenMeteoModelType.DWD
),
DWD_ICON_GLOBAL(
"DWD ICON Global",
modelId = "dwd_icon_global",
modelType = OpenMeteoModelType.DWD
),
DWD_ICON_EU(
"DWD ICON EU",
modelId = "dwd_icon_eu",
modelType = OpenMeteoModelType.DWD
),
DWD_ICON_D2(
"DWD ICON D2",
modelId = "dwd_icon_d2",
modelType = OpenMeteoModelType.DWD
),
GEM_SEAMLESS(
"GEM Seamless",
R.string.open_meteo_model_seamless,
"cmc_gem_seamless",
modelType = OpenMeteoModelType.GEM
),
GEM_GLOBAL(
"GEM Global",
modelId = "cmc_gem_gdps",
modelType = OpenMeteoModelType.GEM
),
GEM_REGIONAL(
"GEM Regional",
modelId = "cmc_gem_rdps",
modelType = OpenMeteoModelType.GEM
),
GEM_HRDPS_CONTINENTAL(
"GEM HRDPS Continental",
modelId = "cmc_gem_hrdps",
modelType = OpenMeteoModelType.GEM
),
GEM_HRDPS_WEST(
"GEM HRDPS West",
modelId = "cmc_gem_hrdps_west",
modelType = OpenMeteoModelType.GEM
),
METEO_FRANCE_SEAMLESS(
"Météo-France Seamless",
R.string.open_meteo_model_seamless,
"meteofrance_seamless",
modelType = OpenMeteoModelType.METEO_FRANCE
),
METEO_FRANCE_ARPEGE_WORLD(
"Météo-France ARPEGE World",
modelId = "meteofrance_arpege_world",
modelType = OpenMeteoModelType.METEO_FRANCE
),
METEO_FRANCE_ARPEGE_EUROPE(
"Météo-France ARPEGE Europe",
modelId = "meteofrance_arpege_europe",
modelType = OpenMeteoModelType.METEO_FRANCE
),
METEO_FRANCE_AROME_FRANCE(
"Météo-France AROME France",
modelId = "meteofrance_arome_france",
modelType = OpenMeteoModelType.METEO_FRANCE
),
METEO_FRANCE_AROME_FRANCE_HD(
"Météo-France AROME France HD",
modelId = "meteofrance_arome_france_hd",
modelType = OpenMeteoModelType.METEO_FRANCE
),
ITALIAMETEO_ARPAE_ICON_2I(
"ItaliaMeteo ARPAE ICON 2I",
modelId = "italia_meteo_arpae_icon_2i",
modelType = OpenMeteoModelType.ITALIA_METEO
),
MET_NORWAY_NORDIC_SEAMLESS_WITH_ECMWF(
"MET Norway Nordic (with ECMWF) Seamless",
R.string.open_meteo_model_seamless,
"metno_seamless",
modelType = OpenMeteoModelType.MET_NORWAY
),
MET_NORWAY_NORDIC(
"MET Norway Nordic",
modelId = "metno_nordic",
modelType = OpenMeteoModelType.MET_NORWAY
),
KNMI_SEAMLESS_WITH_ECMWF(
"KNMI (with ECMWF) Seamless",
R.string.open_meteo_model_seamless,
"knmi_seamless",
modelType = OpenMeteoModelType.KNMI
),
KNMI_HARMONIE_AROME_EUROPE(
"KNMI Harmonie AROME Europe",
modelId = "knmi_harmonie_arome_europe",
modelType = OpenMeteoModelType.KNMI
),
KNMI_HARMONIE_AROME_NETHERLANDS(
"KNMI Harmonie AROME Netherlands",
modelId = "knmi_harmonie_arome_netherlands",
modelType = OpenMeteoModelType.KNMI
),
DMI_SEAMLESS_WITH_ECMWF(
"DMI (with ECMWF) Seamless",
R.string.open_meteo_model_seamless,
"dmi_seamless",
modelType = OpenMeteoModelType.DMI
),
DMI_HARMONIE_AROME_EUROPE(
"DMI Harmonie AROME Europe",
modelId = "dmi_harmonie_arome_europe",
modelType = OpenMeteoModelType.DMI
),
UK_MET_OFFICE_SEAMLESS(
"UK Met Office Seamless",
R.string.open_meteo_model_seamless,
"ukmo_seamless",
modelType = OpenMeteoModelType.UK_MET_OFFICE
),
UK_MET_OFFICE_GLOBAL_10KM(
"UK Met Office Global 10km",
modelId = "ukmo_global_deterministic_10km",
modelType = OpenMeteoModelType.UK_MET_OFFICE
),
UK_MET_OFFICE_UK_2KM(
"UK Met Office UK 2km",
modelId = "ukmo_uk_deterministic_2km",
modelType = OpenMeteoModelType.UK_MET_OFFICE
),
METEOSWISS_ICON_SEAMLESS(
"MeteoSwiss ICON Seamless",
R.string.open_meteo_model_seamless,
"meteoswiss_icon_seamless",
modelType = OpenMeteoModelType.METEOSWISS
),
METEOSWISS_ICON_CH1(
"MeteoSwiss ICON CH1",
modelId = "meteoswiss_icon_ch1",
modelType = OpenMeteoModelType.METEOSWISS
),
METEOSWISS_ICON_CH2(
"MeteoSwiss ICON CH2",
modelId = "meteoswiss_icon_ch2",
modelType = OpenMeteoModelType.METEOSWISS
),
GEOSPHERE_SEAMLESS_WITH_ECMWF(
"GeoSphere (with ECMWF) Seamless",
R.string.open_meteo_model_seamless,
"geosphere_seamless",
modelType = OpenMeteoModelType.GEOSPHERE
),
GEOSPHERE_AROME_AUSTRIA(
"GeoSphere AROME Austria",
modelId = "geosphere_arome_austria",
modelType = OpenMeteoModelType.GEOSPHERE
),
CHMI_ALADIN_SEAMLESS(
"CHMI Aladin Seamless",
R.string.open_meteo_model_seamless,
"chmi_aladin_seamless",
modelType = OpenMeteoModelType.CHMI
),
CHMI_ALADIN_CENTRAL_EUROPE_2KM(
"CHMI Aladin Central Europe 2km",
modelId = "chmi_aladin_central_europe_2km",
modelType = OpenMeteoModelType.CHMI
),
CHMI_ALADIN_CZ_1KM(
"CHMI Aladin CZ 1km",
modelId = "chmi_aladin_cz_1km",
modelType = OpenMeteoModelType.CHMI
),
}
@@ -3,6 +3,7 @@ package com.pranshulgg.weather_master_app.core.model.weather.uv
import android.content.Context
import androidx.compose.ui.graphics.Color
import com.pranshulgg.weather_master_app.R
import com.pranshulgg.weather_master_app.core.model.weather.airquality.AirQualityLevel
enum class UvIndex {
LOW,
@@ -40,4 +41,14 @@ fun UvIndex.toColor(): Color {
UvIndex.VERY_HIGH -> Color(0xFFF44336)
UvIndex.EXTREME -> Color(0xFF9C27B0)
}
}
fun UvIndex.toTextColor(): Color {
return when (this) {
UvIndex.LOW -> Color(0xFF0F3D0F)
UvIndex.MODERATE -> Color(0xFF5C4300)
UvIndex.HIGH -> Color(0xFFFFF4E0)
UvIndex.VERY_HIGH -> Color(0xFFFFEBEE)
UvIndex.EXTREME -> Color(0xFFFFE4F1)
}
}
@@ -0,0 +1,42 @@
package com.pranshulgg.weather_master_app.core.network.calls
import com.pranshulgg.weather_master_app.core.model.domain.AppException
import com.pranshulgg.weather_master_app.core.model.domain.toAppException
import retrofit2.HttpException
import retrofit2.Response
import java.io.IOException
suspend fun <T> safeApiCall(
call: suspend () -> Response<T>
): Result<T> {
return try {
val response = call()
if (response.isSuccessful) {
response.body()?.let(Result.Companion::success)
?: Result.failure(
AppException.EmptyResponseBody()
)
} else {
Result.failure(
resolveException(response)
)
}
} catch (e: Exception) {
Result.failure(e.toAppException())
}
}
private fun resolveException(response: Response<*>): AppException {
return when (response.code()) {
400 -> AppException.BadRequest()
401 -> AppException.Unauthorized()
403 -> AppException.Forbidden()
404 -> AppException.NotFound()
408 -> AppException.RequestTimeout()
429 -> AppException.TooManyRequests()
in 500..599 -> AppException.Server()
else -> AppException.Unknown()
}
}
@@ -1,12 +1,28 @@
package com.pranshulgg.weather_master_app.core.network.github
import com.pranshulgg.weather_master_app.data.local.dao.github.GithubDao
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.net.UnknownHostException
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class GithubRepository @Inject constructor(
private val api: GithubApi
private val api: GithubApi,
private val dao: GithubDao
) {
suspend fun isNewVersionAvailable(currentTag: String): Boolean {
suspend fun isNewVersionAvailable(currentTag: String): Boolean = withContext(Dispatchers.IO) {
val getSavedVersionInfo = dao.getGithubEntity()
if (getSavedVersionInfo != null && getSavedVersionInfo.currentTag == currentTag) {
val ageMillis = System.currentTimeMillis() - getSavedVersionInfo.lastFetchedTime
val maxAgeMillis = TimeUnit.HOURS.toMillis(2)
if (ageMillis < maxAgeMillis) {
return@withContext getSavedVersionInfo.lastFetchedTag != currentTag
}
}
try {
val response = api.fetchGithubRepos()
@@ -14,11 +30,13 @@ class GithubRepository @Inject constructor(
val body = response.body() ?: throw UnknownHostException()
val firstTag = body.firstOrNull { !it.prerelease }?.tagName
?: return false
?: return@withContext false
val isNewAvailable = firstTag != currentTag
return isNewAvailable
dao.insertGithubEntity(currentTag, firstTag, System.currentTimeMillis())
return@withContext isNewAvailable
} catch (e: Exception) {
throw e
@@ -19,20 +19,17 @@ interface NominatimApi {
@Query("format") format: String = "jsonv2",
@Query("lat") latitude: Double,
@Query("lon") longitude: Double,
@Query("layer") layer: String = "address"
@Query("layer") layer: String = "address",
@Query("accept-language") lang: String = "en"
): Response<NominatimAddressJson>
companion object {
const val BASE_URL = "https://nominatim.openstreetmap.org/"
fun create(): NominatimApi {
val logging = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val client = OkHttpClient.Builder()
.addInterceptor(logging)
.addInterceptor { chain ->
val request = chain.request().newBuilder()
.header(
@@ -19,5 +19,7 @@ data class NominatimAddressDataJson(
val suburb: String?,
val state: String?,
val country: String
val country: String,
@SerializedName("country_code") val countryCode: String?
)
@@ -0,0 +1,12 @@
# Air Quality
This folder is for airquality-specific API implementations
### Rules
- Only add APIs here when the source provides **Air Quality only**.
- If air quality comes from a source that also provides weather, keep the API under that source's
existing
folder instead. You can take a look at **AccuWeather** implementation
- A single source should have a single source-level implementation/folder, even if it exposes
multiple endpoints.
@@ -0,0 +1,35 @@
package com.pranshulgg.weather_master_app.core.network.sources.airquality.moenv
import com.pranshulgg.weather_master_app.core.network.sources.airquality.moenv.json.MoenvStationJson
import okhttp3.OkHttpClient
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query
import java.util.concurrent.TimeUnit
interface MoenvApi {
@GET("v2/aqx_p_432")
suspend fun fetchStations(
@Query("api_key") apiKey: String,
@Query("format") format: String = "json"
): Response<List<MoenvStationJson>>
companion object {
const val BASE_URL = "https://data.moenv.gov.tw/api/"
fun create(): MoenvApi {
val client = OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS).build()
return Retrofit.Builder().baseUrl(BASE_URL).client(client).addConverterFactory(
GsonConverterFactory.create()
).build().create(MoenvApi::class.java)
}
}
}
@@ -0,0 +1,63 @@
package com.pranshulgg.weather_master_app.core.network.sources.airquality.moenv
import com.pranshulgg.weather_master_app.core.model.domain.AppException
import com.pranshulgg.weather_master_app.core.model.domain.airquality.AirQuality
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.core.model.sources.Source
import com.pranshulgg.weather_master_app.core.model.weather.airquality.AirQualityDataPack
import com.pranshulgg.weather_master_app.core.model.weather.airquality.FinishedAirQualityResult
import com.pranshulgg.weather_master_app.core.network.calls.safeApiCall
import com.pranshulgg.weather_master_app.data.local.dao.airquality.AirQualityDao
import com.pranshulgg.weather_master_app.data.local.mapper.airquality.sources.moenv.findClosestStation
import com.pranshulgg.weather_master_app.data.local.mapper.airquality.sources.moenv.toDomain
import com.pranshulgg.weather_master_app.data.repository.airquality.AirQualityCacheModel
import com.pranshulgg.weather_master_app.data.repository.capability.AirQualityCapability
import com.pranshulgg.weather_master_app.data.repository.capability.AlertCapability
import com.pranshulgg.weather_master_app.data.repository.capability.WeatherCapability
import com.pranshulgg.weather_master_app.data.repository.data.BaseRepository
import javax.inject.Inject
/**
* MOENV (Taiwan) air quality integration implemented by https://github.com/reveler-hub
*/
class MoenvRepository @Inject constructor(
val api: MoenvApi,
val airQualityDao: AirQualityDao
) : BaseRepository() {
override val weatherSource = Source.NONE
override val alertSource = Source.NONE
override val airQualitySource = Source.MOENV
override fun airQualityCapability(): AirQualityCapability {
return object : AirQualityCapability {
override suspend fun fetchAndProcess(
location: Location,
isManualRefresh: Boolean,
isForceRefresh: Boolean,
airQualityCacheModel: AirQualityCacheModel
): AirQualityDataPack {
val stations = safeApiCall {
api.fetchStations(apiKey = airQualityCacheModel.apiKey!!)
}.getOrThrow()
val closest = findClosestStation(location, stations)
?: throw AppException.EmptyResponseBody()
return AirQualityDataPack(airQuality = closest.toDomain(), location)
}
override suspend fun saveToDb(data: AirQualityDataPack) {
useGenericSaveImplementationForAirQuality(airQualityDao, data)
}
override fun finishedResult(data: AirQuality): FinishedAirQualityResult {
return FinishedAirQualityResult(airQuality = data)
}
}
}
override fun weatherCapability(): WeatherCapability? = null
override fun alertCapability(): AlertCapability? = null
}
@@ -0,0 +1,19 @@
package com.pranshulgg.weather_master_app.core.network.sources.airquality.moenv.json
import com.google.gson.annotations.SerializedName
data class MoenvStationJson(
val sitename: String?,
val county: String?,
val aqi: String?,
val status: String?,
val latitude: String?,
val longitude: String?,
val so2: String?,
val co: String?,
val o3: String?,
val pm10: String?,
@SerializedName("pm2.5") val pm25: String?,
val no2: String?,
)
@@ -1,31 +0,0 @@
package com.pranshulgg.weather_master_app.core.network.sources.airquality.openmeteo
import com.google.gson.annotations.SerializedName
// TODO: ADD HOURLY-DAILY FORECAST
data class OpenMeteoAqiDto(
val current: OpenMeteoAqiCurrentDto
)
data class OpenMeteoAqiCurrentDto(
val time: Long,
@SerializedName("us_aqi")
val usAqi: Int,
val pm10: Double,
@SerializedName("pm2_5")
val pm25: Double,
@SerializedName("carbon_monoxide")
val carbonMonoxide: Double,
@SerializedName("nitrogen_dioxide")
val nitrogenDioxide: Double,
@SerializedName("sulphur_dioxide")
val sulphurDioxide: Double,
val ozone: Double
)
@@ -1,54 +0,0 @@
package com.pranshulgg.weather_master_app.core.network.sources.airquality.openmeteo
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.core.model.weather.airquality.AirQualityResult
import com.pranshulgg.weather_master_app.core.model.weather.airquality.AirQualityResultType
import com.pranshulgg.weather_master_app.core.utils.weather.cache.isCurrentAirQualitySafe
import com.pranshulgg.weather_master_app.core.utils.weather.cache.shouldReturnAirQualityCache
import com.pranshulgg.weather_master_app.data.local.dao.airquality.AirQualityDao
import com.pranshulgg.weather_master_app.data.local.mapper.airquality.toDomain
import com.pranshulgg.weather_master_app.data.local.mapper.airquality.toEntity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.net.UnknownHostException
import javax.inject.Inject
class OpenMeteoAqiRepository @Inject constructor(
private val api: OpenMeteoAqiApi,
private val dao: AirQualityDao
) {
suspend fun getAirQuality(
location: Location,
isManualRefresh: Boolean
): AirQualityResult = withContext(Dispatchers.IO) {
val cache = dao.getAirQualityForLocation(location.id)
val shouldReturnCache = shouldReturnAirQualityCache(cache, isManualRefresh)
when (shouldReturnCache) {
AirQualityResultType.RETURN_CACHE -> return@withContext AirQualityResult.Success(cache!!.toDomain())
else -> {}
}
return@withContext try {
val response = api.fetchAirQuality(location.latitude, location.longitude)
val body = response.body()
?: return@withContext AirQualityResult.Error(exception = UnknownHostException())
val domain = body.toDomain()
dao.insertCurrentAirQuality(domain.current.toEntity(location.id))
AirQualityResult.Success(domain)
} catch (e: Exception) {
val isCacheSafe = isCurrentAirQualitySafe(cache?.toDomain())
AirQualityResult.Error(exception = e, if (isCacheSafe) cache?.toDomain() else null)
}
}
}
@@ -0,0 +1,11 @@
# Alerts
This folder is for alert-specific API implementations
### Rules
- Only add APIs here when the source provides **alerts only**.
- If alerts come from a source that also provides weather, keep the API under that source's existing
folder instead. You can take a look at **Open Meteo** implementation
- A single source should have a single source-level implementation/folder, even if it exposes
multiple endpoints.
@@ -0,0 +1,48 @@
package com.pranshulgg.weather_master_app.core.network.sources.alerts.fpas
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query
import java.util.concurrent.TimeUnit
interface FpasApi {
@GET("alert/area")
suspend fun fetchAlerts(
@Query("min_lat") minLat: Double,
@Query("max_lat") maxLat: Double,
@Query("min_lon") minLon: Double,
@Query("max_lon") maxLon: Double,
): Response<List<String>>
@GET("alert/{id}")
suspend fun fetchAlertsCap(
@Path("id") id: String,
): Response<ResponseBody>
companion object {
const val BASE_URL = "https://alerts.kde.org/"
fun create(): FpasApi {
val client = OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(FpasApi::class.java)
}
}
}
@@ -0,0 +1,185 @@
package com.pranshulgg.weather_master_app.core.network.sources.alerts.fpas
import android.util.Xml
import com.pranshulgg.weather_master_app.core.model.domain.AppException
import com.pranshulgg.weather_master_app.core.model.domain.alerts.Alert
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.core.model.sources.Source
import com.pranshulgg.weather_master_app.core.model.weather.alerts.AlertResult
import com.pranshulgg.weather_master_app.core.model.weather.alerts.AlertResultType
import com.pranshulgg.weather_master_app.core.model.weather.alerts.AlertsDataPack
import com.pranshulgg.weather_master_app.core.model.weather.alerts.FinishedAlertsResult
import com.pranshulgg.weather_master_app.core.network.calls.safeApiCall
import com.pranshulgg.weather_master_app.core.network.sources.alerts.fpas.model.FpasCapAlert
import com.pranshulgg.weather_master_app.core.utils.locale.getCurrentAppLocale
import com.pranshulgg.weather_master_app.core.utils.weather.cache.shouldReturnAlertsCache
import com.pranshulgg.weather_master_app.data.local.dao.alerts.AlertsDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherContextDao
import com.pranshulgg.weather_master_app.data.local.mapper.alerts.sources.fpas.fpasAlertsMapper
import com.pranshulgg.weather_master_app.data.local.mapper.alerts.toDomain
import com.pranshulgg.weather_master_app.data.local.mapper.alerts.toEntity
import com.pranshulgg.weather_master_app.data.repository.alerts.AlertCacheModel
import com.pranshulgg.weather_master_app.data.repository.alerts.AlertRepository
import com.pranshulgg.weather_master_app.data.repository.capability.AirQualityCapability
import com.pranshulgg.weather_master_app.data.repository.capability.AlertCapability
import com.pranshulgg.weather_master_app.data.repository.capability.WeatherCapability
import com.pranshulgg.weather_master_app.data.repository.data.BaseRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.xmlpull.v1.XmlPullParser
import java.io.InputStream
import javax.inject.Inject
class FpasRepository @Inject constructor(
private val api: FpasApi,
private val dao: AlertsDao,
private val weatherContextDao: WeatherContextDao
) : BaseRepository() {
override val alertSource = Source.FPAS
override val weatherSource = Source.NONE
override val airQualitySource = Source.NONE
override fun alertCapability(): AlertCapability? {
return object : AlertCapability {
override suspend fun fetchAndProcess(
location: Location,
isManualRefresh: Boolean,
isForceRefresh: Boolean,
alertCacheModel: AlertCacheModel
): AlertsDataPack {
val response = safeApiCall {
api.fetchAlerts(
minLat = location.latitude - 0.1,
maxLat = location.latitude + 0.1,
minLon = location.longitude - 0.1,
maxLon = location.longitude + 0.1
)
}.getOrThrow()
val preferredLanguage = getCurrentAppLocale().language
val alerts = response.mapNotNull {
val responseAlert = api.fetchAlertsCap(it)
if (responseAlert.isSuccessful) {
responseAlert.body()?.byteStream()?.use { stream ->
parseAlertXmlBody(stream, preferredLanguage)
}
} else {
null
}
}
val domain = fpasAlertsMapper(alerts, location.id)
return AlertsDataPack(domain, location)
}
override suspend fun saveToDb(data: AlertsDataPack, alertCacheModel: AlertCacheModel) {
useGenericSaveImplementationForAlerts(data, alertsDao = dao, weatherContextDao)
}
override fun finishedResult(data: List<Alert>): FinishedAlertsResult {
return FinishedAlertsResult(alerts = data)
}
}
}
override fun weatherCapability(): WeatherCapability? = null
override fun airQualityCapability(): AirQualityCapability? = null
}
private fun parseAlertXmlBody(stream: InputStream, preferredLanguage: String): FpasCapAlert {
val parser = Xml.newPullParser()
parser.setInput(stream, null)
val infoBlocks = mutableListOf<FpasCapAlert>()
var type = parser.eventType
var language: String? = null
var event: String? = null
var severity: String? = null
var effective: String? = null
var expires: String? = null
var senderName: String? = null
var description: String? = null
var headline: String? = null
while (type != XmlPullParser.END_DOCUMENT) {
when (type) {
XmlPullParser.START_TAG -> {
when (parser.name) {
// a CAP alert can carry one <info> block per language; reset per block
// so fields from one language don't leak into another
"info" -> {
language = null
event = null
severity = null
effective = null
expires = null
senderName = null
description = null
headline = null
}
"language" -> language = parser.nextText()
"event" -> event = parser.nextText()
"severity" -> severity = parser.nextText()
"effective" -> effective = parser.nextText()
"expires" -> expires = parser.nextText()
"senderName" -> senderName = parser.nextText()
"description" -> description = parser.nextText()
"headline" -> headline = parser.nextText()
}
}
XmlPullParser.END_TAG -> {
if (parser.name == "info") {
infoBlocks += FpasCapAlert(
language = language,
event = event,
severity = severity,
effective = effective,
expires = expires,
senderName = senderName,
headline = headline,
description = description
)
}
}
}
type = parser.next()
}
return selectPreferredInfoBlock(infoBlocks, preferredLanguage)
}
private fun selectPreferredInfoBlock(
infoBlocks: List<FpasCapAlert>,
preferredLanguage: String
): FpasCapAlert {
return infoBlocks.firstOrNull {
it.language?.startsWith(
preferredLanguage,
ignoreCase = true
) == true
}
?: infoBlocks.firstOrNull { it.language?.startsWith("en", ignoreCase = true) == true }
?: infoBlocks.firstOrNull()
?: FpasCapAlert(
language = null,
event = null,
severity = null,
effective = null,
expires = null,
senderName = null,
headline = null,
description = null
)
}
@@ -0,0 +1,12 @@
package com.pranshulgg.weather_master_app.core.network.sources.alerts.fpas.model
data class FpasCapAlert(
val language: String?,
val event: String?,
val severity: String?,
val effective: String?,
val expires: String?,
val senderName: String?,
val headline: String?,
val description: String?
)
@@ -0,0 +1,55 @@
package com.pranshulgg.weather_master_app.core.network.sources.alerts.weatherapi
import com.pranshulgg.weather_master_app.BuildConfig
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query
import java.util.concurrent.TimeUnit
import com.pranshulgg.weather_master_app.core.network.sources.alerts.weatherapi.json.AlertsWeatherApiJson
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Response
interface AlertsWeatherApi {
@GET("alerts.json")
suspend fun fetchAlerts(
@Query("q") query: String
): Response<AlertsWeatherApiJson>
companion object {
const val BASE_URL = "https://api.weatherapi.com/v1/"
fun create(): AlertsWeatherApi {
val auth = Interceptor { chain ->
val original = chain.request()
val newUrl =
original.url.newBuilder()
.addQueryParameter("key", BuildConfig.WEATHERAPI_KEY)
.build()
val request = original.newBuilder().url(newUrl).build()
chain.proceed(request)
}
val client = OkHttpClient.Builder()
.addInterceptor(auth)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(AlertsWeatherApi::class.java)
}
}
}
@@ -0,0 +1,60 @@
package com.pranshulgg.weather_master_app.core.network.sources.alerts.weatherapi
import com.pranshulgg.weather_master_app.core.model.domain.alerts.Alert
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.core.model.sources.Source
import com.pranshulgg.weather_master_app.core.model.weather.alerts.AlertsDataPack
import com.pranshulgg.weather_master_app.core.model.weather.alerts.FinishedAlertsResult
import com.pranshulgg.weather_master_app.core.network.calls.safeApiCall
import com.pranshulgg.weather_master_app.data.local.dao.alerts.AlertsDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherContextDao
import com.pranshulgg.weather_master_app.data.local.mapper.alerts.sources.weatherapi.toDomain
import com.pranshulgg.weather_master_app.data.repository.alerts.AlertCacheModel
import com.pranshulgg.weather_master_app.data.repository.capability.AirQualityCapability
import com.pranshulgg.weather_master_app.data.repository.capability.AlertCapability
import com.pranshulgg.weather_master_app.data.repository.capability.WeatherCapability
import com.pranshulgg.weather_master_app.data.repository.data.BaseRepository
import javax.inject.Inject
class AlertsWeatherApiRepository @Inject constructor(
private val api: AlertsWeatherApi,
private val dao: AlertsDao,
private val weatherContextDao: WeatherContextDao
) : BaseRepository() {
override val alertSource = Source.WEATHER_API
override val weatherSource = Source.NONE
override val airQualitySource = Source.NONE
override fun alertCapability(): AlertCapability? {
return object : AlertCapability {
override suspend fun fetchAndProcess(
location: Location,
isManualRefresh: Boolean,
isForceRefresh: Boolean,
alertCacheModel: AlertCacheModel
): AlertsDataPack {
val response = safeApiCall {
api.fetchAlerts("${location.latitude},${location.longitude}")
}.getOrThrow()
val domain = response.toDomain(location.id)
return AlertsDataPack(domain, location)
}
override suspend fun saveToDb(data: AlertsDataPack, alertCacheModel: AlertCacheModel) {
useGenericSaveImplementationForAlerts(data, alertsDao = dao, weatherContextDao)
}
override fun finishedResult(data: List<Alert>): FinishedAlertsResult {
return FinishedAlertsResult(alerts = data)
}
}
}
override fun weatherCapability(): WeatherCapability? = null
override fun airQualityCapability(): AirQualityCapability? = null
}
@@ -0,0 +1,19 @@
package com.pranshulgg.weather_master_app.core.network.sources.alerts.weatherapi.json
data class AlertsWeatherApiJson(
val alerts: AlertsWeatherApiAlertJson
)
data class AlertsWeatherApiAlertJson(
val alert: List<AlertsWeatherApiAlertItemJson>
)
data class AlertsWeatherApiAlertItemJson(
val event: String,
val effective: String?,
val expires: String?,
val desc: String?,
val severity: String?,
val headline: String?
)
@@ -0,0 +1,51 @@
package com.pranshulgg.weather_master_app.core.network.sources.alerts.wmosevereweather
import com.pranshulgg.weather_master_app.core.network.sources.alerts.wmosevereweather.json.WmoSevereWeatherJson
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query
import java.util.concurrent.TimeUnit
interface WmoSevereWeatherApi {
@GET("f/wfs")
suspend fun fetchAlerts(
@Query("typeName") typeName: String = "local_postgis:postgis_geojsons",
@Query("cql_filter") cqlFilter: String,
@Query("version") version: String = "1.1.0",
@Query("outputFormat") outputFormat: String = "json",
@Query("request") request: String = "GetFeature",
): Response<WmoSevereWeatherJson>
@GET("v2/cap-alerts/{url}")
suspend fun fetchAlertsXml(
@Path(value = "url", encoded = true) url: String
): Response<ResponseBody>
companion object {
const val BASE_URL = "https://severeweather.wmo.int/"
fun create(): WmoSevereWeatherApi {
val client = OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(WmoSevereWeatherApi::class.java)
}
}
}
@@ -0,0 +1,145 @@
package com.pranshulgg.weather_master_app.core.network.sources.alerts.wmosevereweather
import android.util.Xml
import com.pranshulgg.weather_master_app.core.model.domain.AppException
import com.pranshulgg.weather_master_app.core.model.domain.alerts.Alert
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.core.model.sources.Source
import com.pranshulgg.weather_master_app.core.model.weather.alerts.AlertResult
import com.pranshulgg.weather_master_app.core.model.weather.alerts.AlertResultType
import com.pranshulgg.weather_master_app.core.model.weather.alerts.AlertsDataPack
import com.pranshulgg.weather_master_app.core.model.weather.alerts.FinishedAlertsResult
import com.pranshulgg.weather_master_app.core.network.calls.safeApiCall
import com.pranshulgg.weather_master_app.core.network.sources.alerts.wmosevereweather.model.WmoCapAlert
import com.pranshulgg.weather_master_app.core.utils.weather.cache.shouldReturnAlertsCache
import com.pranshulgg.weather_master_app.data.local.dao.alerts.AlertsDao
import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherContextDao
import com.pranshulgg.weather_master_app.data.local.mapper.alerts.sources.wmosevereweather.wmoSevereWeatherAlertsMapper
import com.pranshulgg.weather_master_app.data.local.mapper.alerts.toDomain
import com.pranshulgg.weather_master_app.data.local.mapper.alerts.toEntity
import com.pranshulgg.weather_master_app.data.repository.alerts.AlertCacheModel
import com.pranshulgg.weather_master_app.data.repository.alerts.AlertRepository
import com.pranshulgg.weather_master_app.data.repository.capability.AirQualityCapability
import com.pranshulgg.weather_master_app.data.repository.capability.AlertCapability
import com.pranshulgg.weather_master_app.data.repository.capability.WeatherCapability
import com.pranshulgg.weather_master_app.data.repository.data.BaseRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.xmlpull.v1.XmlPullParser
import java.io.InputStream
import javax.inject.Inject
class WmoSevereWeatherRepository @Inject constructor(
private val api: WmoSevereWeatherApi,
private val dao: AlertsDao,
private val weatherContextDao: WeatherContextDao
) : BaseRepository() {
override val alertSource = Source.WMO_SEVERE_WEATHER
override val weatherSource = Source.NONE
override val airQualitySource = Source.NONE
override fun alertCapability(): AlertCapability? {
return object : AlertCapability {
override suspend fun fetchAndProcess(
location: Location,
isManualRefresh: Boolean,
isForceRefresh: Boolean,
alertCacheModel: AlertCacheModel
): AlertsDataPack {
val cqlFilter =
"INTERSECTS(wkb_geometry, POINT (${location.latitude} ${location.longitude})) AND row_type NEQ 'BOUNDARY'"
val response = safeApiCall { api.fetchAlerts(cqlFilter = cqlFilter) }.getOrThrow()
val alertsWithCap = response.features.filter {
it.properties != null
}.map { feature ->
val url = feature.properties?.capUrl ?: feature.properties?.rLink
val capAlert = if (!url.isNullOrBlank()) {
val responseAlert = api.fetchAlertsXml(url)
if (responseAlert.isSuccessful) {
responseAlert.body()?.byteStream()?.use { stream ->
parseAlertXmlBody(stream)
}
} else {
null
}
} else {
null
}
feature to capAlert
}
val domain = wmoSevereWeatherAlertsMapper(alertsWithCap, location.id)
return AlertsDataPack(domain, location)
}
override suspend fun saveToDb(data: AlertsDataPack, alertCacheModel: AlertCacheModel) {
useGenericSaveImplementationForAlerts(data, dao, weatherContextDao)
}
override fun finishedResult(data: List<Alert>): FinishedAlertsResult {
return FinishedAlertsResult(alerts = data)
}
}
}
override fun weatherCapability(): WeatherCapability? = null
override fun airQualityCapability(): AirQualityCapability? = null
}
private fun parseAlertXmlBody(stream: InputStream): WmoCapAlert {
val parser = Xml.newPullParser()
parser.setInput(stream, null)
var type = parser.eventType
var language: String? = null
var event: String? = null
var severity: String? = null
var effective: String? = null
var expires: String? = null
var senderName: String? = null
var description: String? = null
var headline: String? = null
while (type != XmlPullParser.END_DOCUMENT) {
when (type) {
XmlPullParser.START_TAG -> {
when (parser.name) {
"language" -> language = parser.nextText()
"event" -> event = parser.nextText()
"severity" -> severity = parser.nextText()
"effective" -> effective = parser.nextText()
"expires" -> expires = parser.nextText()
"senderName" -> senderName = parser.nextText()
"description" -> description = parser.nextText()
"headline" -> headline = parser.nextText()
}
}
}
type = parser.next()
}
return WmoCapAlert(
language = language,
event = event,
severity = severity,
effective = effective,
expires = expires,
senderName = senderName,
headline = headline,
description = description
)
}
@@ -0,0 +1,23 @@
package com.pranshulgg.weather_master_app.core.network.sources.alerts.wmosevereweather.json
import com.google.gson.annotations.SerializedName
data class WmoSevereWeatherJson(
val features: List<WmoSevereWeatherFeatureJson>
)
data class WmoSevereWeatherFeatureJson(
val properties: WmoSevereWeatherFeaturePropertiesJson?
)
data class WmoSevereWeatherFeaturePropertiesJson(
@SerializedName("capurl") val capUrl: String?,
@SerializedName("rlink") val rLink: String?,
val description: String?,
val event: String?,
val effective: String?,
val expires: String?,
@SerializedName("s") val severity: Int?,
val headline: String?
)
@@ -0,0 +1,13 @@
package com.pranshulgg.weather_master_app.core.network.sources.alerts.wmosevereweather.model
data class WmoCapAlert(
val language: String?,
val event: String?,
val severity: String?,
val effective: String?,
val expires: String?,
val senderName: String?,
val headline: String?,
val description: String?
)
@@ -0,0 +1,58 @@
package com.pranshulgg.weather_master_app.core.network.sources.search.accu
import com.pranshulgg.weather_master_app.BuildConfig
import com.pranshulgg.weather_master_app.core.network.sources.search.accu.json.AccuSearchJson
import com.pranshulgg.weather_master_app.core.network.sources.search.geonames.json.GeoNamesSearchJson
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query
import java.util.concurrent.TimeUnit
interface AccuSearchApi {
@GET("locations/v1/cities/search.json")
suspend fun search(
@Query("q") query: String,
): Response<List<AccuSearchJson>>
companion object {
private const val BASE_URL = "https://api.accuweather.com/"
fun create(): AccuSearchApi {
val auth = Interceptor { chain ->
val original = chain.request()
val newUrl =
original.url.newBuilder().addQueryParameter("apikey", BuildConfig.ACCU_KEY)
.build()
val request = original.newBuilder().url(newUrl).build()
chain.proceed(request)
}
val client = OkHttpClient.Builder()
.addInterceptor(auth)
.callTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
.create(AccuSearchApi::class.java)
}
}
}
@@ -0,0 +1,24 @@
package com.pranshulgg.weather_master_app.core.network.sources.search.accu
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.data.local.mapper.locations.toDomain
import com.pranshulgg.weather_master_app.data.repository.data.SearchRepository
import javax.inject.Inject
class AccuSearchRepository @Inject constructor(
private val api: AccuSearchApi
) : SearchRepository {
override suspend fun search(query: String): List<Location> {
val response = api.search(query)
val body = response.body() ?: return emptyList()
val domain = body.toDomain()
return domain
}
}
@@ -0,0 +1,31 @@
package com.pranshulgg.weather_master_app.core.network.sources.search.accu.json
import com.google.gson.annotations.SerializedName
import kotlinx.serialization.Serializable
data class AccuSearchJson(
@SerializedName("EnglishName") val name: String,
@SerializedName("Country") val country: AccuSearchCountryJson,
@SerializedName("AdministrativeArea") val administrativeArea: AccuSearchAdministrativeAreaJson,
@SerializedName("TimeZone") val timezone: AccuSearchTimeZoneJson,
@SerializedName("GeoPosition") val geoPosition: AccuSearchGeoPositionJson
)
data class AccuSearchCountryJson(
@SerializedName("EnglishName") val name: String,
@SerializedName("ID") val countryCode: String
)
data class AccuSearchAdministrativeAreaJson(
@SerializedName("EnglishName") val name: String?
)
data class AccuSearchTimeZoneJson(
@SerializedName("Name") val name: String
)
data class AccuSearchGeoPositionJson(
@SerializedName("Latitude") val latitude: Double,
@SerializedName("Longitude") val longitude: Double
)
@@ -25,9 +25,6 @@ interface GeoNamesSearchApi {
private const val BASE_URL = "https://secure.geonames.org/"
fun create(): GeoNamesSearchApi {
val logging = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BASIC
}
val auth = Interceptor { chain ->
val original = chain.request()
@@ -40,7 +37,6 @@ interface GeoNamesSearchApi {
val client = OkHttpClient.Builder()
.addInterceptor(auth)
.addInterceptor(logging)
.callTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
@@ -2,7 +2,7 @@ package com.pranshulgg.weather_master_app.core.network.sources.search.geonames
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.data.local.mapper.locations.toDomain
import com.pranshulgg.weather_master_app.data.repository.SearchRepository
import com.pranshulgg.weather_master_app.data.repository.data.SearchRepository
import javax.inject.Inject
@@ -4,7 +4,7 @@ import com.google.gson.annotations.SerializedName
data class GeoNamesSearchJson(
val geonames: List<GeoNamesSearchItemJson>
val geonames: List<GeoNamesSearchItemJson>?
)
data class GeoNamesSearchItemJson(
@@ -15,7 +15,7 @@ data class GeoNamesSearchItemJson(
val longitude: Double,
val name: String,
val countryName: String,
val countryName: String?,
@SerializedName("countryCode")
val countryCode: String,
@@ -26,9 +26,6 @@ interface GeoNamesTimezoneApi {
private const val BASE_URL = "https://secure.geonames.org/"
fun create(): GeoNamesTimezoneApi {
val logging = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BASIC
}
val auth = Interceptor { chain ->
val original = chain.request()
@@ -41,7 +38,6 @@ interface GeoNamesTimezoneApi {
val client = OkHttpClient.Builder()
.addInterceptor(auth)
.addInterceptor(logging)
.callTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
@@ -23,12 +23,8 @@ interface OpenMeteoSearchApi {
private const val BASE_URL = "https://geocoding-api.open-meteo.com/v1/"
fun create(): OpenMeteoSearchApi {
val logging = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BASIC
}
val client = OkHttpClient.Builder()
.addInterceptor(logging)
.callTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
@@ -2,7 +2,7 @@ package com.pranshulgg.weather_master_app.core.network.sources.search.openmeteo
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.data.local.mapper.locations.toDomain
import com.pranshulgg.weather_master_app.data.repository.SearchRepository
import com.pranshulgg.weather_master_app.data.repository.data.SearchRepository
import javax.inject.Inject
class OpenMeteoSearchRepository @Inject constructor(
Loaded 100 of 679 files, more files were not shown because too many files have changed in this diff. Show more