Add support for location plugins (#772)
* Cherry pick location refactor * Refactor :data:openstreetmaps to :data:locations * contract, plugin sdk * Implement serialization, module tweaks * Include check for out-of-date departures in SearchableItemVM.requestUpdatedSearchable() * settings for location plugins * Try not to be too lazy * more fiddling with the plugin SDK * add departures in MapView with mock data for debug builds * change icons * add boats * animate departure lazycolumn * Add MarqueeText for text overflow handling * Define height for Departures in case there is no map to display * Don't inclure railway / highway tags for OSM since there will be location plugins for that * sort by time * - Apply pre-merge changes to LocationSettings - Add banner warning about slowed down location search for large search radii * ditch `showLocationOnMap` * LocationItem: make `showOpeningSchedule` toggleable * LocationItem: make Navigation AssistChip work for people that don't have google maps installed * LocationItem: resolve TODOs * MapTiles: ditch unused code, animate userIndicator * Reintroduce departure list * Add LineColor * Add osm tag `stars` as `userRating` https://taginfo.openstreetmap.org/keys/stars#overview * typealias -> import * Don't add Navigation Chip when there is no way to resolve navigation intents * Add settings migration * Set plugin SDK version to 1.2.0-SNAPSHOT * Deduplicate shared plugin classes, use kotlinx.serialization * Fix imports * Use ZonedDateTime for depature times * Add more line types * Rewrite location serialization * Replace street/houseNumber with address * Add attribution field * Add plugin config * Reject location search requests without lat lon parameters * Add default values to plugin location class * Don't crash if column value is null * Add docs comments to LocationCategory values * Refactor OpeningSchedule as polymorphic * remove dead corpse *ahem* code * Split LocationCategory into category and icon (Also update to Kotlin 2.0, please don't do this at home) * Add more location icons * Fix (?) location deserializer * Add more location icons * More icons * Meh * Add Pub * Disable Github Maven repo if credentials are missing * Add location search specific settings to plugin details screen * Add language parameter * Unbreak the build * Refactor plugin SDK (with breaking changes) * Set plugin SDK version to 2.0.0-SNAPSHOT * Document SDK breaking changes * Implement LocationProvider.getQuery * Add a typesafe cursor API * Oops I did it again next time maybe check if the code is actually compiling before pushing * Add missing return statement * Fix list serialization * Departure time UI adjustment * Use typesafe cursor for weather plugins * Add userRatingCount and emailAddress fields * grrr * Rename and extend LineTypes * Add default lineType to Departure to fix serialization errors * Fix refreshing stored plugin locations * Adapt line name column width to available departures * Fix plugin settings screen category overlap * add LocationItem.GenericTransit * Fix crash during deserialization of locations * Update SDK docs * Replace plugin "official" mark with "verified developer" mark before anyone gets sued * show 'now' when departure is in less than one minute * Add typesafe Bundle API * Implement plugin API changes * Plugin SDK: Fix refresh result not being returned * Update docs * apply alpha to departures that have departured * better (maybe): reduce saturation instead of alpha * Add default values for Attribution * Display attribution * Rearrange location result layout * Reduce searchable update interval to 1 minute * Pass last update time to refresh function * Change refresh path and ensure that timestamp is only update when the item was updated * categorize osm location * Update docs * Optimize location search - run providers in parallel - flatten code * add experimental address parsing for OSM * add poi_category_townhall * Fix popup closing when favorites items are updated * Revert "Fix popup closing when favorites items are updated" This reverts commit fc517fd066c7f8109b6d6df2d4f536af66398207. * Fork AndroidAddressFormatter to `:libs:address-formatter` * migrate `:libs:address-formatter` dependencies to version catalog and update them * also consider addr:{suburb,hamlet} for `Address.city` if city tag is missing * Move poi strings back to strings.xml * Update Jetpack Compose * Move address-formatter back to its original package, add license and readme * Move address-formatter back to its original package --------- Co-authored-by: MM20 <15646950+MM2-0@users.noreply.github.com>
This commit is contained in:
+37
-114
@@ -14,6 +14,9 @@ import de.mm20.launcher2.plugin.PluginApi
|
||||
import de.mm20.launcher2.plugin.config.WeatherPluginConfig
|
||||
import de.mm20.launcher2.plugin.contracts.PluginContract
|
||||
import de.mm20.launcher2.plugin.contracts.WeatherPluginContract
|
||||
import de.mm20.launcher2.plugin.contracts.WeatherPluginContract.ForecastColumns
|
||||
import de.mm20.launcher2.plugin.contracts.WeatherPluginContract.LocationColumns
|
||||
import de.mm20.launcher2.plugin.data.withColumns
|
||||
import de.mm20.launcher2.preferences.weather.WeatherLocation
|
||||
import de.mm20.launcher2.weather.Forecast
|
||||
import de.mm20.launcher2.weather.WeatherProvider
|
||||
@@ -107,99 +110,30 @@ internal class PluginWeatherProvider(
|
||||
return cursor.use {
|
||||
val results = mutableListOf<Forecast>()
|
||||
|
||||
val timestampIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.Timestamp)
|
||||
.takeIf { it >= 0 } ?: return null
|
||||
val createdAtIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.CreatedAt)
|
||||
.takeIf { it >= 0 } ?: return null
|
||||
val temperatureIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.Temperature)
|
||||
.takeIf { it >= 0 } ?: return null
|
||||
val conditionIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.Condition)
|
||||
.takeIf { it >= 0 } ?: return null
|
||||
val iconIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.Icon).takeIf { it >= 0 }
|
||||
?: return null
|
||||
cursor.withColumns(ForecastColumns) {
|
||||
|
||||
val locationIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.Location)
|
||||
.takeIf { it >= 0 }
|
||||
?: return null
|
||||
|
||||
val providerIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.Provider)
|
||||
.takeIf { it >= 0 }
|
||||
?: return null
|
||||
|
||||
val providerUrlIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.ProviderUrl)
|
||||
.takeIf { it >= 0 }
|
||||
|
||||
val precipitationIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.Precipitation)
|
||||
.takeIf { it >= 0 }
|
||||
|
||||
val precipProbabilityIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.RainProbability)
|
||||
.takeIf { it >= 0 }
|
||||
|
||||
val cloudsIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.Clouds)
|
||||
.takeIf { it >= 0 }
|
||||
|
||||
val humidityIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.Humidity)
|
||||
.takeIf { it >= 0 }
|
||||
|
||||
val windSpeedIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.WindSpeed)
|
||||
.takeIf { it >= 0 }
|
||||
|
||||
val windDirectionIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.WindDirection)
|
||||
.takeIf { it >= 0 }
|
||||
|
||||
val pressureIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.Pressure)
|
||||
.takeIf { it >= 0 }
|
||||
|
||||
val nightIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.Night)
|
||||
.takeIf { it >= 0 }
|
||||
|
||||
val minTempIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.TemperatureMin)
|
||||
.takeIf { it >= 0 }
|
||||
|
||||
val maxTempIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.ForecastColumns.TemperatureMax)
|
||||
.takeIf { it >= 0 }
|
||||
|
||||
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
results += Forecast(
|
||||
timestamp = cursor.getLongOrNull(timestampIndex) ?: continue,
|
||||
temperature = cursor.getDoubleOrNull(temperatureIndex) ?: continue,
|
||||
updateTime = cursor.getLongOrNull(createdAtIndex) ?: continue,
|
||||
condition = cursor.getStringOrNull(conditionIndex) ?: continue,
|
||||
icon = getIcon(cursor.getStringOrNull(iconIndex) ?: continue),
|
||||
location = cursor.getStringOrNull(locationIndex) ?: continue,
|
||||
provider = cursor.getStringOrNull(providerIndex) ?: continue,
|
||||
providerUrl = providerUrlIndex?.let { cursor.getStringOrNull(it) } ?: "",
|
||||
clouds = cloudsIndex?.let { cursor.getIntOrNull(it) },
|
||||
humidity = humidityIndex?.let { cursor.getDoubleOrNull(it) },
|
||||
precipitation = precipitationIndex?.let { cursor.getDoubleOrNull(it) },
|
||||
precipProbability = precipProbabilityIndex?.let { cursor.getIntOrNull(it) },
|
||||
windSpeed = windSpeedIndex?.let { cursor.getDoubleOrNull(it) },
|
||||
windDirection = windDirectionIndex?.let { cursor.getDoubleOrNull(it) },
|
||||
pressure = pressureIndex?.let { cursor.getDoubleOrNull(it) },
|
||||
night = nightIndex?.let { cursor.getIntOrNull(it) } == 1,
|
||||
minTemp = minTempIndex?.let { cursor.getDoubleOrNull(it) },
|
||||
maxTemp = maxTempIndex?.let { cursor.getDoubleOrNull(it) },
|
||||
)
|
||||
while (cursor.moveToNext()) {
|
||||
results += Forecast(
|
||||
timestamp = cursor[ForecastColumns.Timestamp] ?: continue,
|
||||
temperature = cursor[ForecastColumns.Temperature] ?: continue,
|
||||
updateTime = cursor[ForecastColumns.CreatedAt] ?: continue,
|
||||
condition = cursor[ForecastColumns.Condition] ?: continue,
|
||||
icon = getIcon(cursor[ForecastColumns.Icon]?.name ?: continue),
|
||||
location = cursor[ForecastColumns.Location] ?: continue,
|
||||
provider = cursor[ForecastColumns.Provider] ?: continue,
|
||||
providerUrl = cursor[ForecastColumns.ProviderUrl] ?: "",
|
||||
clouds = cursor[ForecastColumns.Clouds],
|
||||
humidity = cursor[ForecastColumns.Humidity]?.toDouble(),
|
||||
precipitation = cursor[ForecastColumns.Precipitation],
|
||||
precipProbability = cursor[ForecastColumns.RainProbability],
|
||||
windSpeed = cursor[ForecastColumns.WindSpeed],
|
||||
windDirection = cursor[ForecastColumns.WindDirection],
|
||||
pressure = cursor[ForecastColumns.Pressure],
|
||||
night = cursor[ForecastColumns.Night] ?: false,
|
||||
minTemp = cursor[ForecastColumns.TemperatureMin],
|
||||
maxTemp = cursor[ForecastColumns.TemperatureMax],
|
||||
)
|
||||
}
|
||||
}
|
||||
results
|
||||
}
|
||||
@@ -278,29 +212,18 @@ internal class PluginWeatherProvider(
|
||||
return cursor.use {
|
||||
val results = mutableListOf<WeatherLocation>()
|
||||
|
||||
val nameIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.LocationColumns.Name)
|
||||
.takeIf { it >= 0 } ?: return emptyList()
|
||||
val latIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.LocationColumns.Lat)
|
||||
.takeIf { it >= 0 }
|
||||
val lonIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.LocationColumns.Lon)
|
||||
.takeIf { it >= 0 }
|
||||
val locationIdIndex =
|
||||
cursor.getColumnIndex(WeatherPluginContract.LocationColumns.Id)
|
||||
.takeIf { it >= 0 }
|
||||
cursor.withColumns(LocationColumns) {
|
||||
while (cursor.moveToNext()) {
|
||||
val lat = cursor[LocationColumns.Lat]
|
||||
val lon = cursor[LocationColumns.Lon]
|
||||
val locationId = cursor[LocationColumns.Id]
|
||||
val name = cursor[LocationColumns.Name] ?: continue
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
val lat = latIndex?.let { cursor.getDoubleOrNull(it) }
|
||||
val lon = lonIndex?.let { cursor.getDoubleOrNull(it) }
|
||||
val locationId = locationIdIndex?.let { cursor.getStringOrNull(it) }
|
||||
val name = cursor.getStringOrNull(nameIndex) ?: continue
|
||||
|
||||
if (lat != null && lon != null) {
|
||||
results += WeatherLocation.LatLon(lat = lat, lon = lon, name = name)
|
||||
} else if (locationId != null) {
|
||||
results += WeatherLocation.Id(locationId = locationId, name = name)
|
||||
if (lat != null && lon != null) {
|
||||
results += WeatherLocation.LatLon(lat = lat, lon = lon, name = name)
|
||||
} else if (locationId != null) {
|
||||
results += WeatherLocation.Id(locationId = locationId, name = name)
|
||||
}
|
||||
}
|
||||
}
|
||||
results
|
||||
|
||||
Reference in New Issue
Block a user