diff --git a/README.md b/README.md index cd5d76d..e12597f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ -# Karoo Winddir Extension +# Karoo Headwind Extension > [!WARNING] -> This app is currently in prototype stage and its main features might not work at all. If you want to test it anyway and encounter issues, please report them in the [issue tracker](https://github.com/timklge/karoo-winddir/issues), ideally with adb logs attached. +> This app is currently in prototype stage and its main features might not work at all. If you want to test it anyway and encounter issues, please report them in the [issue tracker](https://github.com/timklge/karoo-headwind/issues), ideally with adb logs attached. -This extension for Karoo devices adds a graphical data field that shows the current wind direction relative to the rider as an arrow. It also provides data fields for relative humidity, cloud coverage, wind speed, wind gust speed, surface pressure, and rainfall at the current location. +This extension for Karoo devices adds a graphical data field that shows the current headwind direction as an arrow. +It also provides data fields for relative humidity, cloud coverage, wind speed, wind gust speed, surface pressure, and rainfall at the current location. Compatible with Karoo 2 and Karoo 3 devices running Karoo OS version 1.524.2003 and later. @@ -16,13 +17,13 @@ Compatible with Karoo 2 and Karoo 3 devices running Karoo OS version 1.524.2003 Currently, Hammerhead has not yet released an on-device app store for easy installation of extensions like this. Until then, you can sideload the app. -1. Download the APK from the [releases page](https://github.com/timklge/karoo-winddir/releases) (or build it from source). +1. Download the APK from the [releases page](https://github.com/timklge/karoo-headwind/releases) (or build it from source). 2. Prepare your Karoo for sideloading by following the [step-by-step guide](https://www.dcrainmaker.com/2021/02/how-to-sideload-android-apps-on-your-hammerhead-karoo-1-karoo-2.html) by DC Rainmaker. 3. Install the app using the command `adb install app-release.apk`. ## Usage -After installing this app on your Karoo, you can add a data field showing the relative wind direction or one of the auxiliary fields to your data pages. The relative wind direction will be shown as an arrow image, with an optional overlay of the wind speed in your chosen unit of measurement (default is kilometers per hour). +After installing this app on your Karoo, you can add a data field showing the headwind direction or one of the auxiliary fields to your data pages. The headwind direction will be shown as an arrow image, with an optional overlay of the wind speed in your chosen unit of measurement (default is kilometers per hour). The app will automatically attempt to download weather data for your current approximate location from the [open-meteo.com](https://open-meteo.com) API once your device has acquired a GPS fix. The API service is free for non-commercial use. Your location is rounded to approximately two kilometers to maintain privacy. The data is updated when you ride more than two kilometers from the location where the weather data was downloaded or after one hour at the latest. If the app cannot connect to the weather service, it will retry the download every minute. Downloading weather data should work on Karoo 2 if you have a SIM card inserted or on Karoo 3 via your phone's internet connection if you have the Karoo companion app installed. diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8791448..023c46f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -6,15 +6,15 @@ plugins { } android { - namespace = "de.timklge.karoowinddir" + namespace = "de.timklge.karooheadwind" compileSdk = 34 defaultConfig { - applicationId = "de.timklge.karoowinddir" + applicationId = "de.timklge.karooheadwind" minSdk = 26 targetSdk = 34 - versionCode = 1 - versionName = "1.0.0-beta1" + versionCode = 2 + versionName = "1.0.0-beta2" } buildTypes { diff --git a/app/manifest.json b/app/manifest.json index c506d59..fd2f2c3 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,11 +1,11 @@ { - "label": "karoo-winddir", - "packageName": "de.timklge.karoowinddir", - "iconUrl": "https://github.com/timklge/karoo-winddir/releases/latest/download/karoo-winddir.png", - "latestApkUrl": "https://github.com/timklge/karoo-winddir/releases/latest/download/app-release.apk", - "latestVersion": "1.0.0-beta1", - "latestVersionCode": 1, + "label": "karoo-headwind", + "packageName": "de.timklge.karooheadwind", + "iconUrl": "https://github.com/timklge/karoo-headwind/releases/latest/download/karoo-headwind.png", + "latestApkUrl": "https://github.com/timklge/karoo-headwind/releases/latest/download/app-release.apk", + "latestVersion": "1.0.0-beta2", + "latestVersionCode": 2, "developer": "timklge", - "description": "Provides relative wind direction, wind speed and other weather data fields", + "description": "Provides headwind direction, wind speed and other weather data fields", "releaseNotes": "Initial release" } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a871f48..9e22dc0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,7 @@ android:supportsRtl="true" android:theme="@style/Theme.AppCompat"> @@ -19,7 +19,7 @@ @@ -32,6 +32,6 @@ + android:value="https://github.com/timklge/karoo-headwind/releases/latest/download/manifest.json" /> \ No newline at end of file diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/Extensions.kt b/app/src/main/kotlin/de/timklge/karooheadwind/Extensions.kt similarity index 78% rename from app/src/main/kotlin/de/timklge/karoowinddir/Extensions.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/Extensions.kt index 536d6b3..9160dba 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/Extensions.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/Extensions.kt @@ -1,12 +1,12 @@ -package de.timklge.karoowinddir +package de.timklge.karooheadwind import android.content.Context import android.util.Log import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey -import de.timklge.karoowinddir.datatypes.GpsCoordinates -import de.timklge.karoowinddir.screens.WinddirSettings -import de.timklge.karoowinddir.screens.WinddirStats +import de.timklge.karooheadwind.datatypes.GpsCoordinates +import de.timklge.karooheadwind.screens.HeadwindSettings +import de.timklge.karooheadwind.screens.HeadwindStats import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.models.DataType import io.hammerhead.karooext.models.HttpResponseState @@ -42,13 +42,13 @@ val settingsKey = stringPreferencesKey("settings") val currentDataKey = stringPreferencesKey("current") val statsKey = stringPreferencesKey("stats") -suspend fun saveSettings(context: Context, settings: WinddirSettings) { +suspend fun saveSettings(context: Context, settings: HeadwindSettings) { context.dataStore.edit { t -> t[settingsKey] = Json.encodeToString(settings) } } -suspend fun saveStats(context: Context, stats: WinddirStats) { +suspend fun saveStats(context: Context, stats: HeadwindStats) { context.dataStore.edit { t -> t[statsKey] = Json.encodeToString(stats) } @@ -77,45 +77,45 @@ fun Context.streamCurrentWeatherData(): Flow { val data = settingsJson[currentDataKey] data?.let { d -> jsonWithUnknownKeys.decodeFromString(d) } } catch (e: Throwable) { - Log.e(KarooWinddirExtension.TAG, "Failed to read preferences", e) + Log.e(KarooHeadwindExtension.TAG, "Failed to read preferences", e) null } }.filterNotNull().distinctUntilChanged().filter { it.current.time * 1000 >= System.currentTimeMillis() - (1000 * 60 * 60 * 12) } } -fun Context.streamSettings(): Flow { +fun Context.streamSettings(): Flow { return dataStore.data.map { settingsJson -> try { - jsonWithUnknownKeys.decodeFromString( - settingsJson[settingsKey] ?: WinddirSettings.defaultSettings + jsonWithUnknownKeys.decodeFromString( + settingsJson[settingsKey] ?: HeadwindSettings.defaultSettings ) } catch(e: Throwable){ - Log.e(KarooWinddirExtension.TAG, "Failed to read preferences", e) - jsonWithUnknownKeys.decodeFromString(WinddirSettings.defaultSettings) + Log.e(KarooHeadwindExtension.TAG, "Failed to read preferences", e) + jsonWithUnknownKeys.decodeFromString(HeadwindSettings.defaultSettings) } }.distinctUntilChanged() } -fun Context.streamStats(): Flow { +fun Context.streamStats(): Flow { return dataStore.data.map { statsJson -> try { - jsonWithUnknownKeys.decodeFromString( - statsJson[statsKey] ?: WinddirStats.defaultStats + jsonWithUnknownKeys.decodeFromString( + statsJson[statsKey] ?: HeadwindStats.defaultStats ) } catch(e: Throwable){ - Log.e(KarooWinddirExtension.TAG, "Failed to read stats", e) - jsonWithUnknownKeys.decodeFromString(WinddirStats.defaultStats) + Log.e(KarooHeadwindExtension.TAG, "Failed to read stats", e) + jsonWithUnknownKeys.decodeFromString(HeadwindStats.defaultStats) } }.distinctUntilChanged() } @OptIn(FlowPreview::class) -suspend fun KarooSystemService.makeOpenMeteoHttpRequest(gpsCoordinates: GpsCoordinates, settings: WinddirSettings): HttpResponseState.Complete { +suspend fun KarooSystemService.makeOpenMeteoHttpRequest(gpsCoordinates: GpsCoordinates, settings: HeadwindSettings): HttpResponseState.Complete { return callbackFlow { // https://open-meteo.com/en/docs#current=temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=&daily=&location_mode=csv_coordinates&timeformat=unixtime&forecast_days=3 val url = "https://api.open-meteo.com/v1/forecast?latitude=${gpsCoordinates.lat}&longitude=${gpsCoordinates.lon}¤t=weather_code,temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m,surface_pressure&timeformat=unixtime&wind_speed_unit=${settings.windUnit.id}&precipitation_unit=${settings.precipitationUnit.id}" - Log.d(KarooWinddirExtension.TAG, "Http request to ${url}...") + Log.d(KarooHeadwindExtension.TAG, "Http request to ${url}...") val listenerId = addConsumer( OnHttpResponse.MakeHttpRequest( @@ -124,7 +124,7 @@ suspend fun KarooSystemService.makeOpenMeteoHttpRequest(gpsCoordinates: GpsCoord waitForConnection = false, ), ) { event: OnHttpResponse -> - Log.d(KarooWinddirExtension.TAG, "Http response event $event") + Log.d(KarooHeadwindExtension.TAG, "Http response event $event") if (event.state is HttpResponseState.Complete){ trySend(event.state as HttpResponseState.Complete) close() @@ -162,10 +162,10 @@ fun KarooSystemService.getGpsCoordinateFlow(): Flow { val lon = values[DataType.Field.LOC_LONGITUDE] if (lat != null && lon != null){ - Log.d(KarooWinddirExtension.TAG, "Updated gps coords: $lat $lon") + Log.d(KarooHeadwindExtension.TAG, "Updated gps coords: $lat $lon") GpsCoordinates(lat, lon) } else { - Log.e(KarooWinddirExtension.TAG, "Missing gps values: $values") + Log.e(KarooHeadwindExtension.TAG, "Missing gps values: $values") null } } diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/KarooWinddirExtension.kt b/app/src/main/kotlin/de/timklge/karooheadwind/KarooWinddirExtension.kt similarity index 80% rename from app/src/main/kotlin/de/timklge/karoowinddir/KarooWinddirExtension.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/KarooWinddirExtension.kt index ee8e369..2683723 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/KarooWinddirExtension.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/KarooWinddirExtension.kt @@ -1,17 +1,17 @@ -package de.timklge.karoowinddir +package de.timklge.karooheadwind import android.util.Log -import de.timklge.karoowinddir.datatypes.CloudCoverDataType -import de.timklge.karoowinddir.datatypes.GpsCoordinates -import de.timklge.karoowinddir.datatypes.PrecipitationDataType -import de.timklge.karoowinddir.datatypes.RelativeHumidityDataType -import de.timklge.karoowinddir.datatypes.SurfacePressureDataType -import de.timklge.karoowinddir.datatypes.WindDirectionDataType -import de.timklge.karoowinddir.datatypes.WindGustsDataType -import de.timklge.karoowinddir.datatypes.WindSpeedDataType -import de.timklge.karoowinddir.datatypes.RelativeWindDirectionDataType -import de.timklge.karoowinddir.datatypes.WeatherDataType -import de.timklge.karoowinddir.screens.WinddirStats +import de.timklge.karooheadwind.datatypes.CloudCoverDataType +import de.timklge.karooheadwind.datatypes.GpsCoordinates +import de.timklge.karooheadwind.datatypes.PrecipitationDataType +import de.timklge.karooheadwind.datatypes.RelativeHumidityDataType +import de.timklge.karooheadwind.datatypes.SurfacePressureDataType +import de.timklge.karooheadwind.datatypes.WindDirectionDataType +import de.timklge.karooheadwind.datatypes.WindGustsDataType +import de.timklge.karooheadwind.datatypes.WindSpeedDataType +import de.timklge.karooheadwind.datatypes.RelativeWindDirectionDataType +import de.timklge.karooheadwind.datatypes.WeatherDataType +import de.timklge.karooheadwind.screens.HeadwindStats import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.extension.KarooExtension import kotlinx.coroutines.CoroutineScope @@ -29,9 +29,9 @@ import kotlinx.coroutines.launch import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.minutes -class KarooWinddirExtension : KarooExtension("karoo-winddir", "1.0.0-beta1") { +class KarooHeadwindExtension : KarooExtension("karoo-headwind", "1.0.0-beta2") { companion object { - const val TAG = "karoo-winddir" + const val TAG = "karoo-headwind" } lateinit var karooSystem: KarooSystemService @@ -84,14 +84,14 @@ class KarooWinddirExtension : KarooExtension("karoo-winddir", "1.0.0-beta1") { streamStats().first() } catch(e: Exception){ Log.e(TAG, "Failed to read stats", e) - WinddirStats() + HeadwindStats() } val response = karooSystem.makeOpenMeteoHttpRequest(gps, settings) if (response.error != null){ try { val stats = lastKnownStats.copy(failedWeatherRequest = System.currentTimeMillis()) - launch { saveStats(this@KarooWinddirExtension, stats) } + launch { saveStats(this@KarooHeadwindExtension, stats) } } catch(e: Exception){ Log.e(TAG, "Failed to write stats", e) } @@ -102,7 +102,7 @@ class KarooWinddirExtension : KarooExtension("karoo-winddir", "1.0.0-beta1") { lastSuccessfulWeatherRequest = System.currentTimeMillis(), lastSuccessfulWeatherPosition = gps ) - launch { saveStats(this@KarooWinddirExtension, stats) } + launch { saveStats(this@KarooHeadwindExtension, stats) } } catch(e: Exception){ Log.e(TAG, "Failed to write stats", e) } diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/MainActivity.kt b/app/src/main/kotlin/de/timklge/karooheadwind/MainActivity.kt similarity index 83% rename from app/src/main/kotlin/de/timklge/karoowinddir/MainActivity.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/MainActivity.kt index fca6675..b791ff9 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/MainActivity.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/MainActivity.kt @@ -1,4 +1,4 @@ -package de.timklge.karoowinddir +package de.timklge.karooheadwind import android.content.Context import android.os.Bundle @@ -8,8 +8,8 @@ import androidx.compose.material3.Text import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.preferencesDataStore -import de.timklge.karoowinddir.screens.MainScreen -import de.timklge.karoowinddir.theme.AppTheme +import de.timklge.karooheadwind.screens.MainScreen +import de.timklge.karooheadwind.theme.AppTheme val Context.dataStore: DataStore by preferencesDataStore(name = "settings") diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/OpenMeteoData.kt b/app/src/main/kotlin/de/timklge/karooheadwind/OpenMeteoData.kt similarity index 97% rename from app/src/main/kotlin/de/timklge/karoowinddir/OpenMeteoData.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/OpenMeteoData.kt index ffbd148..cbdf876 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/OpenMeteoData.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/OpenMeteoData.kt @@ -1,4 +1,4 @@ -package de.timklge.karoowinddir +package de.timklge.karooheadwind import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/BaseDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/BaseDataType.kt similarity index 69% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/BaseDataType.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/BaseDataType.kt index 2b67915..e59a2aa 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/BaseDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/BaseDataType.kt @@ -1,10 +1,10 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import android.content.Context import android.util.Log -import de.timklge.karoowinddir.KarooWinddirExtension -import de.timklge.karoowinddir.OpenMeteoCurrentWeatherResponse -import de.timklge.karoowinddir.streamCurrentWeatherData +import de.timklge.karooheadwind.KarooHeadwindExtension +import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse +import de.timklge.karooheadwind.streamCurrentWeatherData import io.hammerhead.karooext.extension.DataTypeImpl import io.hammerhead.karooext.internal.Emitter import io.hammerhead.karooext.models.DataPoint @@ -17,22 +17,22 @@ import kotlinx.coroutines.launch abstract class BaseDataType( private val applicationContext: Context, dataTypeId: String -) : DataTypeImpl("karoo-winddir", dataTypeId) { +) : DataTypeImpl("karoo-headwind", dataTypeId) { abstract fun getValue(data: OpenMeteoCurrentWeatherResponse): Double override fun startStream(emitter: Emitter) { - Log.d(KarooWinddirExtension.TAG, "start $dataTypeId stream") + Log.d(KarooHeadwindExtension.TAG, "start $dataTypeId stream") val job = CoroutineScope(Dispatchers.IO).launch { val currentWeatherData = applicationContext.streamCurrentWeatherData() currentWeatherData.collect { data -> val value = getValue(data) - Log.d(KarooWinddirExtension.TAG, "$dataTypeId: $value") + Log.d(KarooHeadwindExtension.TAG, "$dataTypeId: $value") emitter.onNext(StreamState.Streaming(DataPoint(dataTypeId, mapOf(DataType.Field.SINGLE to value)))) } } emitter.setCancellable { - Log.d(KarooWinddirExtension.TAG, "stop $dataTypeId stream") + Log.d(KarooHeadwindExtension.TAG, "stop $dataTypeId stream") job.cancel() } } diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/CloudCoverDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/CloudCoverDataType.kt similarity index 69% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/CloudCoverDataType.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/CloudCoverDataType.kt index 9139a73..829002b 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/CloudCoverDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/CloudCoverDataType.kt @@ -1,7 +1,7 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import android.content.Context -import de.timklge.karoowinddir.OpenMeteoCurrentWeatherResponse +import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse class CloudCoverDataType(context: Context) : BaseDataType(context, "cloudCover"){ override fun getValue(data: OpenMeteoCurrentWeatherResponse): Double { diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/GpsCoordinates.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/GpsCoordinates.kt similarity index 96% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/GpsCoordinates.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/GpsCoordinates.kt index 064e344..bcf2bc4 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/GpsCoordinates.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/GpsCoordinates.kt @@ -1,4 +1,4 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import kotlinx.serialization.Serializable import kotlin.math.atan2 diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/PrecipitationDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/PrecipitationDataType.kt similarity index 69% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/PrecipitationDataType.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/PrecipitationDataType.kt index af27566..4342715 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/PrecipitationDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/PrecipitationDataType.kt @@ -1,7 +1,7 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import android.content.Context -import de.timklge.karoowinddir.OpenMeteoCurrentWeatherResponse +import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse class PrecipitationDataType(context: Context) : BaseDataType(context, "precipitation"){ override fun getValue(data: OpenMeteoCurrentWeatherResponse): Double { diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/RelativeHumidityDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/RelativeHumidityDataType.kt similarity index 71% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/RelativeHumidityDataType.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/RelativeHumidityDataType.kt index e6c7642..60a8772 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/RelativeHumidityDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/RelativeHumidityDataType.kt @@ -1,7 +1,7 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import android.content.Context -import de.timklge.karoowinddir.OpenMeteoCurrentWeatherResponse +import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse class RelativeHumidityDataType(context: Context) : BaseDataType(context, "relativeHumidity"){ override fun getValue(data: OpenMeteoCurrentWeatherResponse): Double { diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/RelativeWindDirectionDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/RelativeWindDirectionDataType.kt similarity index 82% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/RelativeWindDirectionDataType.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/RelativeWindDirectionDataType.kt index d8a7b95..7e9c1ae 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/RelativeWindDirectionDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/RelativeWindDirectionDataType.kt @@ -1,17 +1,17 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import android.content.Context import android.util.Log import androidx.compose.ui.unit.DpSize import androidx.glance.appwidget.ExperimentalGlanceRemoteViewsApi import androidx.glance.appwidget.GlanceRemoteViews -import de.timklge.karoowinddir.KarooWinddirExtension -import de.timklge.karoowinddir.OpenMeteoCurrentWeatherResponse -import de.timklge.karoowinddir.getHeadingFlow -import de.timklge.karoowinddir.screens.WinddirSettings -import de.timklge.karoowinddir.streamCurrentWeatherData -import de.timklge.karoowinddir.streamDataFlow -import de.timklge.karoowinddir.streamSettings +import de.timklge.karooheadwind.KarooHeadwindExtension +import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse +import de.timklge.karooheadwind.getHeadingFlow +import de.timklge.karooheadwind.screens.HeadwindSettings +import de.timklge.karooheadwind.streamCurrentWeatherData +import de.timklge.karooheadwind.streamDataFlow +import de.timklge.karooheadwind.streamSettings import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.extension.DataTypeImpl import io.hammerhead.karooext.internal.Emitter @@ -37,7 +37,7 @@ import kotlin.math.roundToInt class RelativeWindDirectionDataType( private val karooSystem: KarooSystemService, private val applicationContext: Context -) : DataTypeImpl("karoo-winddir", "winddir") { +) : DataTypeImpl("karoo-headwind", "headwind") { private val glance = GlanceRemoteViews() private fun signedAngleDifference(angle1: Double, angle2: Double): Double { @@ -71,7 +71,7 @@ class RelativeWindDirectionDataType( val windBearing = data.current.windDirection + 180 val diff = (signedAngleDifference(bearing, windBearing) + 360) % 360 - Log.d(KarooWinddirExtension.TAG, "Wind bearing: $bearing vs $windBearing => $diff") + Log.d(KarooHeadwindExtension.TAG, "Wind bearing: $bearing vs $windBearing => $diff") emitter.onNext(StreamState.Streaming(DataPoint(dataTypeId, mapOf(DataType.Field.SINGLE to diff)))) } } @@ -81,13 +81,13 @@ class RelativeWindDirectionDataType( } override fun startView(context: Context, config: ViewConfig, emitter: ViewEmitter) { - Log.d(KarooWinddirExtension.TAG, "Starting relative wind direction view with $emitter") + Log.d(KarooHeadwindExtension.TAG, "Starting headwind direction view with $emitter") val configJob = CoroutineScope(Dispatchers.IO).launch { emitter.onNext(UpdateGraphicConfig(showHeader = false)) awaitCancellation() } - data class StreamData(val value: Double, val data: OpenMeteoCurrentWeatherResponse, val settings: WinddirSettings) + data class StreamData(val value: Double, val data: OpenMeteoCurrentWeatherResponse, val settings: HeadwindSettings) val viewJob = CoroutineScope(Dispatchers.IO).launch { karooSystem.streamDataFlow(dataTypeId) @@ -100,7 +100,7 @@ class RelativeWindDirectionDataType( emitter.updateView(result.remoteViews) } .collect { streamData -> - Log.d(KarooWinddirExtension.TAG, "Updating relative wind direction view") + Log.d(KarooHeadwindExtension.TAG, "Updating headwind direction view") val windSpeed = streamData.data.current.windSpeed val windDirection = streamData.value val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed @@ -114,7 +114,7 @@ class RelativeWindDirectionDataType( } } emitter.setCancellable { - Log.d(KarooWinddirExtension.TAG, "Stopping winddir view with $emitter") + Log.d(KarooHeadwindExtension.TAG, "Stopping headwind view with $emitter") configJob.cancel() viewJob.cancel() } diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/RelativeWindDirectionView.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/RelativeWindDirectionView.kt similarity index 97% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/RelativeWindDirectionView.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/RelativeWindDirectionView.kt index 074398c..5c9921f 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/RelativeWindDirectionView.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/RelativeWindDirectionView.kt @@ -1,4 +1,4 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color @@ -20,7 +20,7 @@ import androidx.glance.preview.ExperimentalGlancePreviewApi import androidx.glance.preview.Preview import androidx.glance.text.Text import androidx.glance.text.TextStyle -import de.timklge.karoowinddir.R +import de.timklge.karooheadwind.R import kotlin.math.roundToInt fun getArrowResourceByBearing(bearing: Int): Int { diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/SurfacePressureDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/SurfacePressureDataType.kt similarity index 70% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/SurfacePressureDataType.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/SurfacePressureDataType.kt index e8c3a11..f70a18a 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/SurfacePressureDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/SurfacePressureDataType.kt @@ -1,7 +1,7 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import android.content.Context -import de.timklge.karoowinddir.OpenMeteoCurrentWeatherResponse +import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse class SurfacePressureDataType(context: Context) : BaseDataType(context, "surfacePressure"){ override fun getValue(data: OpenMeteoCurrentWeatherResponse): Double { diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WeatherDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherDataType.kt similarity index 78% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WeatherDataType.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherDataType.kt index d0c3247..33c0fe1 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WeatherDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherDataType.kt @@ -1,17 +1,17 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import android.content.Context import android.util.Log import androidx.compose.ui.unit.DpSize import androidx.glance.appwidget.ExperimentalGlanceRemoteViewsApi import androidx.glance.appwidget.GlanceRemoteViews -import de.timklge.karoowinddir.KarooWinddirExtension -import de.timklge.karoowinddir.OpenMeteoCurrentWeatherResponse -import de.timklge.karoowinddir.WeatherInterpretation -import de.timklge.karoowinddir.getHeadingFlow -import de.timklge.karoowinddir.screens.WinddirSettings -import de.timklge.karoowinddir.streamCurrentWeatherData -import de.timklge.karoowinddir.streamSettings +import de.timklge.karooheadwind.KarooHeadwindExtension +import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse +import de.timklge.karooheadwind.WeatherInterpretation +import de.timklge.karooheadwind.getHeadingFlow +import de.timklge.karooheadwind.screens.HeadwindSettings +import de.timklge.karooheadwind.streamCurrentWeatherData +import de.timklge.karooheadwind.streamSettings import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.extension.DataTypeImpl import io.hammerhead.karooext.internal.Emitter @@ -34,7 +34,7 @@ import kotlin.math.roundToInt class WeatherDataType( private val karooSystem: KarooSystemService, private val applicationContext: Context -) : DataTypeImpl("karoo-winddir", "weather") { +) : DataTypeImpl("karoo-headwind", "weather") { private val glance = GlanceRemoteViews() // FIXME: Remove. Currently, the data field will permanently show "no sensor" if no data stream is provided @@ -44,7 +44,7 @@ class WeatherDataType( currentWeatherData .collect { data -> - Log.d(KarooWinddirExtension.TAG, "Wind code: ${data.current.weatherCode}") + Log.d(KarooHeadwindExtension.TAG, "Wind code: ${data.current.weatherCode}") emitter.onNext(StreamState.Streaming(DataPoint(dataTypeId, mapOf(DataType.Field.SINGLE to data.current.weatherCode.toDouble())))) } } @@ -54,13 +54,13 @@ class WeatherDataType( } override fun startView(context: Context, config: ViewConfig, emitter: ViewEmitter) { - Log.d(KarooWinddirExtension.TAG, "Starting weather view with $emitter") + Log.d(KarooHeadwindExtension.TAG, "Starting weather view with $emitter") val configJob = CoroutineScope(Dispatchers.IO).launch { emitter.onNext(UpdateGraphicConfig(showHeader = false)) awaitCancellation() } - data class StreamData(val data: OpenMeteoCurrentWeatherResponse, val settings: WinddirSettings) + data class StreamData(val data: OpenMeteoCurrentWeatherResponse, val settings: HeadwindSettings) val viewJob = CoroutineScope(Dispatchers.IO).launch { context.streamCurrentWeatherData() @@ -71,7 +71,7 @@ class WeatherDataType( emitter.updateView(result.remoteViews) } .collect { (data, settings) -> - Log.d(KarooWinddirExtension.TAG, "Updating weather view") + Log.d(KarooHeadwindExtension.TAG, "Updating weather view") val interpretation = WeatherInterpretation.fromWeatherCode(data.current.weatherCode) val result = glance.compose(context, DpSize.Unspecified) { @@ -82,7 +82,7 @@ class WeatherDataType( } } emitter.setCancellable { - Log.d(KarooWinddirExtension.TAG, "Stopping winddir view with $emitter") + Log.d(KarooHeadwindExtension.TAG, "Stopping headwind view with $emitter") configJob.cancel() viewJob.cancel() } diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WeatherView.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherView.kt similarity index 92% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WeatherView.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherView.kt index fc94026..95a10b2 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WeatherView.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherView.kt @@ -1,4 +1,4 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color @@ -15,18 +15,15 @@ import androidx.glance.layout.Column import androidx.glance.layout.ContentScale import androidx.glance.layout.Row import androidx.glance.layout.fillMaxSize -import androidx.glance.layout.fillMaxWidth import androidx.glance.layout.height -import androidx.glance.layout.padding import androidx.glance.layout.width import androidx.glance.preview.ExperimentalGlancePreviewApi import androidx.glance.preview.Preview import androidx.glance.text.FontFamily import androidx.glance.text.Text import androidx.glance.text.TextStyle -import de.timklge.karoowinddir.R -import de.timklge.karoowinddir.WeatherInterpretation -import de.timklge.karoowinddir.screens.WinddirSettings +import de.timklge.karooheadwind.R +import de.timklge.karooheadwind.WeatherInterpretation fun getWeatherIcon(interpretation: WeatherInterpretation): Int { return when (interpretation){ diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WindDirectionDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindDirectionDataType.kt similarity index 92% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WindDirectionDataType.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindDirectionDataType.kt index cbe125e..8ec831c 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WindDirectionDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindDirectionDataType.kt @@ -1,4 +1,4 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import android.content.Context import android.util.Log @@ -16,9 +16,9 @@ import androidx.glance.layout.fillMaxSize import androidx.glance.text.FontFamily import androidx.glance.text.Text import androidx.glance.text.TextStyle -import de.timklge.karoowinddir.KarooWinddirExtension -import de.timklge.karoowinddir.OpenMeteoCurrentWeatherResponse -import de.timklge.karoowinddir.streamDataFlow +import de.timklge.karooheadwind.KarooHeadwindExtension +import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse +import de.timklge.karooheadwind.streamDataFlow import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.internal.ViewEmitter import io.hammerhead.karooext.models.StreamState @@ -66,7 +66,7 @@ class WindDirectionDataType(val karooSystem: KarooSystemService, context: Contex 7 -> "NW" else -> "N/A" } - Log.d( KarooWinddirExtension.TAG,"Updating wind direction view") + Log.d( KarooHeadwindExtension.TAG,"Updating wind direction view") val result = glance.compose(context, DpSize.Unspecified) { Box(modifier = GlanceModifier.fillMaxSize(), contentAlignment = Alignment( diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WindGustsDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindGustsDataType.kt similarity index 68% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WindGustsDataType.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindGustsDataType.kt index c61cf39..e6cce39 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WindGustsDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindGustsDataType.kt @@ -1,7 +1,7 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import android.content.Context -import de.timklge.karoowinddir.OpenMeteoCurrentWeatherResponse +import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse class WindGustsDataType(context: Context) : BaseDataType(context, "windGusts"){ override fun getValue(data: OpenMeteoCurrentWeatherResponse): Double { diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WindSpeedDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindSpeedDataType.kt similarity index 68% rename from app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WindSpeedDataType.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindSpeedDataType.kt index ce6f4c9..43f189f 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/datatypes/WindSpeedDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WindSpeedDataType.kt @@ -1,7 +1,7 @@ -package de.timklge.karoowinddir.datatypes +package de.timklge.karooheadwind.datatypes import android.content.Context -import de.timklge.karoowinddir.OpenMeteoCurrentWeatherResponse +import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse class WindSpeedDataType(context: Context) : BaseDataType(context, "windSpeed"){ override fun getValue(data: OpenMeteoCurrentWeatherResponse): Double { diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/screens/Dropdown.kt b/app/src/main/kotlin/de/timklge/karooheadwind/screens/Dropdown.kt similarity index 98% rename from app/src/main/kotlin/de/timklge/karoowinddir/screens/Dropdown.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/screens/Dropdown.kt index 3722288..ff01152 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/screens/Dropdown.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/screens/Dropdown.kt @@ -1,4 +1,4 @@ -package de.timklge.karoowinddir.screens +package de.timklge.karooheadwind.screens import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.DropdownMenuItem diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/screens/MainScreen.kt b/app/src/main/kotlin/de/timklge/karooheadwind/screens/MainScreen.kt similarity index 88% rename from app/src/main/kotlin/de/timklge/karoowinddir/screens/MainScreen.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/screens/MainScreen.kt index 04921de..979d6af 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/screens/MainScreen.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/screens/MainScreen.kt @@ -1,4 +1,4 @@ -package de.timklge.karoowinddir.screens +package de.timklge.karooheadwind.screens import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -35,11 +35,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp -import de.timklge.karoowinddir.datatypes.GpsCoordinates -import de.timklge.karoowinddir.getGpsCoordinateFlow -import de.timklge.karoowinddir.saveSettings -import de.timklge.karoowinddir.streamSettings -import de.timklge.karoowinddir.streamStats +import de.timklge.karooheadwind.datatypes.GpsCoordinates +import de.timklge.karooheadwind.getGpsCoordinateFlow +import de.timklge.karooheadwind.saveSettings +import de.timklge.karooheadwind.streamSettings +import de.timklge.karooheadwind.streamStats import io.hammerhead.karooext.KarooSystemService import kotlinx.coroutines.launch import kotlinx.serialization.Serializable @@ -64,25 +64,25 @@ enum class PrecipitationUnit(val id: String, val label: String){ } @Serializable -data class WinddirSettings( +data class HeadwindSettings( val windUnit: WindUnit = WindUnit.KILOMETERS_PER_HOUR, val precipitationUnit: PrecipitationUnit = PrecipitationUnit.MILLIMETERS, val welcomeDialogAccepted: Boolean = false, val showWindspeedOverlay: Boolean = true ){ companion object { - val defaultSettings = Json.encodeToString(WinddirSettings()) + val defaultSettings = Json.encodeToString(HeadwindSettings()) } } @Serializable -data class WinddirStats( +data class HeadwindStats( val lastSuccessfulWeatherRequest: Long? = null, val lastSuccessfulWeatherPosition: GpsCoordinates? = null, val failedWeatherRequest: Long? = null, ){ companion object { - val defaultStats = Json.encodeToString(WinddirStats()) + val defaultStats = Json.encodeToString(HeadwindStats()) } } @@ -99,7 +99,7 @@ fun MainScreen() { var welcomeDialogVisible by remember { mutableStateOf(false) } var showWindspeedOverlay by remember { mutableStateOf(false) } - val stats by ctx.streamStats().collectAsState(WinddirStats()) + val stats by ctx.streamStats().collectAsState(HeadwindStats()) val location by karooSystem.getGpsCoordinateFlow().collectAsState(initial = null) var savedDialogVisible by remember { mutableStateOf(false) } @@ -143,13 +143,13 @@ fun MainScreen() { Row(verticalAlignment = Alignment.CenterVertically) { Switch(checked = showWindspeedOverlay, onCheckedChange = { showWindspeedOverlay = it}) Spacer(modifier = Modifier.width(10.dp)) - Text("Show wind speed on direction field") + Text("Show headwind speed on arrow") } FilledTonalButton(modifier = Modifier .fillMaxWidth() .height(50.dp), onClick = { - val newSettings = WinddirSettings(windUnit = selectedWindUnit, precipitationUnit = selectedPrecipitationUnit, welcomeDialogAccepted = true, showWindspeedOverlay = showWindspeedOverlay) + val newSettings = HeadwindSettings(windUnit = selectedWindUnit, precipitationUnit = selectedPrecipitationUnit, welcomeDialogAccepted = true, showWindspeedOverlay = showWindspeedOverlay) coroutineScope.launch { saveSettings(ctx, newSettings) @@ -198,16 +198,16 @@ fun MainScreen() { AlertDialog(onDismissRequest = { }, confirmButton = { Button(onClick = { coroutineScope.launch { - saveSettings(ctx, WinddirSettings(windUnit = selectedWindUnit, precipitationUnit = selectedPrecipitationUnit, welcomeDialogAccepted = true)) + saveSettings(ctx, HeadwindSettings(windUnit = selectedWindUnit, precipitationUnit = selectedPrecipitationUnit, welcomeDialogAccepted = true)) } }) { Text("OK") } }, text = { Column(modifier = Modifier.verticalScroll(rememberScrollState())) { - Text("Welcome to karoo-winddir!") + Text("Welcome to karoo-headwind!") Spacer(Modifier.padding(10.dp)) - Text("You can add relative wind direction and other fields to your data pages in your profile settings.") + Text("You can add headwind direction and other fields to your data pages in your profile settings.") Spacer(Modifier.padding(10.dp)) diff --git a/app/src/main/kotlin/de/timklge/karoowinddir/theme/Theme.kt b/app/src/main/kotlin/de/timklge/karooheadwind/theme/Theme.kt similarity index 84% rename from app/src/main/kotlin/de/timklge/karoowinddir/theme/Theme.kt rename to app/src/main/kotlin/de/timklge/karooheadwind/theme/Theme.kt index 0c7885f..71779e1 100644 --- a/app/src/main/kotlin/de/timklge/karoowinddir/theme/Theme.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/theme/Theme.kt @@ -1,4 +1,4 @@ -package de.timklge.karoowinddir.theme +package de.timklge.karooheadwind.theme import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 78f8cb7..3847260 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,8 +1,8 @@ WindDir - winddir - Wind direction - Current wind direction relative to the riding direction + headwind + Wind direction + Current wind direction relative to the riding direction Humidity Relative humidity in percent Cloud cover diff --git a/app/src/main/res/xml/extension_info.xml b/app/src/main/res/xml/extension_info.xml index 98dfb02..2bc8c85 100644 --- a/app/src/main/res/xml/extension_info.xml +++ b/app/src/main/res/xml/extension_info.xml @@ -2,14 +2,14 @@ + typeId="headwind" />