Merge branch 'main' into l10n_main

Signed-off-by: Pranshul <pranshul.devmain@gmail.com>
This commit is contained in:
Pranshul authored and GitHub committed 2026-07-24 20:43:14 +05:30
commit 90ea267a0e
24 files changed
+2444 -28

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
@@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 46,
"identityHash": "b2ca5c75db987a1d27628fc45eac72bf",
"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, PRIMARY KEY(`id`))",
"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",
@@ -83,6 +83,18 @@
"columnName": "isDeviceLocation",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "alertSource",
"columnName": "alertSource",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "airQualitySource",
"columnName": "airQualitySource",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
@@ -845,7 +857,7 @@
],
"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')"
"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')"
]
}
}
@@ -1,5 +1,7 @@
package com.pranshulgg.weather_master_app.core.model.domain.location
import com.pranshulgg.weather_master_app.core.model.sources.AirQualitySource
import com.pranshulgg.weather_master_app.core.model.sources.AlertSource
import com.pranshulgg.weather_master_app.core.model.sources.WeatherSource
data class Location(
@@ -15,5 +17,8 @@ data class Location(
val isFavorite: Boolean = false,
val isPinned: Boolean = false,
val isDefault: Boolean,
val isDeviceLocation: Boolean = false
val isDeviceLocation: Boolean = false,
val alertSource: AlertSource = AlertSource.NONE,
val airQualitySource: AirQualitySource = AirQualitySource.OPEN_METEO,
val customName: String? = null
)
@@ -0,0 +1,21 @@
package com.pranshulgg.weather_master_app.core.model.sources
enum class AirQualitySource(
val displayName: String,
val displayLink: String,
val fullName: String
) {
NONE(displayName = "None", fullName = "", displayLink = ""),
ACCU_WEATHER(
displayName = "AccuWeather",
fullName = "AccuWeather",
displayLink = "https://www.accuweather.com/"
),
OPEN_METEO(
displayName = "Open Meteo",
fullName = "Open Meteo",
displayLink = "https://open-meteo.com/"
),
}
@@ -0,0 +1,22 @@
package com.pranshulgg.weather_master_app.core.model.sources
enum class AlertSource(
val displayName: String,
val displayLink: String,
val fullName: String
) {
NONE(displayName = "None", fullName = "", displayLink = ""),
ACCU_WEATHER(
displayName = "AccuWeather",
fullName = "AccuWeather",
displayLink = "https://www.accuweather.com/"
),
WEATHER_API(
displayName = "WeatherApi",
fullName = "WeatherApi.com",
displayLink = "https://www.weatherapi.com/"
),
}
@@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FabPosition
import androidx.compose.material3.LargeFlexibleTopAppBar
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
@@ -24,6 +25,7 @@ fun LargeTopBarScaffold(
fab: @Composable () -> Unit = {},
bottomBar: @Composable (() -> Unit) = {},
defaultCollapsed: Boolean = false,
floatingActionButtonPosition: FabPosition = FabPosition.End,
content: @Composable (PaddingValues) -> Unit,
) {
@@ -43,6 +45,7 @@ fun LargeTopBarScaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
containerColor = MaterialTheme.colorScheme.surfaceContainer,
floatingActionButton = fab,
floatingActionButtonPosition = floatingActionButtonPosition,
topBar = {
LargeFlexibleTopAppBar(
title = { Text(text = title) },
@@ -92,7 +92,9 @@ sealed class SettingTile {
val onTextSubmitted: (String) -> Unit,
val placeholder: String,
val placeholderTextField: String,
val initialText: String = ""
val initialText: String = "",
val trailing: (@Composable (() -> Unit))? = null,
val placeholderAsValue: Boolean = false
) : SettingTile()
data class DialogSliderTile(
@@ -247,7 +249,9 @@ fun SettingSection(
placeholder = tile.placeholder,
placeholderTextField = tile.placeholderTextField,
initialText = tile.initialText,
itemBgColor = itemBgColor
itemBgColor = itemBgColor,
trailing = tile.trailing,
placeholderAsValue = tile.placeholderAsValue
)
is SettingTile.DialogSliderTile -> DialogSliderTile(
@@ -20,7 +20,9 @@ fun DialogTextFieldTile(
placeholder: String,
placeholderTextField: String,
shapes: RoundedCornerShape,
itemBgColor: Color
itemBgColor: Color,
trailing: (@Composable (() -> Unit))? = null,
placeholderAsValue: Boolean = false
) {
var showDialog by remember { mutableStateOf(false) }
var textFieldValue by remember { mutableStateOf(initialText) }
@@ -37,17 +39,21 @@ fun DialogTextFieldTile(
leadingContent = leading,
headlineContent = { Text(headline) },
supportingContent = {
if (description != null) Text(description)
if (description != null) Text(
description,
color = if (placeholderAsValue) MaterialTheme.colorScheme.tertiary else Color.Unspecified
)
else if (textFieldValue.isNotEmpty()) Text(
textFieldValue,
color = MaterialTheme.colorScheme.tertiary
) else {
Text(
placeholder,
color = MaterialTheme.colorScheme.onSurfaceVariant
color = if (placeholderAsValue) MaterialTheme.colorScheme.tertiary else MaterialTheme.colorScheme.onSurfaceVariant
)
}
},
trailingContent = trailing
)
}
@@ -21,16 +21,17 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.navigation
import androidx.navigation.navArgument
import com.pranshulgg.weather_master_app.feature.blocks.screens.humidity.HumidityScreen
import com.pranshulgg.weather_master_app.feature.blocks.screens.pressure.PressureScreen
import com.pranshulgg.weather_master_app.feature.blocks.screens.SunMoonScreen
import com.pranshulgg.weather_master_app.feature.blocks.screens.airquality.AirQualityScreen
import com.pranshulgg.weather_master_app.feature.blocks.screens.humidity.HumidityScreen
import com.pranshulgg.weather_master_app.feature.blocks.screens.precipitation.RainScreen
import com.pranshulgg.weather_master_app.feature.blocks.screens.precipitation.SnowScreen
import com.pranshulgg.weather_master_app.feature.blocks.screens.pressure.PressureScreen
import com.pranshulgg.weather_master_app.feature.blocks.screens.uvindex.UvIndexScreen
import com.pranshulgg.weather_master_app.feature.blocks.screens.visibility.VisibilityScreen
import com.pranshulgg.weather_master_app.feature.blocks.screens.wind.WindScreen
import com.pranshulgg.weather_master_app.feature.daily.DailyScreen
import com.pranshulgg.weather_master_app.feature.editlocation.EditLocationScreen
import com.pranshulgg.weather_master_app.feature.main.MainScreen
import com.pranshulgg.weather_master_app.feature.search.SearchScreen
import com.pranshulgg.weather_master_app.feature.settings.SettingsScreen
@@ -66,12 +67,8 @@ fun AppNavHost(
) {
navigation(
route = "root",
startDestination = NavRoutes.MAIN
// startDestination = NavRoutes.blockScreen(
// NavRoutes.AIR_QUALITY,
// 0,
// "ab73f0ac-0dd9-410b-aa85-c944abfdcf60"
// )
// startDestination = NavRoutes.MAIN
startDestination = NavRoutes.editLocation("af673c89-72b7-4da9-865d-c26fdabeca07")
) {
composable(
NavRoutes.MAIN
@@ -156,6 +153,19 @@ fun AppNavHost(
) {
WorkerInfoScreen(navController)
}
composable(
route = "${NavRoutes.EDIT_LOCATION}/{locationId}",
arguments = listOf(
navArgument("locationId") {
type = NavType.StringType
}
)
) { backStackEntry ->
val locationId = backStackEntry.arguments?.getString("locationId")
EditLocationScreen(navController, locationId!!)
}
composable(
route = "{block}/{index}/{locationId}",
arguments = listOf(
@@ -45,6 +45,12 @@ object NavRoutes {
const val WORKER_INFO = "worker_info"
const val EDIT_LOCATION = "edit_location"
fun editLocation(locationId: String): String {
return "$EDIT_LOCATION/$locationId"
}
fun blockScreen(block: String, index: Int, locationId: String): String {
return "$block/$index/$locationId"
}
@@ -38,12 +38,13 @@ import com.pranshulgg.weather_master_app.data.local.entity.weather.nws.NwsGridPo
GithubEntity::class,
HourlyAirQualityEntity::class
],
version = 46,
version = 48,
autoMigrations = [
AutoMigration(from = 39, to = 40),
AutoMigration(from = 42, to = 43),
AutoMigration(from = 43, to = 44),
AutoMigration(from = 44, to = 45)
AutoMigration(from = 44, to = 45),
AutoMigration(from = 47, to = 48)
]
)
abstract class WeatherMasterDatabase : RoomDatabase() {
@@ -67,7 +68,8 @@ abstract class WeatherMasterDatabase : RoomDatabase() {
context.applicationContext,
WeatherMasterDatabase::class.java,
"weather_master.db"
).addMigrations(MIGRATION_40_41, MIGRATION_41_42, MIGRATION_45_46).build()
).addMigrations(MIGRATION_40_41, MIGRATION_41_42, MIGRATION_45_46, MIGRATION_46_47)
.build()
.also { INSTANCE = it }
}
}
@@ -144,4 +146,11 @@ val MIGRATION_45_46 = object : Migration(45, 46) {
"CREATE INDEX IF NOT EXISTS index_air_quality_hourly_locationId ON air_quality_hourly(locationId)"
)
}
}
val MIGRATION_46_47 = object : Migration(46, 47) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE weather_locations ADD COLUMN alertSource TEXT NOT NULL DEFAULT 'NONE'")
db.execSQL("ALTER TABLE weather_locations ADD COLUMN airQualitySource TEXT NOT NULL DEFAULT 'OPEN_METEO'")
}
}
@@ -5,6 +5,7 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import com.pranshulgg.weather_master_app.core.model.sources.AirQualitySource
import com.pranshulgg.weather_master_app.core.model.sources.WeatherSource
import com.pranshulgg.weather_master_app.data.local.entity.location.WeatherLocationEntity
import com.pranshulgg.weather_master_app.data.local.entity.weather.WeatherWithRelations
@@ -72,4 +73,10 @@ interface LocationsDao {
@Query("SELECT * FROM weather_locations WHERE isDeviceLocation = 1 LIMIT 1")
suspend fun getDeviceLocation(): WeatherLocationEntity
@Query("SELECT * FROM weather_locations WHERE id = :id LIMIT 1")
suspend fun getLocationForId(id: String): WeatherLocationEntity
@Query("UPDATE weather_locations SET airQualitySource = :source WHERE id = :id")
suspend fun updateAirQualitySourceForLocation(id: String, source: AirQualitySource)
}
@@ -2,6 +2,8 @@ package com.pranshulgg.weather_master_app.data.local.entity.location
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.pranshulgg.weather_master_app.core.model.sources.AirQualitySource
import com.pranshulgg.weather_master_app.core.model.sources.AlertSource
import com.pranshulgg.weather_master_app.core.model.sources.WeatherSource
import kotlin.uuid.ExperimentalUuidApi
@@ -22,6 +24,8 @@ data class WeatherLocationEntity(
val isPinned: Boolean = false,
val countryCode: String? = null,
val isDefault: Boolean = false,
val isDeviceLocation: Boolean = false
val isDeviceLocation: Boolean = false,
val alertSource: AlertSource,
val airQualitySource: AirQualitySource,
val customName: String? = null
)
@@ -66,7 +66,10 @@ fun Location.toEntity(): WeatherLocationEntity =
isPinned = false,
isFavorite = false,
isDefault = isDefault,
isDeviceLocation = isDeviceLocation
isDeviceLocation = isDeviceLocation,
alertSource = alertSource,
airQualitySource = airQualitySource,
customName = customName
)
fun List<WeatherLocationEntity>.toDomain(): List<Location> =
@@ -88,5 +91,8 @@ fun WeatherLocationEntity.toDomain(): Location =
isFavorite = isFavorite,
isPinned = isPinned,
isDefault = isDefault,
isDeviceLocation = isDeviceLocation
isDeviceLocation = isDeviceLocation,
alertSource = alertSource,
airQualitySource = airQualitySource,
customName = customName
)
@@ -7,6 +7,7 @@ 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.domain.weather.Weather
import com.pranshulgg.weather_master_app.core.model.sources.AirQualitySource
import com.pranshulgg.weather_master_app.core.model.sources.WeatherSource
import com.pranshulgg.weather_master_app.core.network.sources.address.nominatim.json.NominatimRepository
import com.pranshulgg.weather_master_app.data.local.dao.airquality.AirQualityDao
@@ -74,6 +75,14 @@ class LocationsRepository @Inject constructor(
dao.updateSourceForLocation(id, source)
}
suspend fun updateAirQualitySourceForLocation(id: String, source: AirQualitySource) {
dao.updateAirQualitySourceForLocation(id, source)
}
suspend fun getLocationForId(id: String): Location {
return dao.getLocationForId(id).toDomain()
}
@Transaction
suspend fun saveLocation(location: Location) {
@@ -0,0 +1,256 @@
package com.pranshulgg.weather_master_app.feature.editlocation
import android.util.Log
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FabPosition
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SheetValue
import androidx.compose.material3.Text
import androidx.compose.material3.rememberBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.navigation.NavController
import com.pranshulgg.weather_master_app.R
import com.pranshulgg.weather_master_app.core.model.domain.location.Location
import com.pranshulgg.weather_master_app.core.model.sources.AirQualitySource
import com.pranshulgg.weather_master_app.core.model.sources.AlertSource
import com.pranshulgg.weather_master_app.core.model.sources.WeatherSource
import com.pranshulgg.weather_master_app.core.model.sources.getWeatherSourcesForCountry
import com.pranshulgg.weather_master_app.core.model.sources.getWeatherSourcesGlobal
import com.pranshulgg.weather_master_app.core.ui.components.Gap
import com.pranshulgg.weather_master_app.core.ui.components.LargeTopBarScaffold
import com.pranshulgg.weather_master_app.core.ui.components.NavigateUpBtn
import com.pranshulgg.weather_master_app.core.ui.components.SettingSection
import com.pranshulgg.weather_master_app.core.ui.components.SettingTile
import com.pranshulgg.weather_master_app.core.ui.components.Symbol
import com.pranshulgg.weather_master_app.feature.editlocation.ui.EditLocationBottomSheet
import com.pranshulgg.weather_master_app.feature.shared.ui.SharedBottomSheet
data class EditLocationScreenUiState(
val location: Location? = null,
val isWeatherSourcesForLocationSheetOpen: Boolean = false,
val selectedWeatherSource: WeatherSource? = null,
val selectedAlertSource: AlertSource? = null,
val selectedAirQualitySource: AirQualitySource? = null,
val isAlertSourcesSheetOpen: Boolean = false,
val isAirQualitySourcesSheetOpen: Boolean = false,
val isEditLocationNameSheetOpen: Boolean = false
)
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
@Composable
fun EditLocationScreen(
navController: NavController, id: String
) {
val viewModel: EditLocationViewModel = hiltViewModel()
val uiState = viewModel.uiState.value
LaunchedEffect(Unit) {
viewModel.getLocationForId(id)
}
if (uiState.location == null) return
val btnSize = ButtonDefaults.MediumContainerHeight
val sheetState = rememberBottomSheetState(
initialValue = SheetValue.Hidden,
enabledValues = setOf(SheetValue.Expanded, SheetValue.Hidden)
)
val colorDesc = MaterialTheme.colorScheme.tertiary
val locationText = buildString {
append(uiState.location.name)
if (uiState.location.country.isNotBlank()) {
append(", ")
}
if (uiState.location.state.isNotBlank()) {
append(uiState.location.state)
append(", ")
}
append(uiState.location.country)
}
val locationName = if (!uiState.location.customName.isNullOrBlank()) uiState.location.customName
else locationText
var currentLocationName by remember { mutableStateOf(locationName) }
LargeTopBarScaffold(
title = stringResource(R.string.location_edit),
navigationIcon = { NavigateUpBtn(navController) },
floatingActionButtonPosition = FabPosition.Center,
) { paddingValues ->
Column(
modifier =
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(top = paddingValues.calculateTopPadding())
) {
SettingSection(
tiles = listOf(
SettingTile.ActionTile(
title = "Location name",
description = currentLocationName,
onClick = {
viewModel.showEditLocationNameSheet()
},
trailing = {
IconButton(onClick = { currentLocationName = locationName }) {
Symbol(R.drawable.refresh_24px)
}
},
colorDesc = colorDesc
)
)
)
Gap(10.dp)
SettingSection(
tiles = listOf(
SettingTile.ActionTile(
title = "Weather source",
description = uiState.selectedWeatherSource?.displayName
?: uiState.location.source.displayName,
colorDesc = colorDesc,
onClick = {
viewModel.showWeatherSourcesForLocationSheet()
}
),
SettingTile.ActionTile(
title = "Alert source",
description = uiState.selectedAlertSource?.displayName
?: uiState.location.alertSource.displayName,
colorDesc = colorDesc,
onClick = {
viewModel.showAlertSourcesSheet()
}
),
SettingTile.ActionTile(
title = "Air quality source",
description = uiState.selectedAirQualitySource?.displayName
?: uiState.location.airQualitySource.displayName,
colorDesc = colorDesc,
onClick = {
viewModel.showAirQualitySourcesSheet()
}
)
)
)
Text(
"Latitude: ${uiState.location.latitude}, Longitude: ${uiState.location.longitude}",
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 10.dp, start = 16.dp, end = 16.dp)
)
Gap(26.dp)
Button(
modifier = Modifier
.heightIn(btnSize)
.fillMaxWidth()
.padding(horizontal = 16.dp),
onClick = { /* Handle click */ },
shapes = ButtonDefaults.shapes(),
contentPadding = ButtonDefaults.contentPaddingFor(btnSize),
) {
Symbol(
R.drawable.check_24px,
color = MaterialTheme.colorScheme.onPrimaryContainer,
size = ButtonDefaults.iconSizeFor(btnSize)
)
Gap(horizontal = ButtonDefaults.iconSpacingFor(btnSize))
Text(
stringResource(R.string.action_save_changes),
style = ButtonDefaults.textStyleFor(btnSize),
color = MaterialTheme.colorScheme.onPrimaryContainer
)
}
// WEATHER SOURCES SHEET
SharedBottomSheet.WeatherSourcesForLocationSheet(
countryCode = uiState.location.countryCode,
show = uiState.isWeatherSourcesForLocationSheetOpen,
isEditing = true,
selectedSource = uiState.selectedWeatherSource ?: uiState.location.source,
onSave = {
viewModel.updateSelectedWeatherSource(it)
},
onDismiss = viewModel::hideWeatherSourcesForLocationSheet,
sheetState = sheetState
)
// ALERT SOURCES SHEET
EditLocationBottomSheet.AlertSourcesSheet(
show = uiState.isAlertSourcesSheetOpen,
sheetState = sheetState,
selectedSource = uiState.selectedAlertSource ?: uiState.location.alertSource,
onSave = {
viewModel.updateSelectedAlertSource(it)
},
onDismiss = viewModel::hideAlertSourcesSheet
)
// AIR QUALITY SOURCES SHEET
EditLocationBottomSheet.AirQualitySourcesSheet(
show = uiState.isAirQualitySourcesSheetOpen,
sheetState = sheetState,
selectedSource = uiState.selectedAirQualitySource
?: uiState.location.airQualitySource,
onSave = {
viewModel.updateSelectedAirQualitySource(it)
},
onDismiss = viewModel::hideAirQualitySourcesSheet
)
// EDIT LOCATION NAME SHEET
EditLocationBottomSheet.EditLocationNameSheet(
show = uiState.isEditLocationNameSheetOpen,
sheetState = sheetState,
onDismiss = {
viewModel.hideEditLocationNameSheet()
},
onSave = {
if (it.isNotBlank()) {
currentLocationName = it
}
},
value = currentLocationName,
)
Gap(WindowInsets.systemBars.asPaddingValues().calculateBottomPadding())
}
}
}
@@ -0,0 +1,77 @@
package com.pranshulgg.weather_master_app.feature.editlocation
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pranshulgg.weather_master_app.R
import com.pranshulgg.weather_master_app.core.model.sources.AirQualitySource
import com.pranshulgg.weather_master_app.core.model.sources.AlertSource
import com.pranshulgg.weather_master_app.core.model.sources.WeatherSource
import com.pranshulgg.weather_master_app.core.ui.snackbar.SnackbarManager
import com.pranshulgg.weather_master_app.data.repository.LocationsRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class EditLocationViewModel @Inject constructor(
private val locationsRepo: LocationsRepository,
) : ViewModel() {
private var _uiState = mutableStateOf(EditLocationScreenUiState())
val uiState: State<EditLocationScreenUiState> = _uiState
fun getLocationForId(id: String) {
viewModelScope.launch {
val location = locationsRepo.getLocationForId(id)
_uiState.value = _uiState.value.copy(location = location)
}
}
fun showWeatherSourcesForLocationSheet() {
_uiState.value = _uiState.value.copy(isWeatherSourcesForLocationSheetOpen = true)
}
fun hideWeatherSourcesForLocationSheet() {
_uiState.value = _uiState.value.copy(isWeatherSourcesForLocationSheetOpen = false)
}
fun updateSelectedWeatherSource(source: WeatherSource) {
_uiState.value = _uiState.value.copy(selectedWeatherSource = source)
}
fun updateSelectedAlertSource(source: AlertSource) {
_uiState.value = _uiState.value.copy(selectedAlertSource = source)
}
fun updateSelectedAirQualitySource(source: AirQualitySource) {
_uiState.value = _uiState.value.copy(selectedAirQualitySource = source)
}
fun showAlertSourcesSheet() {
_uiState.value = _uiState.value.copy(isAlertSourcesSheetOpen = true)
}
fun hideAlertSourcesSheet() {
_uiState.value = _uiState.value.copy(isAlertSourcesSheetOpen = false)
}
fun showAirQualitySourcesSheet() {
_uiState.value = _uiState.value.copy(isAirQualitySourcesSheetOpen = true)
}
fun hideAirQualitySourcesSheet() {
_uiState.value = _uiState.value.copy(isAirQualitySourcesSheetOpen = false)
}
fun showEditLocationNameSheet() {
_uiState.value = _uiState.value.copy(isEditLocationNameSheetOpen = true)
}
fun hideEditLocationNameSheet() {
_uiState.value = _uiState.value.copy(isEditLocationNameSheetOpen = false)
}
}
@@ -0,0 +1,167 @@
package com.pranshulgg.weather_master_app.feature.editlocation.ui
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.SheetState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.pranshulgg.weather_master_app.R
import com.pranshulgg.weather_master_app.core.model.sources.AirQualitySource
import com.pranshulgg.weather_master_app.core.model.sources.AlertSource
import com.pranshulgg.weather_master_app.core.model.sources.WeatherSource
import com.pranshulgg.weather_master_app.core.model.sources.getWeatherSourcesForCountry
import com.pranshulgg.weather_master_app.core.model.sources.getWeatherSourcesGlobal
import com.pranshulgg.weather_master_app.core.ui.components.ActionBottomSheet
import com.pranshulgg.weather_master_app.core.ui.components.Gap
import com.pranshulgg.weather_master_app.core.ui.components.SettingSection
import com.pranshulgg.weather_master_app.core.ui.components.SettingTile
import com.pranshulgg.weather_master_app.core.ui.components.Symbol
object EditLocationBottomSheet {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EditLocationNameSheet(
show: Boolean,
sheetState: SheetState,
onDismiss: () -> Unit,
onSave: (String) -> Unit,
value: String
) {
if (show) {
var currentText by remember { mutableStateOf(value) }
ActionBottomSheet(
sheetState = sheetState,
onCancel = { onDismiss() },
onConfirm = { onSave(currentText) },
confirmText = stringResource(R.string.action_save),
cancelText = stringResource(R.string.action_cancel)
) {
OutlinedTextField(
value = currentText,
onValueChange = { currentText = it },
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
placeholder = { Text("Name") },
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AlertSourcesSheet(
show: Boolean,
sheetState: SheetState,
selectedSource: AlertSource = AlertSource.NONE,
onSave: (AlertSource) -> Unit,
onDismiss: () -> Unit
) {
if (show) {
var currentSelectedSource by remember(
show,
selectedSource
) {
mutableStateOf(selectedSource)
}
ActionBottomSheet(
sheetState = sheetState,
onCancel = { onDismiss() },
onConfirm = { onSave(currentSelectedSource) },
confirmText = stringResource(R.string.action_save),
cancelText = stringResource(R.string.action_cancel)
) {
SettingSection(
title = stringResource(R.string.global_sources),
tiles = AlertSource.entries.map { source ->
val isSelected = currentSelectedSource == source
SettingTile.ActionTile(
leading = {
if (isSelected) Symbol(
R.drawable.check_24px,
color = MaterialTheme.colorScheme.onSecondaryContainer
)
},
title = source.displayName,
selected = isSelected,
onClick = {
currentSelectedSource = source
}
)
}
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AirQualitySourcesSheet(
show: Boolean,
sheetState: SheetState,
selectedSource: AirQualitySource = AirQualitySource.OPEN_METEO,
onSave: (AirQualitySource) -> Unit,
onDismiss: () -> Unit
) {
if (show) {
var currentSelectedSource by remember(
show,
selectedSource
) {
mutableStateOf(selectedSource)
}
ActionBottomSheet(
sheetState = sheetState,
onCancel = { onDismiss() },
onConfirm = { onSave(currentSelectedSource) },
confirmText = stringResource(R.string.action_save),
cancelText = stringResource(R.string.action_cancel)
) {
SettingSection(
title = stringResource(R.string.global_sources),
tiles = AirQualitySource.entries.map { source ->
val isSelected = currentSelectedSource == source
SettingTile.ActionTile(
leading = {
if (isSelected) Symbol(
R.drawable.check_24px,
color = MaterialTheme.colorScheme.onSecondaryContainer
)
},
title = source.displayName,
selected = isSelected,
onClick = {
currentSelectedSource = source
}
)
}
)
}
}
}
}
@@ -173,13 +173,13 @@ private fun UseDeviceLocationCard(onClick: () -> Unit, isLoading: Boolean = fals
},
headlineContent = {
Text(
"Use current location",
stringResource(R.string.location_use_current),
color = MaterialTheme.colorScheme.onSurface
)
},
supportingContent = {
Text(
"Detect your device’s current location automatically and add it to your list",
stringResource(R.string.location_use_current_secondary),
color = MaterialTheme.colorScheme.onSurfaceVariant
)
},
@@ -10,6 +10,7 @@ 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.domain.toMessageRes
import com.pranshulgg.weather_master_app.core.model.domain.weather.WeatherBlock
import com.pranshulgg.weather_master_app.core.model.sources.AirQualitySource
import com.pranshulgg.weather_master_app.core.model.sources.WeatherSource
import com.pranshulgg.weather_master_app.core.model.sources.isGlobal
import com.pranshulgg.weather_master_app.core.model.sources.isSourceSupportedFor
@@ -106,7 +107,8 @@ class WeatherViewModel @Inject constructor(
location: Location,
source: WeatherSource,
isManualRefresh: Boolean = false,
isForceRefresh: Boolean = false
isForceRefresh: Boolean = false,
isForceRefreshForAirQuality: Boolean = false
) {
setLoading(true)
weatherJob?.cancel()
@@ -190,6 +192,40 @@ class WeatherViewModel @Inject constructor(
}
private fun handleSourceChangeForWeather(
location: Location,
source: WeatherSource,
airQualitySource: AirQualitySource,
) {
val updatedLocation = location.copy(source = source, airQualitySource = airQualitySource)
viewModelScope.launch {
locationsRepo.updateSourceForLocation(location.id, source)
locationsRepo.updateAirQualitySourceForLocation(location.id, airQualitySource)
val allowForceRefreshForWeather = location.source != source
val allowForceRefreshForAirQuality = location.airQualitySource != airQualitySource
if (allowForceRefreshForWeather) {
weatherDataReconcilerRepository.cleanUpStaleData(location.source, location.id)
}
_uiState.value = _uiState.value.copy(
activeLocation = updatedLocation
)
getWeather(
updatedLocation,
source,
isForceRefresh = allowForceRefreshForWeather,
isForceRefreshForAirQuality = allowForceRefreshForAirQuality
)
}
}
fun saveBlocks(
items: List<WeatherBlock>,
isDaily: Boolean = false
+1 -1
View File
@@ -35,7 +35,7 @@
<item quantity="other">%d tuntia sitten</item>
</plurals>
<plurals name="time_days_ago">
<item quantity="one">% päivä sitten</item>
<item quantity="one">%d päivä sitten</item>
<item quantity="other">%d päivää sitten</item>
</plurals>
<string name="time_just_now">Juuri nyt</string>
+21
View File
@@ -360,6 +360,27 @@
<string name="summary_overview_template_night_condition">Conditions will turn %1$s at night.</string>
<string name="gadgetbridge_not_available_error">Gadget bridge is not installed</string>
<string name="settings_worker_info">Worker information</string>
<string name="settings_send_data_gadgetbridge">Send data to Gadgetbridge</string>
<string name="aqi_PM25_full_label">Particulate matter less than 2.5 microns</string>
<string name="aqi_PM10_full_label">Particulate matter less than 10 microns</string>
<string name="aqi_CO_full_label">Carbon monoxide</string>
<string name="aqi_NO2_full_label">Nitrogen Dioxide</string>
<string name="aqi_SO2_full_label">Sulfur Dioxide</string>
<string name="aqi_O3_full_label">Ground surface</string>
<string name="settings_worker_info_successful_run">Last successful run</string>
<string name="label_never">Never</string>
<string name="worker_run_attempt">Run attempt</string>
<string name="worker_tags">Tags</string>
<string name="worker_next_schedule">Next schedule</string>
<string name="action_save_changes">Save changes</string>
<string name="weather_alert_source">Alert source</string>
<string name="location_edit">Edit location</string>
<string name="weather_aqi_source">Air quality source</string>
<string name="location_name">Location name</string>
<string name="location_info">Location information</string>
</resources>
<!--<string name=""></string>-->