Compare commits
No commits in common. "522364dd848ba2770157b154da559c087fbcc3d6" and "c4a23ce4565336e0a55a43766b985207d5b82e50" have entirely different histories.
522364dd84
...
c4a23ce456
1
.github/workflows/android.yml
vendored
@ -25,6 +25,7 @@ jobs:
|
|||||||
echo "KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> $GITHUB_ENV
|
echo "KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> $GITHUB_ENV
|
||||||
echo "KEYSTORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> $GITHUB_ENV
|
echo "KEYSTORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> $GITHUB_ENV
|
||||||
echo "KEYSTORE_BASE64=${{ secrets.KEYSTORE_BASE64 }}" >> $GITHUB_ENV
|
echo "KEYSTORE_BASE64=${{ secrets.KEYSTORE_BASE64 }}" >> $GITHUB_ENV
|
||||||
|
echo "GOOGLE_SERVICES_JSON_BASE64=${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}" >> $GITHUB_ENV
|
||||||
echo "BUILD_NUMBER=${{ github.run_number }}" >> $GITHUB_ENV
|
echo "BUILD_NUMBER=${{ github.run_number }}" >> $GITHUB_ENV
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: set up JDK 17
|
- name: set up JDK 17
|
||||||
|
|||||||
@ -25,7 +25,7 @@ After installing this app on your Karoo and opening it once from the main menu,
|
|||||||
- Tailwind with riding speed (graphical, 1x1 field): Shows an arrow indicating the current headwind direction next to a label reading your current speed and the speed of the tailwind. If you ride against a headwind of 5 mph, it will show "-5". If you ride in the same direction of a 5 mph wind, it will read "+5". Text and arrow are colored based on the tailwind speed, with red indicating a strong headwind and green indicating a strong tailwind.
|
- Tailwind with riding speed (graphical, 1x1 field): Shows an arrow indicating the current headwind direction next to a label reading your current speed and the speed of the tailwind. If you ride against a headwind of 5 mph, it will show "-5". If you ride in the same direction of a 5 mph wind, it will read "+5". Text and arrow are colored based on the tailwind speed, with red indicating a strong headwind and green indicating a strong tailwind.
|
||||||
- Tailwind (graphical, 1x1 field): Similar to the tailwind and riding speed field, but shows tailwind speed, wind speed and wind gust speed instead of riding speed.
|
- Tailwind (graphical, 1x1 field): Similar to the tailwind and riding speed field, but shows tailwind speed, wind speed and wind gust speed instead of riding speed.
|
||||||
- Weather forecast (graphical, 2x1 field): Shows three columns indicating the current weather conditions (sunny, cloudy, ...), wind direction, precipitation and temperature forecasted for the next three hours. Tap on this widget to cycle through the 12 hour forecast. If you have a route loaded, the forecast widget will show the forecasted weather along points of the route, with an estimated traveled distance per hour of 20 km / 12 miles by default.
|
- Weather forecast (graphical, 2x1 field): Shows three columns indicating the current weather conditions (sunny, cloudy, ...), wind direction, precipitation and temperature forecasted for the next three hours. Tap on this widget to cycle through the 12 hour forecast. If you have a route loaded, the forecast widget will show the forecasted weather along points of the route, with an estimated traveled distance per hour of 20 km / 12 miles by default.
|
||||||
- Current weather (graphical, 1x1 field): Shows current weather conditions (same as forecast widget, but only for the current time).
|
- Current weather (graphical, 1x1 field): Shows current weather conditions (same as forecast widget, but only for the current time). Tap on this widget to open the headwind app with a forecast overview.
|
||||||
- Relative grade (numerical): Shows the relative grade. The relative grade is calculated by estimating the force of the headwind, and then calculating the gradient you would need to ride at to experience this resistance if there was no wind. Example: If you are riding on an actual gradient of 2 %, face a headwind of 18 km/h while riding at 29 km/h, the relative grade will be shown as 5.2 % (with 3.2 % added to the actual grade due to the headwind).
|
- Relative grade (numerical): Shows the relative grade. The relative grade is calculated by estimating the force of the headwind, and then calculating the gradient you would need to ride at to experience this resistance if there was no wind. Example: If you are riding on an actual gradient of 2 %, face a headwind of 18 km/h while riding at 29 km/h, the relative grade will be shown as 5.2 % (with 3.2 % added to the actual grade due to the headwind).
|
||||||
- Relative elevation gain (numerical): Shows the relative elegation gain. The relative elevation gain is calculated using the relative grade and is an estimation of how much climbing would have been equivalent to the headwind you faced during the ride.
|
- Relative elevation gain (numerical): Shows the relative elegation gain. The relative elevation gain is calculated using the relative grade and is an estimation of how much climbing would have been equivalent to the headwind you faced during the ride.
|
||||||
- Additionally, data fields that only show the current data value for headwind speed, humidity, cloud cover, absolute wind speed, absolute wind gust speed, absolute wind direction, rainfall and surface pressure can be added if desired.
|
- Additionally, data fields that only show the current data value for headwind speed, humidity, cloud cover, absolute wind speed, absolute wind gust speed, absolute wind direction, rainfall and surface pressure can be added if desired.
|
||||||
@ -41,7 +41,7 @@ If the app cannot connect to the weather service, it will retry the download eve
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
- Icons are from [boxicons.com](https://boxicons.com) ([MIT-licensed](icon_credits.txt)) and the [Google Noto Color Emoji font](https://fonts.google.com/noto/specimen/Noto+Color+Emoji) (SIL Open Font License 1.1)
|
- Icons are from [boxicons.com](https://boxicons.com) ([MIT-licensed](icon_credits.txt))
|
||||||
- Made possible by the generous usage terms of [open-meteo.com](https://open-meteo.com)
|
- Made possible by the generous usage terms of [open-meteo.com](https://open-meteo.com)
|
||||||
- Interfaces with [openweathermap.org](https://openweathermap.org)
|
- Interfaces with [openweathermap.org](https://openweathermap.org)
|
||||||
- Uses [karoo-ext](https://github.com/hammerheadnav/karoo-ext) (Apache2-licensed)
|
- Uses [karoo-ext](https://github.com/hammerheadnav/karoo-ext) (Apache2-licensed)
|
||||||
|
|||||||
3
app/.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
/build
|
/build
|
||||||
|
/google-services.json
|
||||||
|
|||||||
@ -5,6 +5,8 @@ plugins {
|
|||||||
alias(libs.plugins.jetbrains.kotlin.android)
|
alias(libs.plugins.jetbrains.kotlin.android)
|
||||||
alias(libs.plugins.compose.compiler)
|
alias(libs.plugins.compose.compiler)
|
||||||
kotlin("plugin.serialization") version "2.0.20"
|
kotlin("plugin.serialization") version "2.0.20"
|
||||||
|
alias(libs.plugins.google.gms.google.services)
|
||||||
|
alias(libs.plugins.google.firebase.crashlytics)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -35,6 +37,9 @@ android {
|
|||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
isMinifyEnabled = false
|
isMinifyEnabled = false
|
||||||
|
firebaseCrashlytics {
|
||||||
|
mappingFileUploadEnabled = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
signingConfig = signingConfigs.getByName("release")
|
signingConfig = signingConfigs.getByName("release")
|
||||||
@ -55,6 +60,24 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register("addGoogleServicesJson") {
|
||||||
|
description = "Adds google-services.json to the project"
|
||||||
|
group = "build"
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
val googleServicesJson = System.getenv("GOOGLE_SERVICES_JSON_BASE64")
|
||||||
|
?.let { Base64.getDecoder().decode(it) }
|
||||||
|
?.let { String(it) }
|
||||||
|
if (googleServicesJson != null) {
|
||||||
|
val jsonFile = file("$projectDir/google-services.json")
|
||||||
|
jsonFile.writeText(googleServicesJson)
|
||||||
|
println("Added google-services.json to the project")
|
||||||
|
} else {
|
||||||
|
println("No GOOGLE_SERVICES_JSON_BASE64 environment variable found, skipping...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tasks.register("generateManifest") {
|
tasks.register("generateManifest") {
|
||||||
description = "Generates manifest.json with current version information"
|
description = "Generates manifest.json with current version information"
|
||||||
group = "build"
|
group = "build"
|
||||||
@ -70,8 +93,11 @@ tasks.register("generateManifest") {
|
|||||||
"latestVersionCode" to android.defaultConfig.versionCode,
|
"latestVersionCode" to android.defaultConfig.versionCode,
|
||||||
"developer" to "github.com/timklge",
|
"developer" to "github.com/timklge",
|
||||||
"description" to "Open-source extension that provides headwind direction, wind speed, forecast and other weather data fields.",
|
"description" to "Open-source extension that provides headwind direction, wind speed, forecast and other weather data fields.",
|
||||||
"releaseNotes" to "* Remove crashlytics\n" +
|
"releaseNotes" to "* Reduce refresh rate on K2, add refresh rate setting\n" +
|
||||||
"* Reduce refresh rate on K2, add refresh rate setting\n" +
|
"* Fix weather data download from Open-Meteo via iOS companion app (thx @keefar!)\n" +
|
||||||
|
"* Remove custom wind speed unit setting and always use imperial / metric as set in profile\n" +
|
||||||
|
"* Add relative grade, relative elevation gain data fields\n" +
|
||||||
|
"* Add OpenWeatherMap support contributed by lockevod\n",
|
||||||
"screenshotUrls" to listOf(
|
"screenshotUrls" to listOf(
|
||||||
"https://github.com/timklge/karoo-headwind/releases/latest/download/preview1.png",
|
"https://github.com/timklge/karoo-headwind/releases/latest/download/preview1.png",
|
||||||
"https://github.com/timklge/karoo-headwind/releases/latest/download/preview3.png",
|
"https://github.com/timklge/karoo-headwind/releases/latest/download/preview3.png",
|
||||||
@ -88,6 +114,7 @@ tasks.register("generateManifest") {
|
|||||||
|
|
||||||
tasks.named("assemble") {
|
tasks.named("assemble") {
|
||||||
dependsOn("generateManifest")
|
dependsOn("generateManifest")
|
||||||
|
dependsOn("addGoogleServicesJson")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -102,5 +129,6 @@ dependencies {
|
|||||||
implementation(libs.androidx.glance.appwidget)
|
implementation(libs.androidx.glance.appwidget)
|
||||||
implementation(libs.androidx.glance.appwidget.preview)
|
implementation(libs.androidx.glance.appwidget.preview)
|
||||||
implementation(libs.androidx.glance.preview)
|
implementation(libs.androidx.glance.preview)
|
||||||
|
implementation(libs.firebase.crashlytics)
|
||||||
testImplementation(kotlin("test"))
|
testImplementation(kotlin("test"))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -210,22 +210,6 @@ fun Context.streamCurrentForecastWeatherData(): Flow<WeatherDataResponse?> {
|
|||||||
}.distinctUntilChanged()
|
}.distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun lerp(
|
|
||||||
start: Double,
|
|
||||||
end: Double,
|
|
||||||
factor: Double
|
|
||||||
): Double {
|
|
||||||
return start + (end - start) * factor
|
|
||||||
}
|
|
||||||
|
|
||||||
fun lerp(
|
|
||||||
start: Int,
|
|
||||||
end: Int,
|
|
||||||
factor: Double
|
|
||||||
): Int {
|
|
||||||
return (start + (end - start) * factor).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun lerpNullable(
|
fun lerpNullable(
|
||||||
start: Double?,
|
start: Double?,
|
||||||
end: Double?,
|
end: Double?,
|
||||||
@ -282,18 +266,17 @@ fun lerpWeather(
|
|||||||
return WeatherData(
|
return WeatherData(
|
||||||
time = (start.time + (end.time - start.time) * factor).toLong(),
|
time = (start.time + (end.time - start.time) * factor).toLong(),
|
||||||
temperature = start.temperature + (end.temperature - start.temperature) * factor,
|
temperature = start.temperature + (end.temperature - start.temperature) * factor,
|
||||||
relativeHumidity = lerp(start.relativeHumidity, end.relativeHumidity, factor),
|
relativeHumidity = lerpNullable(start.relativeHumidity, end.relativeHumidity, factor),
|
||||||
precipitation = start.precipitation + (end.precipitation - start.precipitation) * factor,
|
precipitation = start.precipitation + (end.precipitation - start.precipitation) * factor,
|
||||||
precipitationProbability = lerpNullable(start.precipitationProbability, end.precipitationProbability, factor),
|
precipitationProbability = lerpNullable(start.precipitationProbability, end.precipitationProbability, factor),
|
||||||
cloudCover = lerp(start.cloudCover, end.cloudCover, factor),
|
cloudCover = lerpNullable(start.cloudCover, end.cloudCover, factor),
|
||||||
surfacePressure = lerp(start.surfacePressure, end.surfacePressure, factor),
|
surfacePressure = lerpNullable(start.surfacePressure, end.surfacePressure, factor),
|
||||||
sealevelPressure = lerp(start.sealevelPressure, end.sealevelPressure, factor),
|
sealevelPressure = lerpNullable(start.sealevelPressure, end.sealevelPressure, factor),
|
||||||
windSpeed = start.windSpeed + (end.windSpeed - start.windSpeed) * factor,
|
windSpeed = start.windSpeed + (end.windSpeed - start.windSpeed) * factor,
|
||||||
windDirection = lerpAngle(start.windDirection, end.windDirection, factor),
|
windDirection = lerpAngle(start.windDirection, end.windDirection, factor),
|
||||||
windGusts = start.windGusts + (end.windGusts - start.windGusts) * factor,
|
windGusts = start.windGusts + (end.windGusts - start.windGusts) * factor,
|
||||||
weatherCode = closestWeatherData.weatherCode,
|
weatherCode = closestWeatherData.weatherCode,
|
||||||
isForecast = closestWeatherData.isForecast,
|
isForecast = closestWeatherData.isForecast
|
||||||
isNight = closestWeatherData.isNight,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package de.timklge.karooheadwind
|
package de.timklge.karooheadwind
|
||||||
|
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.models.ActiveRidePage
|
|
||||||
import io.hammerhead.karooext.models.OnLocationChanged
|
import io.hammerhead.karooext.models.OnLocationChanged
|
||||||
import io.hammerhead.karooext.models.OnNavigationState
|
import io.hammerhead.karooext.models.OnNavigationState
|
||||||
import io.hammerhead.karooext.models.OnStreamState
|
import io.hammerhead.karooext.models.OnStreamState
|
||||||
@ -13,7 +12,6 @@ import kotlinx.coroutines.delay
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.conflate
|
import kotlinx.coroutines.flow.conflate
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.sample
|
import kotlinx.coroutines.flow.sample
|
||||||
import kotlinx.coroutines.flow.transform
|
import kotlinx.coroutines.flow.transform
|
||||||
|
|
||||||
@ -66,23 +64,4 @@ fun<T> Flow<T>.throttle(timeout: Long): Flow<T> = this
|
|||||||
.transform {
|
.transform {
|
||||||
emit(it)
|
emit(it)
|
||||||
delay(timeout)
|
delay(timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KarooSystemService.streamActiveRidePage(): Flow<ActiveRidePage> {
|
|
||||||
return callbackFlow {
|
|
||||||
val listenerId = addConsumer { activeRidePage: ActiveRidePage ->
|
|
||||||
trySendBlocking(activeRidePage)
|
|
||||||
}
|
|
||||||
awaitClose {
|
|
||||||
removeConsumer(listenerId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun KarooSystemService.streamDatatypeIsVisible(
|
|
||||||
datatype: String,
|
|
||||||
): Flow<Boolean> {
|
|
||||||
return streamActiveRidePage().map { page ->
|
|
||||||
page.page.elements.any { it.dataTypeId == datatype }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -50,6 +50,7 @@ data class HeadwindWidgetSettings(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Moded with openweahtermap.org
|
||||||
@Serializable
|
@Serializable
|
||||||
data class HeadwindStats(
|
data class HeadwindStats(
|
||||||
val lastSuccessfulWeatherRequest: Long? = null,
|
val lastSuccessfulWeatherRequest: Long? = null,
|
||||||
@ -69,8 +70,8 @@ enum class RefreshRate(val id: String, val k2Ms: Long, val k3Ms: Long) {
|
|||||||
SLOW("slow", 5_000L, 3_000L),
|
SLOW("slow", 5_000L, 3_000L),
|
||||||
MINIMUM("minimum", 10_000L, 10_000L);
|
MINIMUM("minimum", 10_000L, 10_000L);
|
||||||
|
|
||||||
fun getDescription(isOnK2: Boolean): String {
|
fun getDescription(karooSystemService: KarooSystemService): String {
|
||||||
return if (isOnK2) {
|
return if (karooSystemService.hardwareType == HardwareType.K2) {
|
||||||
when (this) {
|
when (this) {
|
||||||
FAST -> "Fast (1s)"
|
FAST -> "Fast (1s)"
|
||||||
STANDARD -> "Standard (2s)"
|
STANDARD -> "Standard (2s)"
|
||||||
|
|||||||
@ -3,24 +3,16 @@ package de.timklge.karooheadwind.datatypes
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import de.timklge.karooheadwind.KarooHeadwindExtension
|
import de.timklge.karooheadwind.KarooHeadwindExtension
|
||||||
import de.timklge.karooheadwind.streamCurrentWeatherData
|
|
||||||
import de.timklge.karooheadwind.streamUserProfile
|
|
||||||
import de.timklge.karooheadwind.throttle
|
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
|
import de.timklge.karooheadwind.streamCurrentWeatherData
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.extension.DataTypeImpl
|
import io.hammerhead.karooext.extension.DataTypeImpl
|
||||||
import io.hammerhead.karooext.internal.Emitter
|
import io.hammerhead.karooext.internal.Emitter
|
||||||
import io.hammerhead.karooext.internal.ViewEmitter
|
|
||||||
import io.hammerhead.karooext.models.DataPoint
|
import io.hammerhead.karooext.models.DataPoint
|
||||||
import io.hammerhead.karooext.models.DataType
|
import io.hammerhead.karooext.models.DataType
|
||||||
import io.hammerhead.karooext.models.StreamState
|
import io.hammerhead.karooext.models.StreamState
|
||||||
import io.hammerhead.karooext.models.UpdateGraphicConfig
|
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
|
||||||
import io.hammerhead.karooext.models.ViewConfig
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.filter
|
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@ -29,25 +21,17 @@ abstract class BaseDataType(
|
|||||||
private val applicationContext: Context,
|
private val applicationContext: Context,
|
||||||
dataTypeId: String
|
dataTypeId: String
|
||||||
) : DataTypeImpl("karoo-headwind", dataTypeId) {
|
) : DataTypeImpl("karoo-headwind", dataTypeId) {
|
||||||
abstract fun getValue(data: WeatherData, userProfile: UserProfile): Double?
|
abstract fun getValue(data: WeatherData): Double?
|
||||||
|
|
||||||
open fun getFormatDataType(): String? = null
|
|
||||||
|
|
||||||
override fun startStream(emitter: Emitter<StreamState>) {
|
override fun startStream(emitter: Emitter<StreamState>) {
|
||||||
Log.d(KarooHeadwindExtension.TAG, "start $dataTypeId stream")
|
Log.d(KarooHeadwindExtension.TAG, "start $dataTypeId stream")
|
||||||
val job = CoroutineScope(Dispatchers.IO).launch {
|
val job = CoroutineScope(Dispatchers.IO).launch {
|
||||||
data class StreamData(val weatherData: WeatherData, val userProfile: UserProfile)
|
val currentWeatherData = applicationContext.streamCurrentWeatherData(karooSystemService)
|
||||||
|
|
||||||
val currentWeatherData = combine(applicationContext.streamCurrentWeatherData(karooSystemService).filterNotNull(), karooSystemService.streamUserProfile()) { weatherData, userProfile ->
|
currentWeatherData
|
||||||
StreamData(weatherData, userProfile)
|
.filterNotNull()
|
||||||
}
|
.collect { data ->
|
||||||
|
val value = getValue(data)
|
||||||
val refreshRate = karooSystemService.getRefreshRateInMilliseconds(applicationContext)
|
|
||||||
|
|
||||||
currentWeatherData.filterNotNull()
|
|
||||||
.throttle(refreshRate)
|
|
||||||
.collect { (data, userProfile) ->
|
|
||||||
val value = getValue(data, userProfile)
|
|
||||||
Log.d(KarooHeadwindExtension.TAG, "$dataTypeId: $value")
|
Log.d(KarooHeadwindExtension.TAG, "$dataTypeId: $value")
|
||||||
|
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
@ -62,12 +46,4 @@ abstract class BaseDataType(
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startView(context: Context, config: ViewConfig, emitter: ViewEmitter) {
|
|
||||||
Log.d(KarooHeadwindExtension.TAG, "Starting $dataTypeId view with $emitter")
|
|
||||||
|
|
||||||
if (getFormatDataType() != null){
|
|
||||||
emitter.onNext(UpdateGraphicConfig(formatDataTypeId = getFormatDataType()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,10 +3,9 @@ package de.timklge.karooheadwind.datatypes
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
|
||||||
|
|
||||||
class CloudCoverDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "cloudCover"){
|
class CloudCoverDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "cloudCover"){
|
||||||
override fun getValue(data: WeatherData, userProfile: UserProfile): Double? {
|
override fun getValue(data: WeatherData): Double? {
|
||||||
return data.cloudCover
|
return data.cloudCover
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -28,22 +28,18 @@ import de.timklge.karooheadwind.KarooHeadwindExtension
|
|||||||
import de.timklge.karooheadwind.R
|
import de.timklge.karooheadwind.R
|
||||||
import de.timklge.karooheadwind.TemperatureUnit
|
import de.timklge.karooheadwind.TemperatureUnit
|
||||||
import de.timklge.karooheadwind.UpcomingRoute
|
import de.timklge.karooheadwind.UpcomingRoute
|
||||||
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
|
import de.timklge.karooheadwind.weatherprovider.WeatherDataForLocation
|
||||||
import de.timklge.karooheadwind.WeatherDataProvider
|
import de.timklge.karooheadwind.WeatherDataProvider
|
||||||
|
import de.timklge.karooheadwind.weatherprovider.WeatherDataResponse
|
||||||
|
import de.timklge.karooheadwind.weatherprovider.WeatherInterpretation
|
||||||
import de.timklge.karooheadwind.getHeadingFlow
|
import de.timklge.karooheadwind.getHeadingFlow
|
||||||
import de.timklge.karooheadwind.streamCurrentForecastWeatherData
|
import de.timklge.karooheadwind.streamCurrentForecastWeatherData
|
||||||
import de.timklge.karooheadwind.streamDatatypeIsVisible
|
|
||||||
import de.timklge.karooheadwind.streamSettings
|
import de.timklge.karooheadwind.streamSettings
|
||||||
import de.timklge.karooheadwind.streamUpcomingRoute
|
import de.timklge.karooheadwind.streamUpcomingRoute
|
||||||
import de.timklge.karooheadwind.streamUserProfile
|
import de.timklge.karooheadwind.streamUserProfile
|
||||||
import de.timklge.karooheadwind.streamWidgetSettings
|
import de.timklge.karooheadwind.streamWidgetSettings
|
||||||
import de.timklge.karooheadwind.throttle
|
import de.timklge.karooheadwind.throttle
|
||||||
import de.timklge.karooheadwind.util.celciusInUserUnit
|
|
||||||
import de.timklge.karooheadwind.util.millimetersInUserUnit
|
|
||||||
import de.timklge.karooheadwind.util.msInUserUnit
|
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherDataForLocation
|
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherDataResponse
|
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherInterpretation
|
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.extension.DataTypeImpl
|
import io.hammerhead.karooext.extension.DataTypeImpl
|
||||||
import io.hammerhead.karooext.internal.ViewEmitter
|
import io.hammerhead.karooext.internal.ViewEmitter
|
||||||
@ -58,7 +54,6 @@ import kotlinx.coroutines.delay
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.filter
|
|
||||||
import kotlinx.coroutines.flow.firstOrNull
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -83,8 +78,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
timeLabel: String,
|
timeLabel: String,
|
||||||
dateLabel: String?,
|
dateLabel: String?,
|
||||||
distance: Double?,
|
distance: Double?,
|
||||||
isImperial: Boolean,
|
isImperial: Boolean)
|
||||||
isNight: Boolean)
|
|
||||||
|
|
||||||
@OptIn(ExperimentalGlanceRemoteViewsApi::class)
|
@OptIn(ExperimentalGlanceRemoteViewsApi::class)
|
||||||
private val glance = GlanceRemoteViews()
|
private val glance = GlanceRemoteViews()
|
||||||
@ -95,7 +89,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
|
|
||||||
data class StreamData(val data: WeatherDataResponse?, val settings: SettingsAndProfile,
|
data class StreamData(val data: WeatherDataResponse?, val settings: SettingsAndProfile,
|
||||||
val widgetSettings: HeadwindWidgetSettings? = null,
|
val widgetSettings: HeadwindWidgetSettings? = null,
|
||||||
val headingResponse: HeadingResponse? = null, val upcomingRoute: UpcomingRoute? = null, val isVisible: Boolean)
|
val headingResponse: HeadingResponse? = null, val upcomingRoute: UpcomingRoute? = null)
|
||||||
|
|
||||||
data class SettingsAndProfile(val settings: HeadwindSettings, val isImperial: Boolean, val isImperialTemperature: Boolean)
|
data class SettingsAndProfile(val settings: HeadwindSettings, val isImperial: Boolean, val isImperialTemperature: Boolean)
|
||||||
|
|
||||||
@ -119,7 +113,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
WeatherData(
|
WeatherData(
|
||||||
time = forecastTime,
|
time = forecastTime,
|
||||||
temperature = forecastTemperature,
|
temperature = forecastTemperature,
|
||||||
relativeHumidity = 20,
|
relativeHumidity = 20.0,
|
||||||
precipitation = forecastPrecipitation,
|
precipitation = forecastPrecipitation,
|
||||||
cloudCover = 3.0,
|
cloudCover = 3.0,
|
||||||
sealevelPressure = 1013.25,
|
sealevelPressure = 1013.25,
|
||||||
@ -129,8 +123,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
windDirection = forecastWindDirection,
|
windDirection = forecastWindDirection,
|
||||||
windGusts = forecastWindGusts,
|
windGusts = forecastWindGusts,
|
||||||
weatherCode = forecastWeatherCode,
|
weatherCode = forecastWeatherCode,
|
||||||
isForecast = true,
|
isForecast = true
|
||||||
isNight = it < 2
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +135,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
current = WeatherData(
|
current = WeatherData(
|
||||||
time = timeAtFullHour,
|
time = timeAtFullHour,
|
||||||
temperature = 20.0,
|
temperature = 20.0,
|
||||||
relativeHumidity = 20,
|
relativeHumidity = 20.0,
|
||||||
precipitation = 0.0,
|
precipitation = 0.0,
|
||||||
cloudCover = 3.0,
|
cloudCover = 3.0,
|
||||||
sealevelPressure = 1013.25,
|
sealevelPressure = 1013.25,
|
||||||
@ -151,8 +144,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
windDirection = 180.0,
|
windDirection = 180.0,
|
||||||
windGusts = 10.0,
|
windGusts = 10.0,
|
||||||
weatherCode = WeatherInterpretation.getKnownWeatherCodes().random(),
|
weatherCode = WeatherInterpretation.getKnownWeatherCodes().random(),
|
||||||
isForecast = false,
|
isForecast = false
|
||||||
isNight = false
|
|
||||||
),
|
),
|
||||||
coords = GpsCoordinates(0.0, 0.0, distanceAlongRoute = index * distancePerHour),
|
coords = GpsCoordinates(0.0, 0.0, distanceAlongRoute = index * distancePerHour),
|
||||||
timezone = "UTC",
|
timezone = "UTC",
|
||||||
@ -169,8 +161,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
HeadwindSettings(),
|
HeadwindSettings(),
|
||||||
settingsAndProfile?.isImperial == true,
|
settingsAndProfile?.isImperial == true,
|
||||||
settingsAndProfile?.isImperialTemperature == true
|
settingsAndProfile?.isImperialTemperature == true
|
||||||
),
|
)
|
||||||
isVisible = true
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -212,23 +203,14 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
if (oldDistance == null || newDistance == null) return@distinctUntilChanged false
|
if (oldDistance == null || newDistance == null) return@distinctUntilChanged false
|
||||||
|
|
||||||
abs(oldDistance - newDistance) < 1_000
|
abs(oldDistance - newDistance) < 1_000
|
||||||
},
|
}
|
||||||
karooSystem.streamDatatypeIsVisible(dataTypeId)
|
) { weatherData, settings, widgetSettings, heading, upcomingRoute ->
|
||||||
) { data ->
|
|
||||||
val weatherData = data[0] as WeatherDataResponse?
|
|
||||||
val settings = data[1] as SettingsAndProfile
|
|
||||||
val widgetSettings = data[2] as HeadwindWidgetSettings?
|
|
||||||
val heading = data[3] as HeadingResponse?
|
|
||||||
val upcomingRoute = data[4] as UpcomingRoute?
|
|
||||||
val isVisible = data[5] as Boolean
|
|
||||||
|
|
||||||
StreamData(
|
StreamData(
|
||||||
data = weatherData,
|
data = weatherData,
|
||||||
settings = settings,
|
settings = settings,
|
||||||
widgetSettings = widgetSettings,
|
widgetSettings = widgetSettings,
|
||||||
headingResponse = heading,
|
headingResponse = heading,
|
||||||
upcomingRoute = upcomingRoute,
|
upcomingRoute = upcomingRoute
|
||||||
isVisible = isVisible
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,7 +218,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
val viewJob = CoroutineScope(Dispatchers.IO).launch {
|
val viewJob = CoroutineScope(Dispatchers.IO).launch {
|
||||||
emitter.onNext(ShowCustomStreamState("", null))
|
emitter.onNext(ShowCustomStreamState("", null))
|
||||||
|
|
||||||
dataFlow.filter { it.isVisible }.collect { (allData, settingsAndProfile, widgetSettings, headingResponse, upcomingRoute) ->
|
dataFlow.collect { (allData, settingsAndProfile, widgetSettings, headingResponse, upcomingRoute) ->
|
||||||
Log.d(KarooHeadwindExtension.TAG, "Updating weather forecast view")
|
Log.d(KarooHeadwindExtension.TAG, "Updating weather forecast view")
|
||||||
|
|
||||||
if (allData?.data.isNullOrEmpty()){
|
if (allData?.data.isNullOrEmpty()){
|
||||||
@ -314,17 +296,16 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
arrowBitmap = baseBitmap,
|
arrowBitmap = baseBitmap,
|
||||||
current = interpretation,
|
current = interpretation,
|
||||||
windBearing = data.current.windDirection.roundToInt(),
|
windBearing = data.current.windDirection.roundToInt(),
|
||||||
windSpeed = msInUserUnit(data.current.windSpeed, settingsAndProfile.isImperial).roundToInt(),
|
windSpeed = data.current.windSpeed.roundToInt(),
|
||||||
windGusts = msInUserUnit(data.current.windGusts, settingsAndProfile.isImperial).roundToInt(),
|
windGusts = data.current.windGusts.roundToInt(),
|
||||||
precipitation = millimetersInUserUnit(data.current.precipitation, settingsAndProfile.isImperial),
|
precipitation = data.current.precipitation,
|
||||||
precipitationProbability = null,
|
precipitationProbability = null,
|
||||||
temperature = celciusInUserUnit(data.current.temperature, settingsAndProfile.isImperialTemperature).roundToInt(),
|
temperature = data.current.temperature.roundToInt(),
|
||||||
temperatureUnit = if (settingsAndProfile.isImperialTemperature) TemperatureUnit.FAHRENHEIT else TemperatureUnit.CELSIUS,
|
temperatureUnit = if (settingsAndProfile.isImperialTemperature) TemperatureUnit.FAHRENHEIT else TemperatureUnit.CELSIUS,
|
||||||
timeLabel = formattedTime,
|
timeLabel = formattedTime,
|
||||||
dateLabel = if (hasNewDate) formattedDate else null,
|
dateLabel = if (hasNewDate) formattedDate else null,
|
||||||
distance = null,
|
distance = null,
|
||||||
isImperial = settingsAndProfile.isImperial,
|
isImperial = settingsAndProfile.isImperial
|
||||||
isNight = data.current.isNight
|
|
||||||
)
|
)
|
||||||
|
|
||||||
previousDate = formattedDate
|
previousDate = formattedDate
|
||||||
@ -340,17 +321,16 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
|
|||||||
arrowBitmap = baseBitmap,
|
arrowBitmap = baseBitmap,
|
||||||
current = interpretation,
|
current = interpretation,
|
||||||
windBearing = weatherData?.windDirection?.roundToInt() ?: 0,
|
windBearing = weatherData?.windDirection?.roundToInt() ?: 0,
|
||||||
windSpeed = msInUserUnit(weatherData?.windSpeed ?: 0.0, settingsAndProfile.isImperial).roundToInt(),
|
windSpeed = weatherData?.windSpeed?.roundToInt() ?: 0,
|
||||||
windGusts = msInUserUnit(weatherData?.windGusts ?: 0.0, settingsAndProfile.isImperial).roundToInt(),
|
windGusts = weatherData?.windGusts?.roundToInt() ?: 0,
|
||||||
precipitation = millimetersInUserUnit(weatherData?.precipitation ?: 0.0, settingsAndProfile.isImperial),
|
precipitation = weatherData?.precipitation ?: 0.0,
|
||||||
precipitationProbability = weatherData?.precipitationProbability?.toInt(),
|
precipitationProbability = weatherData?.precipitationProbability?.toInt(),
|
||||||
temperature = celciusInUserUnit(weatherData?.temperature ?: 0.0, settingsAndProfile.isImperialTemperature).roundToInt(),
|
temperature = weatherData?.temperature?.roundToInt() ?: 0,
|
||||||
temperatureUnit = if (settingsAndProfile.isImperialTemperature) TemperatureUnit.FAHRENHEIT else TemperatureUnit.CELSIUS,
|
temperatureUnit = if (settingsAndProfile.isImperialTemperature) TemperatureUnit.FAHRENHEIT else TemperatureUnit.CELSIUS,
|
||||||
timeLabel = formattedTime,
|
timeLabel = formattedTime,
|
||||||
dateLabel = if (hasNewDate) formattedDate else null,
|
dateLabel = if (hasNewDate) formattedDate else null,
|
||||||
distance = if (settingsAndProfile.settings.showDistanceInForecast) distanceFromCurrent else null,
|
distance = if (settingsAndProfile.settings.showDistanceInForecast) distanceFromCurrent else null,
|
||||||
isImperial = settingsAndProfile.isImperial,
|
isImperial = settingsAndProfile.isImperial
|
||||||
isNight = weatherData?.isNight == true
|
|
||||||
)
|
)
|
||||||
|
|
||||||
previousDate = formattedDate
|
previousDate = formattedDate
|
||||||
|
|||||||
@ -34,16 +34,16 @@ fun GraphicalForecast(
|
|||||||
distance: Double? = null,
|
distance: Double? = null,
|
||||||
timeLabel: String? = null,
|
timeLabel: String? = null,
|
||||||
rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally,
|
rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally,
|
||||||
isImperial: Boolean?,
|
isImperial: Boolean?
|
||||||
isNight: Boolean,
|
|
||||||
) {
|
) {
|
||||||
Column(modifier = GlanceModifier.fillMaxHeight().padding(1.dp).width(86.dp), horizontalAlignment = rowAlignment) {
|
Column(modifier = GlanceModifier.fillMaxHeight().padding(1.dp).width(86.dp), horizontalAlignment = rowAlignment) {
|
||||||
Row(modifier = GlanceModifier.defaultWeight().wrapContentWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) {
|
Row(modifier = GlanceModifier.defaultWeight().wrapContentWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) {
|
||||||
Image(
|
Image(
|
||||||
modifier = GlanceModifier.defaultWeight().wrapContentWidth().padding(1.dp),
|
modifier = GlanceModifier.defaultWeight().wrapContentWidth().padding(1.dp),
|
||||||
provider = ImageProvider(getWeatherIcon(current, isNight)),
|
provider = ImageProvider(getWeatherIcon(current)),
|
||||||
contentDescription = "Current weather information",
|
contentDescription = "Current weather information",
|
||||||
contentScale = ContentScale.Fit,
|
contentScale = ContentScale.Fit,
|
||||||
|
colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,15 +96,13 @@ class GraphicalForecastDataType(karooSystem: KarooSystemService) : ForecastDataT
|
|||||||
timeLabel: String,
|
timeLabel: String,
|
||||||
dateLabel: String?,
|
dateLabel: String?,
|
||||||
distance: Double?,
|
distance: Double?,
|
||||||
isImperial: Boolean,
|
isImperial: Boolean
|
||||||
isNight: Boolean,
|
|
||||||
) {
|
) {
|
||||||
GraphicalForecast(
|
GraphicalForecast(
|
||||||
current = current,
|
current = current,
|
||||||
distance = distance,
|
distance = distance,
|
||||||
timeLabel = timeLabel,
|
timeLabel = timeLabel,
|
||||||
isImperial = isImperial,
|
isImperial = isImperial
|
||||||
isNight = isNight
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -12,11 +12,8 @@ import de.timklge.karooheadwind.KarooHeadwindExtension
|
|||||||
import de.timklge.karooheadwind.WindDirectionIndicatorSetting
|
import de.timklge.karooheadwind.WindDirectionIndicatorSetting
|
||||||
import de.timklge.karooheadwind.getRelativeHeadingFlow
|
import de.timklge.karooheadwind.getRelativeHeadingFlow
|
||||||
import de.timklge.karooheadwind.streamCurrentWeatherData
|
import de.timklge.karooheadwind.streamCurrentWeatherData
|
||||||
import de.timklge.karooheadwind.streamDatatypeIsVisible
|
|
||||||
import de.timklge.karooheadwind.streamSettings
|
import de.timklge.karooheadwind.streamSettings
|
||||||
import de.timklge.karooheadwind.streamUserProfile
|
|
||||||
import de.timklge.karooheadwind.throttle
|
import de.timklge.karooheadwind.throttle
|
||||||
import de.timklge.karooheadwind.util.msInUserUnit
|
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.extension.DataTypeImpl
|
import io.hammerhead.karooext.extension.DataTypeImpl
|
||||||
import io.hammerhead.karooext.internal.Emitter
|
import io.hammerhead.karooext.internal.Emitter
|
||||||
@ -26,7 +23,6 @@ import io.hammerhead.karooext.models.DataType
|
|||||||
import io.hammerhead.karooext.models.HardwareType
|
import io.hammerhead.karooext.models.HardwareType
|
||||||
import io.hammerhead.karooext.models.StreamState
|
import io.hammerhead.karooext.models.StreamState
|
||||||
import io.hammerhead.karooext.models.UpdateGraphicConfig
|
import io.hammerhead.karooext.models.UpdateGraphicConfig
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
|
||||||
import io.hammerhead.karooext.models.ViewConfig
|
import io.hammerhead.karooext.models.ViewConfig
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -35,7 +31,6 @@ import kotlinx.coroutines.delay
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.emitAll
|
import kotlinx.coroutines.flow.emitAll
|
||||||
import kotlinx.coroutines.flow.filter
|
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -48,54 +43,46 @@ class HeadwindDirectionDataType(
|
|||||||
) : DataTypeImpl("karoo-headwind", "headwind") {
|
) : DataTypeImpl("karoo-headwind", "headwind") {
|
||||||
private val glance = GlanceRemoteViews()
|
private val glance = GlanceRemoteViews()
|
||||||
|
|
||||||
data class StreamData(val headingResponse: HeadingResponse, val absoluteWindDirection: Double?, val windSpeed: Double?, val settings: HeadwindSettings)
|
|
||||||
|
|
||||||
private fun streamValues(): Flow<Double> = flow {
|
private fun streamValues(): Flow<Double> = flow {
|
||||||
combine(
|
karooSystem.getRelativeHeadingFlow(applicationContext)
|
||||||
karooSystem.getRelativeHeadingFlow(applicationContext),
|
.combine(applicationContext.streamCurrentWeatherData(karooSystem)) { headingResponse, data ->
|
||||||
applicationContext.streamCurrentWeatherData(karooSystem),
|
StreamData(headingResponse, data?.windDirection, data?.windSpeed)
|
||||||
applicationContext.streamSettings(karooSystem),
|
|
||||||
) { headingResponse, currentWeather, settings ->
|
|
||||||
StreamData(
|
|
||||||
headingResponse,
|
|
||||||
currentWeather?.windDirection,
|
|
||||||
currentWeather?.windSpeed,
|
|
||||||
settings,
|
|
||||||
)
|
|
||||||
}.collect { streamData ->
|
|
||||||
val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff
|
|
||||||
|
|
||||||
var returnValue = 0.0
|
|
||||||
if (value == null || streamData.absoluteWindDirection == null || streamData.windSpeed == null){
|
|
||||||
var errorCode = 1.0
|
|
||||||
var headingResponse = streamData.headingResponse
|
|
||||||
|
|
||||||
if (headingResponse is HeadingResponse.Value && (streamData.absoluteWindDirection == null || streamData.windSpeed == null)){
|
|
||||||
headingResponse = HeadingResponse.NoWeatherData
|
|
||||||
}
|
}
|
||||||
|
.combine(applicationContext.streamSettings(karooSystem)) { data, settings -> data.copy(settings = settings) }
|
||||||
|
.collect { streamData ->
|
||||||
|
val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff
|
||||||
|
|
||||||
if (streamData.settings.welcomeDialogAccepted == false){
|
var returnValue = 0.0
|
||||||
errorCode = ERROR_APP_NOT_SET_UP.toDouble()
|
if (value == null || streamData.absoluteWindDirection == null || streamData.settings == null || streamData.windSpeed == null){
|
||||||
} else if (headingResponse is HeadingResponse.NoGps){
|
var errorCode = 1.0
|
||||||
errorCode = ERROR_NO_GPS.toDouble()
|
var headingResponse = streamData.headingResponse
|
||||||
|
|
||||||
|
if (headingResponse is HeadingResponse.Value && (streamData.absoluteWindDirection == null || streamData.windSpeed == null)){
|
||||||
|
headingResponse = HeadingResponse.NoWeatherData
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streamData.settings?.welcomeDialogAccepted == false){
|
||||||
|
errorCode = ERROR_APP_NOT_SET_UP.toDouble()
|
||||||
|
} else if (headingResponse is HeadingResponse.NoGps){
|
||||||
|
errorCode = ERROR_NO_GPS.toDouble()
|
||||||
|
} else {
|
||||||
|
errorCode = ERROR_NO_WEATHER_DATA.toDouble()
|
||||||
|
}
|
||||||
|
|
||||||
|
returnValue = errorCode
|
||||||
} else {
|
} else {
|
||||||
errorCode = ERROR_NO_WEATHER_DATA.toDouble()
|
var windDirection = when (streamData.settings.windDirectionIndicatorSetting){
|
||||||
|
WindDirectionIndicatorSetting.HEADWIND_DIRECTION -> value
|
||||||
|
WindDirectionIndicatorSetting.WIND_DIRECTION -> streamData.absoluteWindDirection + 180
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windDirection < 0) windDirection += 360
|
||||||
|
|
||||||
|
returnValue = windDirection
|
||||||
}
|
}
|
||||||
|
|
||||||
returnValue = errorCode
|
emit(returnValue)
|
||||||
} else {
|
|
||||||
var windDirection = when (streamData.settings.windDirectionIndicatorSetting){
|
|
||||||
WindDirectionIndicatorSetting.HEADWIND_DIRECTION -> value
|
|
||||||
WindDirectionIndicatorSetting.WIND_DIRECTION -> streamData.absoluteWindDirection + 180
|
|
||||||
}
|
|
||||||
|
|
||||||
if (windDirection < 0) windDirection += 360
|
|
||||||
|
|
||||||
returnValue = windDirection
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(returnValue)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startStream(emitter: Emitter<StreamState>) {
|
override fun startStream(emitter: Emitter<StreamState>) {
|
||||||
@ -109,12 +96,9 @@ class HeadwindDirectionDataType(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class DirectionAndSpeed(
|
data class StreamData(val headingResponse: HeadingResponse?, val absoluteWindDirection: Double?, val windSpeed: Double?, val settings: HeadwindSettings? = null)
|
||||||
val bearing: Double,
|
|
||||||
val speed: Double?,
|
data class DirectionAndSpeed(val bearing: Double, val speed: Double?)
|
||||||
val isVisible: Boolean,
|
|
||||||
val isImperial: Boolean
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun previewFlow(): Flow<DirectionAndSpeed> {
|
private fun previewFlow(): Flow<DirectionAndSpeed> {
|
||||||
return flow {
|
return flow {
|
||||||
@ -122,12 +106,7 @@ class HeadwindDirectionDataType(
|
|||||||
val bearing = (0..360).random().toDouble()
|
val bearing = (0..360).random().toDouble()
|
||||||
val windSpeed = (0..20).random()
|
val windSpeed = (0..20).random()
|
||||||
|
|
||||||
emit(DirectionAndSpeed(
|
emit(DirectionAndSpeed(bearing, windSpeed.toDouble()))
|
||||||
bearing,
|
|
||||||
windSpeed.toDouble(),
|
|
||||||
true,
|
|
||||||
true
|
|
||||||
))
|
|
||||||
|
|
||||||
delay(2_000)
|
delay(2_000)
|
||||||
}
|
}
|
||||||
@ -157,15 +136,15 @@ class HeadwindDirectionDataType(
|
|||||||
emitAll(UserWindSpeedDataType.streamValues(context, karooSystem))
|
emitAll(UserWindSpeedDataType.streamValues(context, karooSystem))
|
||||||
}
|
}
|
||||||
|
|
||||||
combine(directionFlow, speedFlow, karooSystem.streamDatatypeIsVisible(dataTypeId), karooSystem.streamUserProfile()) { direction, speed, isVisible, profile ->
|
combine(directionFlow, speedFlow) { direction, speed ->
|
||||||
DirectionAndSpeed(direction, speed, isVisible, profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL)
|
DirectionAndSpeed(direction, speed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val viewJob = CoroutineScope(Dispatchers.IO).launch {
|
val viewJob = CoroutineScope(Dispatchers.IO).launch {
|
||||||
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
|
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
|
||||||
|
|
||||||
flow.filter { it.isVisible }.throttle(refreshRate).collect { streamData ->
|
flow.throttle(refreshRate).collect { streamData ->
|
||||||
Log.d(KarooHeadwindExtension.TAG, "Updating headwind direction view")
|
Log.d(KarooHeadwindExtension.TAG, "Updating headwind direction view")
|
||||||
|
|
||||||
val errorCode = streamData.bearing.let { if(it < 0) it.toInt() else null }
|
val errorCode = streamData.bearing.let { if(it < 0) it.toInt() else null }
|
||||||
@ -175,15 +154,14 @@ class HeadwindDirectionDataType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val windDirection = streamData.bearing
|
val windDirection = streamData.bearing
|
||||||
val windSpeed = streamData.speed ?: 0.0
|
val windSpeed = streamData.speed
|
||||||
val windSpeedUserUnit = msInUserUnit(windSpeed, streamData.isImperial)
|
|
||||||
|
|
||||||
val result = glance.compose(context, DpSize.Unspecified) {
|
val result = glance.compose(context, DpSize.Unspecified) {
|
||||||
HeadwindDirection(
|
HeadwindDirection(
|
||||||
baseBitmap,
|
baseBitmap,
|
||||||
windDirection.roundToInt(),
|
windDirection.roundToInt(),
|
||||||
config.textSize,
|
config.textSize,
|
||||||
windSpeedUserUnit.roundToInt().toString(),
|
windSpeed?.toInt()?.toString() ?: "",
|
||||||
preview = config.preview,
|
preview = config.preview,
|
||||||
wideMode = false
|
wideMode = false
|
||||||
)
|
)
|
||||||
|
|||||||
@ -67,7 +67,7 @@ fun HeadwindDirection(
|
|||||||
val baseModifier = GlanceModifier.fillMaxSize().padding(5.dp).background(dayColor, nightColor).cornerRadius(10.dp)
|
val baseModifier = GlanceModifier.fillMaxSize().padding(5.dp).background(dayColor, nightColor).cornerRadius(10.dp)
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = baseModifier, // TODO if (!preview) baseModifier.clickable(actionStartActivity<MainActivity>()) else baseModifier,
|
modifier = if (!preview) baseModifier.clickable(actionStartActivity<MainActivity>()) else baseModifier,
|
||||||
contentAlignment = Alignment(
|
contentAlignment = Alignment(
|
||||||
vertical = Alignment.Vertical.CenterVertically,
|
vertical = Alignment.Vertical.CenterVertically,
|
||||||
horizontal = Alignment.Horizontal.CenterHorizontally,
|
horizontal = Alignment.Horizontal.CenterHorizontally,
|
||||||
|
|||||||
@ -7,16 +7,12 @@ import de.timklge.karooheadwind.weatherprovider.WeatherData
|
|||||||
import de.timklge.karooheadwind.getRelativeHeadingFlow
|
import de.timklge.karooheadwind.getRelativeHeadingFlow
|
||||||
import de.timklge.karooheadwind.streamCurrentWeatherData
|
import de.timklge.karooheadwind.streamCurrentWeatherData
|
||||||
import de.timklge.karooheadwind.streamSettings
|
import de.timklge.karooheadwind.streamSettings
|
||||||
import de.timklge.karooheadwind.throttle
|
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.extension.DataTypeImpl
|
import io.hammerhead.karooext.extension.DataTypeImpl
|
||||||
import io.hammerhead.karooext.internal.Emitter
|
import io.hammerhead.karooext.internal.Emitter
|
||||||
import io.hammerhead.karooext.internal.ViewEmitter
|
|
||||||
import io.hammerhead.karooext.models.DataPoint
|
import io.hammerhead.karooext.models.DataPoint
|
||||||
import io.hammerhead.karooext.models.DataType
|
import io.hammerhead.karooext.models.DataType
|
||||||
import io.hammerhead.karooext.models.StreamState
|
import io.hammerhead.karooext.models.StreamState
|
||||||
import io.hammerhead.karooext.models.UpdateGraphicConfig
|
|
||||||
import io.hammerhead.karooext.models.ViewConfig
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
@ -31,14 +27,11 @@ class HeadwindSpeedDataType(
|
|||||||
|
|
||||||
override fun startStream(emitter: Emitter<StreamState>) {
|
override fun startStream(emitter: Emitter<StreamState>) {
|
||||||
val job = CoroutineScope(Dispatchers.IO).launch {
|
val job = CoroutineScope(Dispatchers.IO).launch {
|
||||||
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
|
|
||||||
|
|
||||||
karooSystem.getRelativeHeadingFlow(context)
|
karooSystem.getRelativeHeadingFlow(context)
|
||||||
.combine(context.streamCurrentWeatherData(karooSystem)) { value, data -> value to data }
|
.combine(context.streamCurrentWeatherData(karooSystem)) { value, data -> value to data }
|
||||||
.combine(context.streamSettings(karooSystem)) { (value, data), settings ->
|
.combine(context.streamSettings(karooSystem)) { (value, data), settings ->
|
||||||
StreamData(value, data, settings)
|
StreamData(value, data, settings)
|
||||||
}
|
}
|
||||||
.throttle(refreshRate)
|
|
||||||
.collect { streamData ->
|
.collect { streamData ->
|
||||||
val windSpeed = streamData.weatherData?.windSpeed ?: 0.0
|
val windSpeed = streamData.weatherData?.windSpeed ?: 0.0
|
||||||
val windDirection = (streamData.headingResponse as? HeadingResponse.Value)?.diff ?: 0.0
|
val windDirection = (streamData.headingResponse as? HeadingResponse.Value)?.diff ?: 0.0
|
||||||
@ -52,9 +45,5 @@ class HeadwindSpeedDataType(
|
|||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startView(context: Context, config: ViewConfig, emitter: ViewEmitter) {
|
|
||||||
emitter.onNext(UpdateGraphicConfig(formatDataTypeId = DataType.Type.SPEED))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
package de.timklge.karooheadwind.datatypes
|
package de.timklge.karooheadwind.datatypes
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import de.timklge.karooheadwind.util.millimetersInUserUnit
|
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
|
||||||
|
|
||||||
class PrecipitationDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "precipitation"){
|
class PrecipitationDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "precipitation"){
|
||||||
override fun getValue(data: WeatherData, userProfile: UserProfile): Double {
|
override fun getValue(data: WeatherData): Double {
|
||||||
return millimetersInUserUnit(data.precipitation, userProfile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL)
|
return data.precipitation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25,6 +25,7 @@ import de.timklge.karooheadwind.weatherprovider.WeatherInterpretation
|
|||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PrecipitationForecast(
|
fun PrecipitationForecast(
|
||||||
@ -33,7 +34,7 @@ fun PrecipitationForecast(
|
|||||||
distance: Double? = null,
|
distance: Double? = null,
|
||||||
timeLabel: String? = null,
|
timeLabel: String? = null,
|
||||||
rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally,
|
rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally,
|
||||||
isImperial: Boolean?,
|
isImperial: Boolean?
|
||||||
) {
|
) {
|
||||||
Column(modifier = GlanceModifier.fillMaxHeight().padding(1.dp).width(86.dp), horizontalAlignment = rowAlignment) {
|
Column(modifier = GlanceModifier.fillMaxHeight().padding(1.dp).width(86.dp), horizontalAlignment = rowAlignment) {
|
||||||
Row(modifier = GlanceModifier.defaultWeight().fillMaxWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) {
|
Row(modifier = GlanceModifier.defaultWeight().fillMaxWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) {
|
||||||
@ -94,15 +95,14 @@ class PrecipitationForecastDataType(karooSystem: KarooSystemService) : ForecastD
|
|||||||
timeLabel: String,
|
timeLabel: String,
|
||||||
dateLabel: String?,
|
dateLabel: String?,
|
||||||
distance: Double?,
|
distance: Double?,
|
||||||
isImperial: Boolean,
|
isImperial: Boolean
|
||||||
isNight: Boolean,
|
|
||||||
) {
|
) {
|
||||||
PrecipitationForecast(
|
PrecipitationForecast(
|
||||||
precipitation = ceil(precipitation).toInt(),
|
precipitation = ceil(precipitation).toInt(),
|
||||||
precipitationProbability = precipitationProbability,
|
precipitationProbability = precipitationProbability,
|
||||||
distance = distance,
|
distance = distance,
|
||||||
timeLabel = timeLabel,
|
timeLabel = timeLabel,
|
||||||
isImperial = isImperial,
|
isImperial = isImperial
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10,7 +10,6 @@ import de.timklge.karooheadwind.streamCurrentWeatherData
|
|||||||
import de.timklge.karooheadwind.streamDataFlow
|
import de.timklge.karooheadwind.streamDataFlow
|
||||||
import de.timklge.karooheadwind.streamSettings
|
import de.timklge.karooheadwind.streamSettings
|
||||||
import de.timklge.karooheadwind.streamUserProfile
|
import de.timklge.karooheadwind.streamUserProfile
|
||||||
import de.timklge.karooheadwind.throttle
|
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.extension.DataTypeImpl
|
import io.hammerhead.karooext.extension.DataTypeImpl
|
||||||
import io.hammerhead.karooext.internal.Emitter
|
import io.hammerhead.karooext.internal.Emitter
|
||||||
@ -114,7 +113,7 @@ class RelativeGradeDataType(private val karooSystemService: KarooSystemService,
|
|||||||
return relativeGrade
|
return relativeGrade
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun streamRelativeGrade(karooSystemService: KarooSystemService, context: Context): Flow<RelativeGradeResponse> {
|
fun streamRelativeGrade(karooSystemService: KarooSystemService, context: Context): Flow<RelativeGradeResponse> {
|
||||||
val relativeWindDirectionFlow = karooSystemService.getRelativeHeadingFlow(context).filterIsInstance<HeadingResponse.Value>().map { it.diff + 180 }
|
val relativeWindDirectionFlow = karooSystemService.getRelativeHeadingFlow(context).filterIsInstance<HeadingResponse.Value>().map { it.diff + 180 }
|
||||||
val speedFlow = karooSystemService.streamDataFlow(DataType.Type.SPEED).filterIsInstance<StreamState.Streaming>().map { it.dataPoint.singleValue ?: 0.0 }
|
val speedFlow = karooSystemService.streamDataFlow(DataType.Type.SPEED).filterIsInstance<StreamState.Streaming>().map { it.dataPoint.singleValue ?: 0.0 }
|
||||||
val actualGradeFlow = karooSystemService.streamDataFlow(DataType.Type.ELEVATION_GRADE).filterIsInstance<StreamState.Streaming>().map { it.dataPoint.singleValue }.filterNotNull().map { it / 100.0 } // Convert to decimal grade
|
val actualGradeFlow = karooSystemService.streamDataFlow(DataType.Type.ELEVATION_GRADE).filterIsInstance<StreamState.Streaming>().map { it.dataPoint.singleValue }.filterNotNull().map { it / 100.0 } // Convert to decimal grade
|
||||||
@ -127,10 +126,29 @@ class RelativeGradeDataType(private val karooSystemService: KarooSystemService,
|
|||||||
} + DEFAULT_BIKE_WEIGHT
|
} + DEFAULT_BIKE_WEIGHT
|
||||||
}
|
}
|
||||||
|
|
||||||
val refreshRate = karooSystemService.getRefreshRateInMilliseconds(context)
|
val windSpeedFlow = combine(context.streamSettings(karooSystemService), karooSystemService.streamUserProfile(), context.streamCurrentWeatherData(karooSystemService).filterNotNull()) { settings, profile, weatherData ->
|
||||||
|
val isOpenMeteo = settings.weatherProvider == WeatherDataProvider.OPEN_METEO
|
||||||
|
val profileIsImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
||||||
|
|
||||||
val windSpeedFlow = context.streamCurrentWeatherData(karooSystemService).filterNotNull().map { weatherData ->
|
if (isOpenMeteo) {
|
||||||
weatherData.windSpeed
|
if (profileIsImperial) { // OpenMeteo returns wind speed in mph
|
||||||
|
val windSpeedInMilesPerHour = weatherData.windSpeed
|
||||||
|
|
||||||
|
windSpeedInMilesPerHour * 0.44704
|
||||||
|
} else { // Wind speed reported by openmeteo is in km/h
|
||||||
|
val windSpeedInKmh = weatherData.windSpeed
|
||||||
|
|
||||||
|
windSpeedInKmh * 0.277778
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (profileIsImperial) { // OpenWeatherMap returns wind speed in mph
|
||||||
|
val windSpeedInMilesPerHour = weatherData.windSpeed
|
||||||
|
|
||||||
|
windSpeedInMilesPerHour * 0.44704
|
||||||
|
} else { // Wind speed reported by openweathermap is in m/s
|
||||||
|
weatherData.windSpeed
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class StreamValues(
|
data class StreamValues(
|
||||||
@ -143,7 +161,7 @@ class RelativeGradeDataType(private val karooSystemService: KarooSystemService,
|
|||||||
|
|
||||||
return combine(relativeWindDirectionFlow, speedFlow, windSpeedFlow, actualGradeFlow, totalMassFlow) { windDirection, speed, windSpeed, actualGrade, totalMass ->
|
return combine(relativeWindDirectionFlow, speedFlow, windSpeedFlow, actualGradeFlow, totalMassFlow) { windDirection, speed, windSpeed, actualGrade, totalMass ->
|
||||||
StreamValues(windDirection, speed, windSpeed, actualGrade, totalMass)
|
StreamValues(windDirection, speed, windSpeed, actualGrade, totalMass)
|
||||||
}.distinctUntilChanged().throttle(refreshRate).map { (windDirection, speed, windSpeed, actualGrade, totalMass) ->
|
}.distinctUntilChanged().map { (windDirection, speed, windSpeed, actualGrade, totalMass) ->
|
||||||
val relativeGrade = estimateRelativeGrade(actualGrade, speed, windSpeed, windDirection, totalMass)
|
val relativeGrade = estimateRelativeGrade(actualGrade, speed, windSpeed, windDirection, totalMass)
|
||||||
|
|
||||||
Log.d(KarooHeadwindExtension.TAG, "Relative grade: $relativeGrade - Wind Direction: $windDirection - Speed: $speed - Wind Speed: $windSpeed - Actual Grade: $actualGrade - Total Mass: $totalMass")
|
Log.d(KarooHeadwindExtension.TAG, "Relative grade: $relativeGrade - Wind Direction: $windDirection - Speed: $speed - Wind Speed: $windSpeed - Actual Grade: $actualGrade - Total Mass: $totalMass")
|
||||||
|
|||||||
@ -3,10 +3,9 @@ package de.timklge.karooheadwind.datatypes
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
|
||||||
|
|
||||||
class RelativeHumidityDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "relativeHumidity"){
|
class RelativeHumidityDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "relativeHumidity"){
|
||||||
override fun getValue(data: WeatherData, userProfile: UserProfile): Double? {
|
override fun getValue(data: WeatherData): Double? {
|
||||||
return data.relativeHumidity.toDouble()
|
return data.relativeHumidity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,10 +3,9 @@ package de.timklge.karooheadwind.datatypes
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
|
||||||
|
|
||||||
class SealevelPressureDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "sealevelPressure"){
|
class SealevelPressureDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "sealevelPressure"){
|
||||||
override fun getValue(data: WeatherData, userProfile: UserProfile): Double? {
|
override fun getValue(data: WeatherData): Double? {
|
||||||
return data.sealevelPressure
|
return data.sealevelPressure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,10 +3,9 @@ package de.timklge.karooheadwind.datatypes
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
|
||||||
|
|
||||||
class SurfacePressureDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "surfacePressure"){
|
class SurfacePressureDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "surfacePressure"){
|
||||||
override fun getValue(data: WeatherData, userProfile: UserProfile): Double? {
|
override fun getValue(data: WeatherData): Double? {
|
||||||
return data.surfacePressure
|
return data.surfacePressure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -21,12 +21,9 @@ import de.timklge.karooheadwind.datatypes.TailwindDataType.StreamData
|
|||||||
import de.timklge.karooheadwind.getRelativeHeadingFlow
|
import de.timklge.karooheadwind.getRelativeHeadingFlow
|
||||||
import de.timklge.karooheadwind.streamCurrentWeatherData
|
import de.timklge.karooheadwind.streamCurrentWeatherData
|
||||||
import de.timklge.karooheadwind.streamDataFlow
|
import de.timklge.karooheadwind.streamDataFlow
|
||||||
import de.timklge.karooheadwind.streamDatatypeIsVisible
|
|
||||||
import de.timklge.karooheadwind.streamSettings
|
import de.timklge.karooheadwind.streamSettings
|
||||||
import de.timklge.karooheadwind.streamUserProfile
|
import de.timklge.karooheadwind.streamUserProfile
|
||||||
import de.timklge.karooheadwind.throttle
|
import de.timklge.karooheadwind.throttle
|
||||||
import de.timklge.karooheadwind.util.msInUserUnit
|
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.extension.DataTypeImpl
|
import io.hammerhead.karooext.extension.DataTypeImpl
|
||||||
import io.hammerhead.karooext.internal.ViewEmitter
|
import io.hammerhead.karooext.internal.ViewEmitter
|
||||||
@ -88,7 +85,7 @@ class TailwindAndRideSpeedDataType(
|
|||||||
val gustSpeed = windSpeed * ((10..40).random().toDouble() / 10)
|
val gustSpeed = windSpeed * ((10..40).random().toDouble() / 10)
|
||||||
val isImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
val isImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
||||||
|
|
||||||
emit(StreamData(HeadingResponse.Value(bearing), bearing, windSpeed.toDouble(), HeadwindSettings(), rideSpeed, gustSpeed = gustSpeed, isImperial = isImperial, isVisible = true))
|
emit(StreamData(HeadingResponse.Value(bearing), bearing, windSpeed.toDouble(), HeadwindSettings(), rideSpeed, gustSpeed = gustSpeed, isImperial = isImperial))
|
||||||
|
|
||||||
delay(2_000)
|
delay(2_000)
|
||||||
}
|
}
|
||||||
@ -116,27 +113,18 @@ class TailwindAndRideSpeedDataType(
|
|||||||
val flow = if (config.preview) {
|
val flow = if (config.preview) {
|
||||||
previewFlow(karooSystem.streamUserProfile())
|
previewFlow(karooSystem.streamUserProfile())
|
||||||
} else {
|
} else {
|
||||||
combine(karooSystem.getRelativeHeadingFlow(context),
|
combine(karooSystem.getRelativeHeadingFlow(context), context.streamCurrentWeatherData(karooSystem), context.streamSettings(karooSystem), karooSystem.streamUserProfile(), streamSpeedInMs()) { headingResponse, weatherData, settings, userProfile, rideSpeedInMs ->
|
||||||
context.streamCurrentWeatherData(karooSystem),
|
|
||||||
context.streamSettings(karooSystem),
|
|
||||||
karooSystem.streamUserProfile(),
|
|
||||||
streamSpeedInMs(),
|
|
||||||
karooSystem.streamDatatypeIsVisible(dataTypeId)
|
|
||||||
) { data ->
|
|
||||||
val headingResponse = data[0] as HeadingResponse
|
|
||||||
val weatherData = data[1] as? WeatherData
|
|
||||||
val settings = data[2] as HeadwindSettings
|
|
||||||
val userProfile = data[3] as UserProfile
|
|
||||||
val rideSpeedInMs = data[4] as Double
|
|
||||||
val isVisible = data[5] as Boolean
|
|
||||||
|
|
||||||
val isImperial = userProfile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
val isImperial = userProfile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
||||||
val absoluteWindDirection = weatherData?.windDirection
|
val absoluteWindDirection = weatherData?.windDirection
|
||||||
val windSpeed = weatherData?.windSpeed
|
val windSpeed = weatherData?.windSpeed
|
||||||
val gustSpeed = weatherData?.windGusts
|
val gustSpeed = weatherData?.windGusts
|
||||||
val rideSpeed = rideSpeedInMs
|
val rideSpeed = if (isImperial){
|
||||||
|
rideSpeedInMs * 2.23694
|
||||||
|
} else {
|
||||||
|
rideSpeedInMs * 3.6
|
||||||
|
}
|
||||||
|
|
||||||
StreamData(headingResponse, absoluteWindDirection, windSpeed, settings, rideSpeed = rideSpeed, isImperial = isImperial, gustSpeed = gustSpeed, isVisible = isVisible)
|
StreamData(headingResponse, absoluteWindDirection, windSpeed, settings, rideSpeed = rideSpeed, isImperial = isImperial, gustSpeed = gustSpeed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,21 +154,15 @@ class TailwindAndRideSpeedDataType(
|
|||||||
WindDirectionIndicatorSetting.WIND_DIRECTION -> streamData.absoluteWindDirection + 180
|
WindDirectionIndicatorSetting.WIND_DIRECTION -> streamData.absoluteWindDirection + 180
|
||||||
}
|
}
|
||||||
|
|
||||||
val rideSpeedInUserUnit = msInUserUnit(streamData.rideSpeed ?: 0.0, streamData.isImperial)
|
val text = streamData.rideSpeed?.let { String.format(Locale.current.platformLocale, "%.1f", it) } ?: ""
|
||||||
val text = String.format(Locale.current.platformLocale, "%.1f", rideSpeedInUserUnit)
|
|
||||||
|
|
||||||
val wideMode = config.gridSize.first == 60
|
val wideMode = config.gridSize.first == 60
|
||||||
|
|
||||||
val gustSpeedInUserUnit = msInUserUnit(streamData.gustSpeed ?: 0.0, streamData.isImperial)
|
|
||||||
|
|
||||||
val gustSpeedAddon = if (wideMode) {
|
val gustSpeedAddon = if (wideMode) {
|
||||||
"-${gustSpeedInUserUnit.roundToInt()}"
|
"-${streamData.gustSpeed?.roundToInt() ?: 0}"
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
|
|
||||||
val windSpeedUserUnit = msInUserUnit(windSpeed, streamData.isImperial)
|
|
||||||
|
|
||||||
val subtextWithSign = when (streamData.settings.windDirectionIndicatorTextSetting) {
|
val subtextWithSign = when (streamData.settings.windDirectionIndicatorTextSetting) {
|
||||||
WindDirectionIndicatorTextSetting.HEADWIND_SPEED -> {
|
WindDirectionIndicatorTextSetting.HEADWIND_SPEED -> {
|
||||||
val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed
|
val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed
|
||||||
@ -189,12 +171,9 @@ class TailwindAndRideSpeedDataType(
|
|||||||
val sign = if (headwindSpeed < 0) "+" else {
|
val sign = if (headwindSpeed < 0) "+" else {
|
||||||
if (headwindSpeed > 0) "-" else ""
|
if (headwindSpeed > 0) "-" else ""
|
||||||
}
|
}
|
||||||
|
"$sign${headwindSpeed.roundToInt().absoluteValue} ${windSpeed.roundToInt()}${gustSpeedAddon}"
|
||||||
val headwindSpeedUserUnit = msInUserUnit(headwindSpeed, streamData.isImperial)
|
|
||||||
|
|
||||||
"$sign${headwindSpeedUserUnit.roundToInt().absoluteValue} ${windSpeedUserUnit.roundToInt()}${gustSpeedAddon}"
|
|
||||||
}
|
}
|
||||||
WindDirectionIndicatorTextSetting.WIND_SPEED -> "${windSpeedUserUnit.roundToInt()}${gustSpeedAddon}"
|
WindDirectionIndicatorTextSetting.WIND_SPEED -> "${windSpeed.roundToInt()}${gustSpeedAddon}"
|
||||||
WindDirectionIndicatorTextSetting.NONE -> ""
|
WindDirectionIndicatorTextSetting.NONE -> ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +182,11 @@ class TailwindAndRideSpeedDataType(
|
|||||||
|
|
||||||
if (streamData.settings.windDirectionIndicatorSetting == WindDirectionIndicatorSetting.HEADWIND_DIRECTION) {
|
if (streamData.settings.windDirectionIndicatorSetting == WindDirectionIndicatorSetting.HEADWIND_DIRECTION) {
|
||||||
val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed
|
val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed
|
||||||
val windSpeedInKmh = headwindSpeed * 3.6
|
val windSpeedInKmh = if (streamData.isImperial == true){
|
||||||
|
headwindSpeed / 2.23694 * 3.6
|
||||||
|
} else {
|
||||||
|
headwindSpeed
|
||||||
|
}
|
||||||
dayColor = interpolateWindColor(windSpeedInKmh, false, context)
|
dayColor = interpolateWindColor(windSpeedInKmh, false, context)
|
||||||
nightColor = interpolateWindColor(windSpeedInKmh, true, context)
|
nightColor = interpolateWindColor(windSpeedInKmh, true, context)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,12 +17,9 @@ import de.timklge.karooheadwind.WindDirectionIndicatorTextSetting
|
|||||||
import de.timklge.karooheadwind.getRelativeHeadingFlow
|
import de.timklge.karooheadwind.getRelativeHeadingFlow
|
||||||
import de.timklge.karooheadwind.streamCurrentWeatherData
|
import de.timklge.karooheadwind.streamCurrentWeatherData
|
||||||
import de.timklge.karooheadwind.streamDataFlow
|
import de.timklge.karooheadwind.streamDataFlow
|
||||||
import de.timklge.karooheadwind.streamDatatypeIsVisible
|
|
||||||
import de.timklge.karooheadwind.streamSettings
|
import de.timklge.karooheadwind.streamSettings
|
||||||
import de.timklge.karooheadwind.streamUserProfile
|
import de.timklge.karooheadwind.streamUserProfile
|
||||||
import de.timklge.karooheadwind.throttle
|
import de.timklge.karooheadwind.throttle
|
||||||
import de.timklge.karooheadwind.util.msInUserUnit
|
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.extension.DataTypeImpl
|
import io.hammerhead.karooext.extension.DataTypeImpl
|
||||||
import io.hammerhead.karooext.internal.ViewEmitter
|
import io.hammerhead.karooext.internal.ViewEmitter
|
||||||
@ -38,7 +35,6 @@ import kotlinx.coroutines.awaitCancellation
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.filter
|
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
@ -60,8 +56,7 @@ class TailwindDataType(
|
|||||||
val settings: HeadwindSettings,
|
val settings: HeadwindSettings,
|
||||||
val rideSpeed: Double?,
|
val rideSpeed: Double?,
|
||||||
val gustSpeed: Double?,
|
val gustSpeed: Double?,
|
||||||
val isImperial: Boolean,
|
val isImperial: Boolean)
|
||||||
val isVisible: Boolean)
|
|
||||||
|
|
||||||
private fun previewFlow(profileFlow: Flow<UserProfile>): Flow<StreamData> {
|
private fun previewFlow(profileFlow: Flow<UserProfile>): Flow<StreamData> {
|
||||||
return flow {
|
return flow {
|
||||||
@ -74,7 +69,7 @@ class TailwindDataType(
|
|||||||
val gustSpeed = windSpeed * ((10..40).random().toDouble() / 10)
|
val gustSpeed = windSpeed * ((10..40).random().toDouble() / 10)
|
||||||
val isImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
val isImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
||||||
|
|
||||||
emit(StreamData(HeadingResponse.Value(bearing), bearing, windSpeed.toDouble(), HeadwindSettings(), rideSpeed, gustSpeed = gustSpeed, isImperial = isImperial, isVisible = true))
|
emit(StreamData(HeadingResponse.Value(bearing), bearing, windSpeed.toDouble(), HeadwindSettings(), rideSpeed, gustSpeed = gustSpeed, isImperial = isImperial))
|
||||||
|
|
||||||
delay(2_000)
|
delay(2_000)
|
||||||
}
|
}
|
||||||
@ -103,26 +98,18 @@ class TailwindDataType(
|
|||||||
val flow = if (config.preview) {
|
val flow = if (config.preview) {
|
||||||
previewFlow(karooSystem.streamUserProfile())
|
previewFlow(karooSystem.streamUserProfile())
|
||||||
} else {
|
} else {
|
||||||
combine(karooSystem.getRelativeHeadingFlow(context),
|
combine(karooSystem.getRelativeHeadingFlow(context), context.streamCurrentWeatherData(karooSystem), context.streamSettings(karooSystem), karooSystem.streamUserProfile(), streamSpeedInMs()) { headingResponse, weatherData, settings, userProfile, rideSpeedInMs ->
|
||||||
context.streamCurrentWeatherData(karooSystem),
|
|
||||||
context.streamSettings(karooSystem),
|
|
||||||
karooSystem.streamUserProfile(),
|
|
||||||
streamSpeedInMs(),
|
|
||||||
karooSystem.streamDatatypeIsVisible(dataTypeId)
|
|
||||||
) { data ->
|
|
||||||
val headingResponse = data[0] as HeadingResponse
|
|
||||||
val weatherData = data[1] as? WeatherData
|
|
||||||
val settings = data[2] as HeadwindSettings
|
|
||||||
val userProfile = data[3] as UserProfile
|
|
||||||
val rideSpeedInMs = data[4] as Double
|
|
||||||
val isVisible = data[5] as Boolean
|
|
||||||
|
|
||||||
val isImperial = userProfile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
val isImperial = userProfile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
||||||
val absoluteWindDirection = weatherData?.windDirection
|
val absoluteWindDirection = weatherData?.windDirection
|
||||||
val windSpeed = weatherData?.windSpeed
|
val windSpeed = weatherData?.windSpeed
|
||||||
val gustSpeed = weatherData?.windGusts
|
val gustSpeed = weatherData?.windGusts
|
||||||
|
val rideSpeed = if (isImperial){
|
||||||
|
rideSpeedInMs * 2.23694
|
||||||
|
} else {
|
||||||
|
rideSpeedInMs * 3.6
|
||||||
|
}
|
||||||
|
|
||||||
StreamData(headingResponse, absoluteWindDirection, windSpeed, settings, rideSpeed = rideSpeedInMs, isImperial = isImperial, gustSpeed = gustSpeed, isVisible = isVisible)
|
StreamData(headingResponse, absoluteWindDirection, windSpeed, settings, rideSpeed = rideSpeed, isImperial = isImperial, gustSpeed = gustSpeed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +117,7 @@ class TailwindDataType(
|
|||||||
emitter.onNext(ShowCustomStreamState("", null))
|
emitter.onNext(ShowCustomStreamState("", null))
|
||||||
|
|
||||||
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
|
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
|
||||||
flow.filter { it.isVisible }.throttle(refreshRate).collect { streamData ->
|
flow.throttle(refreshRate).collect { streamData ->
|
||||||
Log.d(KarooHeadwindExtension.TAG, "Updating tailwind direction view")
|
Log.d(KarooHeadwindExtension.TAG, "Updating tailwind direction view")
|
||||||
|
|
||||||
val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff
|
val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff
|
||||||
@ -160,26 +147,24 @@ class TailwindDataType(
|
|||||||
val sign = if (headwindSpeed < 0) "+" else {
|
val sign = if (headwindSpeed < 0) "+" else {
|
||||||
if (headwindSpeed > 0) "-" else ""
|
if (headwindSpeed > 0) "-" else ""
|
||||||
}
|
}
|
||||||
|
"$sign${headwindSpeed.roundToInt().absoluteValue}"
|
||||||
val headwindSpeedUserUnit = msInUserUnit(headwindSpeed, streamData.isImperial)
|
|
||||||
|
|
||||||
"$sign${headwindSpeedUserUnit.roundToInt().absoluteValue}"
|
|
||||||
}
|
}
|
||||||
WindDirectionIndicatorTextSetting.WIND_SPEED -> msInUserUnit(windSpeed, streamData.isImperial).roundToInt().toString()
|
WindDirectionIndicatorTextSetting.WIND_SPEED -> windSpeed.roundToInt().toString()
|
||||||
WindDirectionIndicatorTextSetting.NONE -> ""
|
WindDirectionIndicatorTextSetting.NONE -> ""
|
||||||
}
|
}
|
||||||
|
|
||||||
val windSpeedUserUnit = msInUserUnit(windSpeed, streamData.isImperial)
|
val subtext = "${windSpeed.roundToInt()}-${streamData.gustSpeed?.roundToInt()}"
|
||||||
val gustSpeedUserUnit = msInUserUnit(streamData.gustSpeed ?: 0.0, streamData.isImperial)
|
|
||||||
|
|
||||||
val subtext = "${windSpeedUserUnit.roundToInt()}-${gustSpeedUserUnit.roundToInt()}"
|
|
||||||
|
|
||||||
var dayColor = Color(ContextCompat.getColor(context, R.color.black))
|
var dayColor = Color(ContextCompat.getColor(context, R.color.black))
|
||||||
var nightColor = Color(ContextCompat.getColor(context, R.color.white))
|
var nightColor = Color(ContextCompat.getColor(context, R.color.white))
|
||||||
|
|
||||||
if (streamData.settings.windDirectionIndicatorSetting == WindDirectionIndicatorSetting.HEADWIND_DIRECTION) {
|
if (streamData.settings.windDirectionIndicatorSetting == WindDirectionIndicatorSetting.HEADWIND_DIRECTION) {
|
||||||
val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed
|
val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed
|
||||||
val windSpeedInKmh = headwindSpeed * 3.6
|
val windSpeedInKmh = if (streamData.isImperial){
|
||||||
|
headwindSpeed / 2.23694 * 3.6
|
||||||
|
} else {
|
||||||
|
headwindSpeed
|
||||||
|
}
|
||||||
dayColor = interpolateWindColor(windSpeedInKmh, false, context)
|
dayColor = interpolateWindColor(windSpeedInKmh, false, context)
|
||||||
nightColor = interpolateWindColor(windSpeedInKmh, true, context)
|
nightColor = interpolateWindColor(windSpeedInKmh, true, context)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,15 +3,9 @@ package de.timklge.karooheadwind.datatypes
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.models.DataType
|
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
|
||||||
|
|
||||||
class TemperatureDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "temperature"){
|
class TemperatureDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "temperature"){
|
||||||
override fun getValue(data: WeatherData, userProfile: UserProfile): Double {
|
override fun getValue(data: WeatherData): Double {
|
||||||
return data.temperature
|
return data.temperature
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFormatDataType(): String? {
|
|
||||||
return DataType.Type.TEMPERATURE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -91,15 +91,14 @@ class TemperatureForecastDataType(karooSystem: KarooSystemService) : ForecastDat
|
|||||||
timeLabel: String,
|
timeLabel: String,
|
||||||
dateLabel: String?,
|
dateLabel: String?,
|
||||||
distance: Double?,
|
distance: Double?,
|
||||||
isImperial: Boolean,
|
isImperial: Boolean
|
||||||
isNight: Boolean
|
|
||||||
) {
|
) {
|
||||||
TemperatureForecast(
|
TemperatureForecast(
|
||||||
temperature = temperature,
|
temperature = temperature,
|
||||||
temperatureUnit = temperatureUnit,
|
temperatureUnit = temperatureUnit,
|
||||||
distance = distance,
|
distance = distance,
|
||||||
timeLabel = timeLabel,
|
timeLabel = timeLabel,
|
||||||
isImperial = isImperial,
|
isImperial = isImperial
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,19 +16,13 @@ import de.timklge.karooheadwind.HeadingResponse
|
|||||||
import de.timklge.karooheadwind.HeadwindSettings
|
import de.timklge.karooheadwind.HeadwindSettings
|
||||||
import de.timklge.karooheadwind.KarooHeadwindExtension
|
import de.timklge.karooheadwind.KarooHeadwindExtension
|
||||||
import de.timklge.karooheadwind.MainActivity
|
import de.timklge.karooheadwind.MainActivity
|
||||||
import de.timklge.karooheadwind.R
|
|
||||||
import de.timklge.karooheadwind.TemperatureUnit
|
import de.timklge.karooheadwind.TemperatureUnit
|
||||||
import de.timklge.karooheadwind.getHeadingFlow
|
|
||||||
import de.timklge.karooheadwind.streamCurrentWeatherData
|
|
||||||
import de.timklge.karooheadwind.streamDatatypeIsVisible
|
|
||||||
import de.timklge.karooheadwind.streamSettings
|
|
||||||
import de.timklge.karooheadwind.streamUserProfile
|
|
||||||
import de.timklge.karooheadwind.throttle
|
|
||||||
import de.timklge.karooheadwind.util.celciusInUserUnit
|
|
||||||
import de.timklge.karooheadwind.util.millimetersInUserUnit
|
|
||||||
import de.timklge.karooheadwind.util.msInUserUnit
|
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherInterpretation
|
import de.timklge.karooheadwind.weatherprovider.WeatherInterpretation
|
||||||
|
import de.timklge.karooheadwind.getHeadingFlow
|
||||||
|
import de.timklge.karooheadwind.streamCurrentWeatherData
|
||||||
|
import de.timklge.karooheadwind.streamSettings
|
||||||
|
import de.timklge.karooheadwind.streamUserProfile
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.extension.DataTypeImpl
|
import io.hammerhead.karooext.extension.DataTypeImpl
|
||||||
import io.hammerhead.karooext.internal.Emitter
|
import io.hammerhead.karooext.internal.Emitter
|
||||||
@ -46,7 +40,6 @@ import kotlinx.coroutines.awaitCancellation
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.filter
|
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@ -69,10 +62,11 @@ class WeatherDataType(
|
|||||||
val job = CoroutineScope(Dispatchers.IO).launch {
|
val job = CoroutineScope(Dispatchers.IO).launch {
|
||||||
val currentWeatherData = applicationContext.streamCurrentWeatherData(karooSystem)
|
val currentWeatherData = applicationContext.streamCurrentWeatherData(karooSystem)
|
||||||
|
|
||||||
currentWeatherData.collect { data ->
|
currentWeatherData
|
||||||
Log.d(KarooHeadwindExtension.TAG, "Wind code: ${data?.weatherCode}")
|
.collect { data ->
|
||||||
emitter.onNext(StreamState.Streaming(DataPoint(dataTypeId, mapOf(DataType.Field.SINGLE to (data?.weatherCode?.toDouble() ?: 0.0)))))
|
Log.d(KarooHeadwindExtension.TAG, "Wind code: ${data?.weatherCode}")
|
||||||
}
|
emitter.onNext(StreamState.Streaming(DataPoint(dataTypeId, mapOf(DataType.Field.SINGLE to (data?.weatherCode?.toDouble() ?: 0.0)))))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
emitter.setCancellable {
|
emitter.setCancellable {
|
||||||
job.cancel()
|
job.cancel()
|
||||||
@ -80,18 +74,14 @@ class WeatherDataType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class StreamData(val data: WeatherData?, val settings: HeadwindSettings,
|
data class StreamData(val data: WeatherData?, val settings: HeadwindSettings,
|
||||||
val profile: UserProfile? = null, val headingResponse: HeadingResponse? = null,
|
val profile: UserProfile? = null, val headingResponse: HeadingResponse? = null)
|
||||||
val isVisible: Boolean)
|
|
||||||
|
|
||||||
private fun previewFlow(): Flow<StreamData> = flow {
|
private fun previewFlow(): Flow<StreamData> = flow {
|
||||||
while (true){
|
while (true){
|
||||||
emit(StreamData(
|
emit(StreamData(
|
||||||
WeatherData(
|
WeatherData(Instant.now().epochSecond, 0.0,
|
||||||
Instant.now().epochSecond, 0.0,
|
20.0, 50.0, 3.0, 0.0, 1013.25, 980.0, 15.0, 30.0, 30.0,
|
||||||
20, 50.0, 3.0, 0.0, 1013.25, 980.0, 15.0, 30.0, 30.0,
|
WeatherInterpretation.getKnownWeatherCodes().random(), isForecast = false), HeadwindSettings()))
|
||||||
WeatherInterpretation.getKnownWeatherCodes().random(), isForecast = false,
|
|
||||||
isNight = listOf(true, false).random()
|
|
||||||
), HeadwindSettings(), isVisible = true))
|
|
||||||
|
|
||||||
delay(5_000)
|
delay(5_000)
|
||||||
}
|
}
|
||||||
@ -106,29 +96,21 @@ class WeatherDataType(
|
|||||||
|
|
||||||
val baseBitmap = BitmapFactory.decodeResource(
|
val baseBitmap = BitmapFactory.decodeResource(
|
||||||
context.resources,
|
context.resources,
|
||||||
R.drawable.arrow_0
|
de.timklge.karooheadwind.R.drawable.arrow_0
|
||||||
)
|
)
|
||||||
|
|
||||||
val dataFlow = if (config.preview){
|
val dataFlow = if (config.preview){
|
||||||
previewFlow()
|
previewFlow()
|
||||||
} else {
|
} else {
|
||||||
combine(
|
combine(context.streamCurrentWeatherData(karooSystem), context.streamSettings(karooSystem), karooSystem.streamUserProfile(), karooSystem.getHeadingFlow(context)) { data, settings, profile, heading ->
|
||||||
context.streamCurrentWeatherData(karooSystem),
|
StreamData(data, settings, profile, heading)
|
||||||
context.streamSettings(karooSystem),
|
|
||||||
karooSystem.streamUserProfile(),
|
|
||||||
karooSystem.getHeadingFlow(context),
|
|
||||||
karooSystem.streamDatatypeIsVisible(dataTypeId)
|
|
||||||
) { data, settings, profile, heading, isVisible ->
|
|
||||||
StreamData(data, settings, profile, heading, isVisible)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val viewJob = CoroutineScope(Dispatchers.IO).launch {
|
val viewJob = CoroutineScope(Dispatchers.IO).launch {
|
||||||
emitter.onNext(ShowCustomStreamState("", null))
|
emitter.onNext(ShowCustomStreamState("", null))
|
||||||
|
|
||||||
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
|
dataFlow.collect { (data, settings, userProfile, headingResponse) ->
|
||||||
|
|
||||||
dataFlow.filter { it.isVisible }.throttle(refreshRate).collect { (data, settings, userProfile, headingResponse) ->
|
|
||||||
Log.d(KarooHeadwindExtension.TAG, "Updating weather view")
|
Log.d(KarooHeadwindExtension.TAG, "Updating weather view")
|
||||||
|
|
||||||
if (data == null){
|
if (data == null){
|
||||||
@ -143,18 +125,18 @@ class WeatherDataType(
|
|||||||
|
|
||||||
val result = glance.compose(context, DpSize.Unspecified) {
|
val result = glance.compose(context, DpSize.Unspecified) {
|
||||||
var modifier = GlanceModifier.fillMaxSize()
|
var modifier = GlanceModifier.fillMaxSize()
|
||||||
// TODO reenable once swipes are no longer interpreted as clicks if (!config.preview) modifier = modifier.clickable(onClick = actionStartActivity<MainActivity>())
|
if (!config.preview) modifier = modifier.clickable(onClick = actionStartActivity<MainActivity>())
|
||||||
|
|
||||||
Box(modifier = modifier, contentAlignment = Alignment.CenterEnd) {
|
Box(modifier = modifier, contentAlignment = Alignment.CenterEnd) {
|
||||||
Weather(
|
Weather(
|
||||||
baseBitmap,
|
baseBitmap,
|
||||||
current = interpretation,
|
current = interpretation,
|
||||||
windBearing = data.windDirection.roundToInt(),
|
windBearing = data.windDirection.roundToInt(),
|
||||||
windSpeed = msInUserUnit(data.windSpeed, userProfile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
|
windSpeed = data.windSpeed.roundToInt(),
|
||||||
windGusts = msInUserUnit(data.windGusts, userProfile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
|
windGusts = data.windGusts.roundToInt(),
|
||||||
precipitation = millimetersInUserUnit(data.precipitation, userProfile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL),
|
precipitation = data.precipitation,
|
||||||
precipitationProbability = null,
|
precipitationProbability = null,
|
||||||
temperature = celciusInUserUnit(data.temperature, userProfile?.preferredUnit?.temperature == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
|
temperature = data.temperature.roundToInt(),
|
||||||
temperatureUnit = if (userProfile?.preferredUnit?.temperature != UserProfile.PreferredUnit.UnitType.IMPERIAL) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
|
temperatureUnit = if (userProfile?.preferredUnit?.temperature != UserProfile.PreferredUnit.UnitType.IMPERIAL) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
|
||||||
timeLabel = formattedTime,
|
timeLabel = formattedTime,
|
||||||
rowAlignment = when (config.alignment){
|
rowAlignment = when (config.alignment){
|
||||||
@ -164,8 +146,7 @@ class WeatherDataType(
|
|||||||
},
|
},
|
||||||
dateLabel = formattedDate,
|
dateLabel = formattedDate,
|
||||||
singleDisplay = true,
|
singleDisplay = true,
|
||||||
isImperial = userProfile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL,
|
isImperial = userProfile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
||||||
isNight = data.isNight,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,8 +21,7 @@ class WeatherForecastDataType(karooSystem: KarooSystemService) : ForecastDataTyp
|
|||||||
timeLabel: String,
|
timeLabel: String,
|
||||||
dateLabel: String?,
|
dateLabel: String?,
|
||||||
distance: Double?,
|
distance: Double?,
|
||||||
isImperial: Boolean,
|
isImperial: Boolean
|
||||||
isNight: Boolean,
|
|
||||||
) {
|
) {
|
||||||
Weather(
|
Weather(
|
||||||
arrowBitmap = arrowBitmap,
|
arrowBitmap = arrowBitmap,
|
||||||
@ -37,8 +36,7 @@ class WeatherForecastDataType(karooSystem: KarooSystemService) : ForecastDataTyp
|
|||||||
timeLabel = timeLabel,
|
timeLabel = timeLabel,
|
||||||
dateLabel = dateLabel,
|
dateLabel = dateLabel,
|
||||||
distance = distance,
|
distance = distance,
|
||||||
isImperial = isImperial,
|
isImperial = isImperial
|
||||||
isNight = isNight,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,14 +45,14 @@ fun getShortDateFormatter(): DateTimeFormatter = DateTimeFormatter.ofPattern(
|
|||||||
}
|
}
|
||||||
).withZone(ZoneId.systemDefault())
|
).withZone(ZoneId.systemDefault())
|
||||||
|
|
||||||
fun getWeatherIcon(interpretation: WeatherInterpretation, isNight: Boolean): Int {
|
fun getWeatherIcon(interpretation: WeatherInterpretation): Int {
|
||||||
return when (interpretation){
|
return when (interpretation){
|
||||||
WeatherInterpretation.CLEAR -> if (isNight) R.drawable.crescent_moon else R.drawable.sun
|
WeatherInterpretation.CLEAR -> R.drawable.bx_clear
|
||||||
WeatherInterpretation.CLOUDY -> R.drawable.cloud
|
WeatherInterpretation.CLOUDY -> R.drawable.bx_cloud
|
||||||
WeatherInterpretation.RAINY -> R.drawable.cloud_with_rain
|
WeatherInterpretation.RAINY -> R.drawable.bx_cloud_rain
|
||||||
WeatherInterpretation.SNOWY -> R.drawable.cloud_with_snow
|
WeatherInterpretation.SNOWY -> R.drawable.bx_cloud_snow
|
||||||
WeatherInterpretation.DRIZZLE -> R.drawable.cloud_with_light_rain
|
WeatherInterpretation.DRIZZLE -> R.drawable.bx_cloud_drizzle
|
||||||
WeatherInterpretation.THUNDERSTORM -> R.drawable.cloud_with_lightning_and_rain
|
WeatherInterpretation.THUNDERSTORM -> R.drawable.bx_cloud_lightning
|
||||||
WeatherInterpretation.UNKNOWN -> R.drawable.question_mark_regular_240
|
WeatherInterpretation.UNKNOWN -> R.drawable.question_mark_regular_240
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,8 +74,7 @@ fun Weather(
|
|||||||
rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally,
|
rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally,
|
||||||
dateLabel: String? = null,
|
dateLabel: String? = null,
|
||||||
singleDisplay: Boolean = false,
|
singleDisplay: Boolean = false,
|
||||||
isImperial: Boolean?,
|
isImperial: Boolean?
|
||||||
isNight: Boolean
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val fontSize = if (singleDisplay) 19f else 14f
|
val fontSize = if (singleDisplay) 19f else 14f
|
||||||
@ -84,9 +83,10 @@ fun Weather(
|
|||||||
Row(modifier = GlanceModifier.defaultWeight().wrapContentWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) {
|
Row(modifier = GlanceModifier.defaultWeight().wrapContentWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) {
|
||||||
Image(
|
Image(
|
||||||
modifier = GlanceModifier.defaultWeight().wrapContentWidth().padding(1.dp),
|
modifier = GlanceModifier.defaultWeight().wrapContentWidth().padding(1.dp),
|
||||||
provider = ImageProvider(getWeatherIcon(current, isNight)),
|
provider = ImageProvider(getWeatherIcon(current)),
|
||||||
contentDescription = "Current weather information",
|
contentDescription = "Current weather information",
|
||||||
contentScale = ContentScale.Fit,
|
contentScale = ContentScale.Fit,
|
||||||
|
colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +142,7 @@ fun Weather(
|
|||||||
provider = ImageProvider(R.drawable.thermometer),
|
provider = ImageProvider(R.drawable.thermometer),
|
||||||
contentDescription = "Temperature",
|
contentDescription = "Temperature",
|
||||||
contentScale = ContentScale.Fit,
|
contentScale = ContentScale.Fit,
|
||||||
|
colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White))
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@ -17,25 +17,21 @@ import androidx.glance.text.FontFamily
|
|||||||
import androidx.glance.text.Text
|
import androidx.glance.text.Text
|
||||||
import androidx.glance.text.TextStyle
|
import androidx.glance.text.TextStyle
|
||||||
import de.timklge.karooheadwind.KarooHeadwindExtension
|
import de.timklge.karooheadwind.KarooHeadwindExtension
|
||||||
import de.timklge.karooheadwind.streamDataFlow
|
|
||||||
import de.timklge.karooheadwind.streamDatatypeIsVisible
|
|
||||||
import de.timklge.karooheadwind.throttle
|
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
|
import de.timklge.karooheadwind.streamDataFlow
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.internal.ViewEmitter
|
import io.hammerhead.karooext.internal.ViewEmitter
|
||||||
import io.hammerhead.karooext.models.ShowCustomStreamState
|
import io.hammerhead.karooext.models.ShowCustomStreamState
|
||||||
import io.hammerhead.karooext.models.StreamState
|
import io.hammerhead.karooext.models.StreamState
|
||||||
import io.hammerhead.karooext.models.UpdateGraphicConfig
|
import io.hammerhead.karooext.models.UpdateGraphicConfig
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
|
||||||
import io.hammerhead.karooext.models.ViewConfig
|
import io.hammerhead.karooext.models.ViewConfig
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.awaitCancellation
|
import kotlinx.coroutines.awaitCancellation
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.filter
|
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@ -52,22 +48,14 @@ class WindDirectionDataType(val karooSystem: KarooSystemService, context: Contex
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getValue(data: WeatherData, userProfile: UserProfile): Double {
|
override fun getValue(data: WeatherData): Double {
|
||||||
return data.windDirection
|
return data.windDirection
|
||||||
}
|
}
|
||||||
|
|
||||||
data class StreamData(
|
private fun previewFlow(): Flow<Double> {
|
||||||
val windBearing: Double,
|
|
||||||
val isVisible: Boolean
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun previewFlow(): Flow<StreamData> {
|
|
||||||
return flow {
|
return flow {
|
||||||
while (true) {
|
while (true) {
|
||||||
emit(StreamData(
|
emit((0..360).random().toDouble())
|
||||||
(0..360).random().toDouble(),
|
|
||||||
true
|
|
||||||
))
|
|
||||||
delay(1_000)
|
delay(1_000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,39 +74,31 @@ class WindDirectionDataType(val karooSystem: KarooSystemService, context: Contex
|
|||||||
val flow = if (config.preview){
|
val flow = if (config.preview){
|
||||||
previewFlow()
|
previewFlow()
|
||||||
} else {
|
} else {
|
||||||
combine(
|
karooSystem.streamDataFlow(dataTypeId)
|
||||||
karooSystem.streamDataFlow(dataTypeId),
|
.mapNotNull { (it as? StreamState.Streaming)?.dataPoint?.singleValue ?: 0.0 }
|
||||||
karooSystem.streamDatatypeIsVisible(dataTypeId)
|
|
||||||
) { windBearing, isVisible ->
|
|
||||||
StreamData(
|
|
||||||
windBearing = (windBearing as? StreamState.Streaming)?.dataPoint?.singleValue ?: 0.0,
|
|
||||||
isVisible = isVisible
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
|
flow
|
||||||
|
.collect { windBearing ->
|
||||||
|
val windCardinalDirectionIndex = ((windBearing % 360) / 22.5).roundToInt() % 16
|
||||||
|
|
||||||
flow.filter { it.isVisible }.throttle(refreshRate).collect { (windBearing, isVisible) ->
|
val text = windDirections[windCardinalDirectionIndex]
|
||||||
val windCardinalDirectionIndex = ((windBearing % 360) / 22.5).roundToInt() % 16
|
Log.d( KarooHeadwindExtension.TAG,"Updating wind direction view")
|
||||||
|
val result = glance.compose(context, DpSize.Unspecified) {
|
||||||
val text = windDirections[windCardinalDirectionIndex]
|
Box(modifier = GlanceModifier.fillMaxSize(),
|
||||||
Log.d(KarooHeadwindExtension.TAG,"Updating wind direction view")
|
contentAlignment = Alignment(
|
||||||
val result = glance.compose(context, DpSize.Unspecified) {
|
vertical = Alignment.Vertical.Top,
|
||||||
Box(modifier = GlanceModifier.fillMaxSize(),
|
horizontal = when(config.alignment){
|
||||||
contentAlignment = Alignment(
|
ViewConfig.Alignment.LEFT -> Alignment.Horizontal.Start
|
||||||
vertical = Alignment.Vertical.Top,
|
ViewConfig.Alignment.CENTER -> Alignment.Horizontal.CenterHorizontally
|
||||||
horizontal = when(config.alignment){
|
ViewConfig.Alignment.RIGHT -> Alignment.Horizontal.End
|
||||||
ViewConfig.Alignment.LEFT -> Alignment.Horizontal.Start
|
},
|
||||||
ViewConfig.Alignment.CENTER -> Alignment.Horizontal.CenterHorizontally
|
)) {
|
||||||
ViewConfig.Alignment.RIGHT -> Alignment.Horizontal.End
|
Text(text, style = TextStyle(color = ColorProvider(Color.Black, Color.White), fontFamily = FontFamily.Monospace, fontSize = TextUnit(
|
||||||
},
|
config.textSize.toFloat(), TextUnitType.Sp)))
|
||||||
)) {
|
}
|
||||||
Text(text, style = TextStyle(color = ColorProvider(Color.Black, Color.White), fontFamily = FontFamily.Monospace, fontSize = TextUnit(
|
|
||||||
config.textSize.toFloat(), TextUnitType.Sp)))
|
|
||||||
}
|
}
|
||||||
}
|
emitter.updateView(result.remoteViews)
|
||||||
emitter.updateView(result.remoteViews)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -103,8 +103,7 @@ class WindForecastDataType(karooSystem: KarooSystemService) : ForecastDataType(k
|
|||||||
timeLabel: String,
|
timeLabel: String,
|
||||||
dateLabel: String?,
|
dateLabel: String?,
|
||||||
distance: Double?,
|
distance: Double?,
|
||||||
isImperial: Boolean,
|
isImperial: Boolean
|
||||||
isNight: Boolean
|
|
||||||
) {
|
) {
|
||||||
WindForecast(
|
WindForecast(
|
||||||
arrowBitmap = arrowBitmap,
|
arrowBitmap = arrowBitmap,
|
||||||
@ -113,7 +112,7 @@ class WindForecastDataType(karooSystem: KarooSystemService) : ForecastDataType(k
|
|||||||
gustSpeed = windGusts,
|
gustSpeed = windGusts,
|
||||||
distance = distance,
|
distance = distance,
|
||||||
timeLabel = timeLabel,
|
timeLabel = timeLabel,
|
||||||
isImperial = isImperial,
|
isImperial = isImperial
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,10 +3,9 @@ package de.timklge.karooheadwind.datatypes
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
|
||||||
|
|
||||||
class WindGustsDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "windGusts"){
|
class WindGustsDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "windGusts"){
|
||||||
override fun getValue(data: WeatherData, userProfile: UserProfile): Double {
|
override fun getValue(data: WeatherData): Double {
|
||||||
return data.windGusts
|
return data.windGusts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,10 +3,9 @@ package de.timklge.karooheadwind.datatypes
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
|
||||||
|
|
||||||
class WindSpeedDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "windSpeed"){
|
class WindSpeedDataType(karooSystemService: KarooSystemService, context: Context) : BaseDataType(karooSystemService, context, "windSpeed"){
|
||||||
override fun getValue(data: WeatherData, userProfile: UserProfile): Double {
|
override fun getValue(data: WeatherData): Double {
|
||||||
return data.windSpeed
|
return data.windSpeed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,7 +84,6 @@ fun SettingsScreen(onFinish: () -> Unit) {
|
|||||||
|
|
||||||
var selectedWeatherProvider by remember { mutableStateOf(WeatherDataProvider.OPEN_METEO) }
|
var selectedWeatherProvider by remember { mutableStateOf(WeatherDataProvider.OPEN_METEO) }
|
||||||
var openWeatherMapApiKey by remember { mutableStateOf("") }
|
var openWeatherMapApiKey by remember { mutableStateOf("") }
|
||||||
var isK2 by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
ctx.streamSettings(karooSystem).collect { settings ->
|
ctx.streamSettings(karooSystem).collect { settings ->
|
||||||
@ -103,7 +102,6 @@ fun SettingsScreen(onFinish: () -> Unit) {
|
|||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
karooSystem.connect { connected ->
|
karooSystem.connect { connected ->
|
||||||
karooConnected = connected
|
karooConnected = connected
|
||||||
isK2 = karooSystem.hardwareType == io.hammerhead.karooext.models.HardwareType.K2
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,8 +151,8 @@ fun SettingsScreen(onFinish: () -> Unit) {
|
|||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(10.dp)
|
.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||||
) {
|
) {
|
||||||
val refreshRateDropdownOptions = remember(isK2) { RefreshRate.entries.toList().map { unit -> DropdownOption(unit.id, unit.getDescription(isK2)) } }
|
val refreshRateDropdownOptions = RefreshRate.entries.toList().map { unit -> DropdownOption(unit.id, unit.getDescription(karooSystem)) }
|
||||||
val refreshRateSelection by remember(refreshRateSetting, isK2) {
|
val refreshRateSelection by remember(refreshRateSetting) {
|
||||||
mutableStateOf(refreshRateDropdownOptions.find { option -> option.id == refreshRateSetting.id }!!)
|
mutableStateOf(refreshRateDropdownOptions.find { option -> option.id == refreshRateSetting.id }!!)
|
||||||
}
|
}
|
||||||
Dropdown(
|
Dropdown(
|
||||||
@ -162,7 +160,8 @@ fun SettingsScreen(onFinish: () -> Unit) {
|
|||||||
options = refreshRateDropdownOptions,
|
options = refreshRateDropdownOptions,
|
||||||
selected = refreshRateSelection
|
selected = refreshRateSelection
|
||||||
) { selectedOption ->
|
) { selectedOption ->
|
||||||
refreshRateSetting = RefreshRate.entries.find { unit -> unit.id == selectedOption.id }!!
|
refreshRateSetting =
|
||||||
|
RefreshRate.entries.find { unit -> unit.id == selectedOption.id }!!
|
||||||
}
|
}
|
||||||
|
|
||||||
val windDirectionIndicatorSettingDropdownOptions =
|
val windDirectionIndicatorSettingDropdownOptions =
|
||||||
|
|||||||
@ -37,9 +37,6 @@ import de.timklge.karooheadwind.streamCurrentWeatherData
|
|||||||
import de.timklge.karooheadwind.streamStats
|
import de.timklge.karooheadwind.streamStats
|
||||||
import de.timklge.karooheadwind.streamUpcomingRoute
|
import de.timklge.karooheadwind.streamUpcomingRoute
|
||||||
import de.timklge.karooheadwind.streamUserProfile
|
import de.timklge.karooheadwind.streamUserProfile
|
||||||
import de.timklge.karooheadwind.util.celciusInUserUnit
|
|
||||||
import de.timklge.karooheadwind.util.millimetersInUserUnit
|
|
||||||
import de.timklge.karooheadwind.util.msInUserUnit
|
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
import io.hammerhead.karooext.models.UserProfile
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@ -113,17 +110,16 @@ fun WeatherScreen(onFinish: () -> Unit) {
|
|||||||
baseBitmap = baseBitmap,
|
baseBitmap = baseBitmap,
|
||||||
current = WeatherInterpretation.fromWeatherCode(currentWeatherData?.weatherCode),
|
current = WeatherInterpretation.fromWeatherCode(currentWeatherData?.weatherCode),
|
||||||
windBearing = currentWeatherData?.windDirection?.roundToInt() ?: 0,
|
windBearing = currentWeatherData?.windDirection?.roundToInt() ?: 0,
|
||||||
windSpeed = msInUserUnit(currentWeatherData?.windSpeed ?: 0.0, profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
|
windSpeed = currentWeatherData?.windSpeed?.roundToInt() ?: 0,
|
||||||
windGusts = msInUserUnit(currentWeatherData?.windGusts ?: 0.0, profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
|
windGusts = currentWeatherData?.windGusts?.roundToInt() ?: 0,
|
||||||
precipitation = millimetersInUserUnit(currentWeatherData?.precipitation ?: 0.0, profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL),
|
precipitation = currentWeatherData?.precipitation ?: 0.0,
|
||||||
temperature = celciusInUserUnit(currentWeatherData?.temperature ?: 0.0, profile?.preferredUnit?.temperature == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
|
temperature = currentWeatherData?.temperature?.toInt() ?: 0,
|
||||||
temperatureUnit = if(profile?.preferredUnit?.temperature == UserProfile.PreferredUnit.UnitType.METRIC) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
|
temperatureUnit = if(profile?.preferredUnit?.temperature == UserProfile.PreferredUnit.UnitType.METRIC) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
|
||||||
timeLabel = formattedTime,
|
timeLabel = formattedTime,
|
||||||
dateLabel = formattedDate,
|
dateLabel = formattedDate,
|
||||||
distance = requestedWeatherPosition?.let { l -> location?.distanceTo(l)?.times(1000) },
|
distance = requestedWeatherPosition?.let { l -> location?.distanceTo(l)?.times(1000) },
|
||||||
includeDistanceLabel = false,
|
includeDistanceLabel = false,
|
||||||
isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL,
|
isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL,
|
||||||
isNight = currentWeatherData?.isNight == true
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,18 +229,17 @@ fun WeatherScreen(onFinish: () -> Unit) {
|
|||||||
baseBitmap,
|
baseBitmap,
|
||||||
current = interpretation,
|
current = interpretation,
|
||||||
windBearing = weatherData?.windDirection?.roundToInt() ?: 0,
|
windBearing = weatherData?.windDirection?.roundToInt() ?: 0,
|
||||||
windSpeed = msInUserUnit(currentWeatherData?.windSpeed ?: 0.0, profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
|
windSpeed = weatherData?.windSpeed?.roundToInt() ?: 0,
|
||||||
windGusts = msInUserUnit(currentWeatherData?.windGusts ?: 0.0, profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
|
windGusts = weatherData?.windGusts?.roundToInt() ?: 0,
|
||||||
precipitation = millimetersInUserUnit(weatherData?.precipitation ?: 0.0, profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL),
|
precipitation = weatherData?.precipitation ?: 0.0,
|
||||||
temperature = celciusInUserUnit(weatherData?.temperature ?: 0.0, profile?.preferredUnit?.temperature == UserProfile.PreferredUnit.UnitType.IMPERIAL).roundToInt(),
|
temperature = weatherData?.temperature?.toInt() ?: 0,
|
||||||
temperatureUnit = if (profile?.preferredUnit?.temperature != UserProfile.PreferredUnit.UnitType.IMPERIAL) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
|
temperatureUnit = if (profile?.preferredUnit?.temperature != UserProfile.PreferredUnit.UnitType.IMPERIAL) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
|
||||||
timeLabel = formattedForecastTime,
|
timeLabel = formattedForecastTime,
|
||||||
dateLabel = formattedForecastDate,
|
dateLabel = formattedForecastDate,
|
||||||
distance = distanceFromCurrent,
|
distance = distanceFromCurrent,
|
||||||
includeDistanceLabel = true,
|
includeDistanceLabel = true,
|
||||||
precipitationProbability = weatherData?.precipitationProbability?.toInt() ?: 0,
|
precipitationProbability = weatherData?.precipitationProbability?.toInt() ?: 0,
|
||||||
isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL,
|
isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
||||||
isNight = weatherData?.isNight == true,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LocalContentColor
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@ -47,10 +46,9 @@ fun WeatherWidget(
|
|||||||
distance: Double? = null,
|
distance: Double? = null,
|
||||||
includeDistanceLabel: Boolean = false,
|
includeDistanceLabel: Boolean = false,
|
||||||
precipitationProbability: Int? = null,
|
precipitationProbability: Int? = null,
|
||||||
isImperial: Boolean,
|
isImperial: Boolean
|
||||||
isNight: Boolean
|
|
||||||
) {
|
) {
|
||||||
val fontSize = 18.sp
|
val fontSize = 20.sp
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth().padding(5.dp),
|
modifier = Modifier.fillMaxWidth().padding(5.dp),
|
||||||
@ -99,20 +97,22 @@ fun WeatherWidget(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image(
|
// Weather icon (larger)
|
||||||
painter = painterResource(id = getWeatherIcon(current, isNight)),
|
Icon(
|
||||||
|
painter = painterResource(id = getWeatherIcon(current)),
|
||||||
contentDescription = "Current weather",
|
contentDescription = "Current weather",
|
||||||
modifier = Modifier.size(72.dp)
|
modifier = Modifier.size(72.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
Column(horizontalAlignment = Alignment.End) {
|
Column(horizontalAlignment = Alignment.End) {
|
||||||
|
// Temperature (larger)
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Image(
|
Icon(
|
||||||
painter = painterResource(id = R.drawable.thermometer),
|
painter = painterResource(id = R.drawable.thermometer),
|
||||||
contentDescription = "Temperature",
|
contentDescription = "Temperature",
|
||||||
modifier = Modifier.size(18.dp),
|
modifier = Modifier.size(18.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
@ -134,8 +134,8 @@ fun WeatherWidget(
|
|||||||
val precipitationProbabilityLabel =
|
val precipitationProbabilityLabel =
|
||||||
if (precipitationProbability != null) "${precipitationProbability}% " else ""
|
if (precipitationProbability != null) "${precipitationProbability}% " else ""
|
||||||
|
|
||||||
Image(
|
Icon(
|
||||||
painter = painterResource(id = R.drawable.droplet),
|
painter = painterResource(id = R.drawable.droplet_regular),
|
||||||
contentDescription = "Precipitation",
|
contentDescription = "Precipitation",
|
||||||
modifier = Modifier.size(18.dp)
|
modifier = Modifier.size(18.dp)
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
package de.timklge.karooheadwind.util
|
|
||||||
|
|
||||||
fun celciusInUserUnit(celcius: Double, isImperial: Boolean): Double {
|
|
||||||
return if (isImperial) {
|
|
||||||
celcius * 9.0 / 5 + 32.0
|
|
||||||
} else {
|
|
||||||
celcius
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun millimetersInUserUnit(millimeters: Double, isImperial: Boolean): Double {
|
|
||||||
return if (isImperial) {
|
|
||||||
millimeters / 25.4
|
|
||||||
} else {
|
|
||||||
millimeters
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the given speed value (m / s) in user unit (km/h or mph)
|
|
||||||
fun msInUserUnit(ms: Double, isImperial: Boolean): Double {
|
|
||||||
return if (isImperial) {
|
|
||||||
ms * 2.2369362920544
|
|
||||||
} else {
|
|
||||||
ms * 3.6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,17 +6,16 @@ import kotlinx.serialization.Serializable
|
|||||||
data class WeatherData(
|
data class WeatherData(
|
||||||
val time: Long,
|
val time: Long,
|
||||||
val temperature: Double,
|
val temperature: Double,
|
||||||
val relativeHumidity: Int,
|
val relativeHumidity: Double? = null,
|
||||||
val precipitation: Double,
|
val precipitation: Double,
|
||||||
val precipitationProbability: Double? = null,
|
val precipitationProbability: Double? = null,
|
||||||
val cloudCover: Double,
|
val cloudCover: Double? = null,
|
||||||
val sealevelPressure: Double,
|
val sealevelPressure: Double? = null,
|
||||||
val surfacePressure: Double,
|
val surfacePressure: Double? = null,
|
||||||
val windSpeed: Double,
|
val windSpeed: Double,
|
||||||
val windDirection: Double,
|
val windDirection: Double,
|
||||||
val windGusts: Double,
|
val windGusts: Double,
|
||||||
val weatherCode: Int,
|
val weatherCode: Int,
|
||||||
val isForecast: Boolean,
|
val isForecast: Boolean
|
||||||
val isNight: Boolean
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -12,16 +12,15 @@ data class OpenMeteoWeatherData(
|
|||||||
@SerialName("precipitation") val precipitation: Double,
|
@SerialName("precipitation") val precipitation: Double,
|
||||||
@SerialName("cloud_cover") val cloudCover: Int,
|
@SerialName("cloud_cover") val cloudCover: Int,
|
||||||
@SerialName("surface_pressure") val surfacePressure: Double,
|
@SerialName("surface_pressure") val surfacePressure: Double,
|
||||||
@SerialName("pressure_msl") val sealevelPressure: Double,
|
@SerialName("pressure_msl") val sealevelPressure: Double? = null,
|
||||||
@SerialName("wind_speed_10m") val windSpeed: Double,
|
@SerialName("wind_speed_10m") val windSpeed: Double,
|
||||||
@SerialName("wind_direction_10m") val windDirection: Double,
|
@SerialName("wind_direction_10m") val windDirection: Double,
|
||||||
@SerialName("wind_gusts_10m") val windGusts: Double,
|
@SerialName("wind_gusts_10m") val windGusts: Double,
|
||||||
@SerialName("weather_code") val weatherCode: Int,
|
@SerialName("weather_code") val weatherCode: Int,
|
||||||
@SerialName("is_day") val isDay: Int,
|
|
||||||
) {
|
) {
|
||||||
fun toWeatherData(): WeatherData = WeatherData(
|
fun toWeatherData(): WeatherData = WeatherData(
|
||||||
temperature = temperature,
|
temperature = temperature,
|
||||||
relativeHumidity = relativeHumidity,
|
relativeHumidity = relativeHumidity.toDouble(),
|
||||||
precipitation = precipitation,
|
precipitation = precipitation,
|
||||||
cloudCover = cloudCover.toDouble(),
|
cloudCover = cloudCover.toDouble(),
|
||||||
surfacePressure = surfacePressure,
|
surfacePressure = surfacePressure,
|
||||||
@ -32,7 +31,6 @@ data class OpenMeteoWeatherData(
|
|||||||
weatherCode = weatherCode,
|
weatherCode = weatherCode,
|
||||||
time = time,
|
time = time,
|
||||||
isForecast = false,
|
isForecast = false,
|
||||||
isNight = isDay == 0,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,12 +14,7 @@ data class OpenMeteoWeatherForecastData(
|
|||||||
@SerialName("wind_speed_10m") val windSpeed: List<Double>,
|
@SerialName("wind_speed_10m") val windSpeed: List<Double>,
|
||||||
@SerialName("wind_direction_10m") val windDirection: List<Double>,
|
@SerialName("wind_direction_10m") val windDirection: List<Double>,
|
||||||
@SerialName("wind_gusts_10m") val windGusts: List<Double>,
|
@SerialName("wind_gusts_10m") val windGusts: List<Double>,
|
||||||
@SerialName("cloud_cover") val cloudCover: List<Double>,
|
) {
|
||||||
@SerialName("surface_pressure") val surfacePressure: List<Double>,
|
|
||||||
@SerialName("pressure_msl") val sealevelPressure: List<Double>,
|
|
||||||
@SerialName("is_day") val isDay: List<Int>,
|
|
||||||
@SerialName("relative_humidity_2m") val relativeHumidity: List<Int>,
|
|
||||||
) {
|
|
||||||
fun toWeatherData(): List<WeatherData> {
|
fun toWeatherData(): List<WeatherData> {
|
||||||
return time.mapIndexed { index, t ->
|
return time.mapIndexed { index, t ->
|
||||||
WeatherData(
|
WeatherData(
|
||||||
@ -30,13 +25,8 @@ data class OpenMeteoWeatherForecastData(
|
|||||||
windDirection = windDirection[index],
|
windDirection = windDirection[index],
|
||||||
windGusts = windGusts[index],
|
windGusts = windGusts[index],
|
||||||
weatherCode = weatherCode[index],
|
weatherCode = weatherCode[index],
|
||||||
isNight = isDay[index] == 0,
|
|
||||||
time = t,
|
time = t,
|
||||||
isForecast = true,
|
isForecast = true,
|
||||||
cloudCover = cloudCover[index],
|
|
||||||
surfacePressure = surfacePressure[index],
|
|
||||||
sealevelPressure = sealevelPressure[index],
|
|
||||||
relativeHumidity = relativeHumidity[index],
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,10 @@ package de.timklge.karooheadwind.weatherprovider.openmeteo
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import de.timklge.karooheadwind.HeadwindSettings
|
import de.timklge.karooheadwind.HeadwindSettings
|
||||||
import de.timklge.karooheadwind.KarooHeadwindExtension
|
import de.timklge.karooheadwind.KarooHeadwindExtension
|
||||||
|
import de.timklge.karooheadwind.PrecipitationUnit
|
||||||
|
import de.timklge.karooheadwind.TemperatureUnit
|
||||||
import de.timklge.karooheadwind.WeatherDataProvider
|
import de.timklge.karooheadwind.WeatherDataProvider
|
||||||
|
import de.timklge.karooheadwind.WindUnit
|
||||||
import de.timklge.karooheadwind.datatypes.GpsCoordinates
|
import de.timklge.karooheadwind.datatypes.GpsCoordinates
|
||||||
import de.timklge.karooheadwind.jsonWithUnknownKeys
|
import de.timklge.karooheadwind.jsonWithUnknownKeys
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherDataResponse
|
import de.timklge.karooheadwind.weatherprovider.WeatherDataResponse
|
||||||
@ -25,12 +28,16 @@ import kotlin.time.Duration.Companion.seconds
|
|||||||
|
|
||||||
class OpenMeteoWeatherProvider : WeatherProvider {
|
class OpenMeteoWeatherProvider : WeatherProvider {
|
||||||
@OptIn(FlowPreview::class)
|
@OptIn(FlowPreview::class)
|
||||||
private suspend fun makeOpenMeteoWeatherRequest(karooSystemService: KarooSystemService, gpsCoordinates: List<GpsCoordinates>): HttpResponseState.Complete {
|
private suspend fun makeOpenMeteoWeatherRequest(karooSystemService: KarooSystemService, gpsCoordinates: List<GpsCoordinates>, settings: HeadwindSettings, profile: UserProfile?): HttpResponseState.Complete {
|
||||||
|
val precipitationUnit = if (profile?.preferredUnit?.distance != UserProfile.PreferredUnit.UnitType.IMPERIAL) PrecipitationUnit.MILLIMETERS else PrecipitationUnit.INCH
|
||||||
|
val temperatureUnit = if (profile?.preferredUnit?.temperature != UserProfile.PreferredUnit.UnitType.IMPERIAL) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT
|
||||||
|
val windUnit = if (profile?.preferredUnit?.distance != UserProfile.PreferredUnit.UnitType.IMPERIAL) WindUnit.KILOMETERS_PER_HOUR else WindUnit.MILES_PER_HOUR
|
||||||
|
|
||||||
val response = callbackFlow {
|
val response = callbackFlow {
|
||||||
// https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41¤t=is_day,surface_pressure,pressure_msl,temperature_2m,relative_humidity_2m,precipitation,weather_code,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,precipitation_probability,precipitation,weather_code,wind_speed_10m,wind_direction_10m,wind_gusts_10m&timeformat=unixtime&past_hours=1&forecast_days=1&forecast_hours=12
|
// https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41¤t=surface_pressure,pressure_msl,temperature_2m,relative_humidity_2m,precipitation,weather_code,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,precipitation_probability,precipitation,weather_code,wind_speed_10m,wind_direction_10m,wind_gusts_10m&timeformat=unixtime&past_hours=1&forecast_days=1&forecast_hours=12
|
||||||
val lats = gpsCoordinates.joinToString(",") { String.format(Locale.US, "%.6f", it.lat) }
|
val lats = gpsCoordinates.joinToString(",") { String.format(Locale.US, "%.6f", it.lat) }
|
||||||
val lons = gpsCoordinates.joinToString(",") { String.format(Locale.US, "%.6f", it.lon) }
|
val lons = gpsCoordinates.joinToString(",") { String.format(Locale.US, "%.6f", it.lon) }
|
||||||
val url = "https://api.open-meteo.com/v1/forecast?latitude=${lats}&longitude=${lons}¤t=is_day,surface_pressure,pressure_msl,temperature_2m,relative_humidity_2m,precipitation,weather_code,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,precipitation_probability,precipitation,weather_code,wind_speed_10m,wind_direction_10m,wind_gusts_10m,is_day,surface_pressure,pressure_msl,relative_humidity_2m,cloud_cover&timeformat=unixtime&past_hours=0&forecast_days=1&forecast_hours=12&wind_speed_unit=ms"
|
val url = "https://api.open-meteo.com/v1/forecast?latitude=${lats}&longitude=${lons}¤t=surface_pressure,pressure_msl,temperature_2m,relative_humidity_2m,precipitation,weather_code,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,precipitation_probability,precipitation,weather_code,wind_speed_10m,wind_direction_10m,wind_gusts_10m&timeformat=unixtime&past_hours=0&forecast_days=1&forecast_hours=12&wind_speed_unit=${windUnit.id}&precipitation_unit=${precipitationUnit.id}&temperature_unit=${temperatureUnit.id}"
|
||||||
|
|
||||||
Log.d(KarooHeadwindExtension.TAG, "Http request to ${url}...")
|
Log.d(KarooHeadwindExtension.TAG, "Http request to ${url}...")
|
||||||
|
|
||||||
@ -77,7 +84,7 @@ class OpenMeteoWeatherProvider : WeatherProvider {
|
|||||||
settings: HeadwindSettings,
|
settings: HeadwindSettings,
|
||||||
profile: UserProfile?
|
profile: UserProfile?
|
||||||
): WeatherDataResponse {
|
): WeatherDataResponse {
|
||||||
val openMeteoResponse = makeOpenMeteoWeatherRequest(karooSystem, coordinates)
|
val openMeteoResponse = makeOpenMeteoWeatherRequest(karooSystem, coordinates, settings, profile)
|
||||||
val responseBody = openMeteoResponse.body?.let { String(it) } ?: throw WeatherProviderException(500, "Null response from OpenMeteo")
|
val responseBody = openMeteoResponse.body?.let { String(it) } ?: throw WeatherProviderException(500, "Null response from OpenMeteo")
|
||||||
|
|
||||||
val weatherData = if (coordinates.size == 1) {
|
val weatherData = if (coordinates.size == 1) {
|
||||||
@ -95,4 +102,4 @@ class OpenMeteoWeatherProvider : WeatherProvider {
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,8 +2,6 @@ package de.timklge.karooheadwind.weatherprovider.openweathermap
|
|||||||
|
|
||||||
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
import de.timklge.karooheadwind.weatherprovider.WeatherData
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import java.time.Instant
|
|
||||||
import java.time.ZoneOffset
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class OpenWeatherMapForecastData(
|
data class OpenWeatherMapForecastData(
|
||||||
@ -22,31 +20,20 @@ data class OpenWeatherMapForecastData(
|
|||||||
val snow: Snow? = null,
|
val snow: Snow? = null,
|
||||||
val weather: List<Weather>
|
val weather: List<Weather>
|
||||||
) {
|
) {
|
||||||
fun toWeatherData(currentWeatherData: OpenWeatherMapWeatherData): WeatherData {
|
fun toWeatherData(): WeatherData = WeatherData(
|
||||||
val dtInstant = Instant.ofEpochSecond(dt)
|
temperature = temp,
|
||||||
val sunriseInstant = Instant.ofEpochSecond(currentWeatherData.sunrise)
|
relativeHumidity = humidity.toDouble(),
|
||||||
val sunsetInstant = Instant.ofEpochSecond(currentWeatherData.sunset)
|
precipitation = rain?.h1 ?: 0.0,
|
||||||
|
cloudCover = clouds.toDouble(),
|
||||||
val dtTime = dtInstant.atZone(ZoneOffset.UTC).toLocalTime()
|
surfacePressure = pressure.toDouble(),
|
||||||
val sunriseTime = sunriseInstant.atZone(ZoneOffset.UTC).toLocalTime()
|
sealevelPressure = pressure.toDouble(), // FIXME
|
||||||
val sunsetTime = sunsetInstant.atZone(ZoneOffset.UTC).toLocalTime()
|
windSpeed = wind_speed,
|
||||||
|
windDirection = wind_deg.toDouble(),
|
||||||
return WeatherData(
|
windGusts = wind_gust ?: wind_speed,
|
||||||
temperature = temp,
|
weatherCode = OpenWeatherMapWeatherProvider.convertWeatherCodeToOpenMeteo(
|
||||||
relativeHumidity = humidity,
|
weather.firstOrNull()?.id ?: 800
|
||||||
precipitation = rain?.h1 ?: 0.0,
|
),
|
||||||
cloudCover = clouds.toDouble(),
|
time = dt,
|
||||||
surfacePressure = pressure.toDouble(),
|
isForecast = true
|
||||||
sealevelPressure = pressure.toDouble(), // FIXME
|
)
|
||||||
windSpeed = wind_speed,
|
}
|
||||||
windDirection = wind_deg.toDouble(),
|
|
||||||
windGusts = wind_gust ?: wind_speed,
|
|
||||||
weatherCode = OpenWeatherMapWeatherProvider.convertWeatherCodeToOpenMeteo(
|
|
||||||
weather.firstOrNull()?.id ?: 800
|
|
||||||
),
|
|
||||||
time = dt,
|
|
||||||
isForecast = true,
|
|
||||||
isNight = dtTime.isBefore(sunriseTime) || dtTime.isAfter(sunsetTime)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -23,7 +23,7 @@ data class OpenWeatherMapWeatherData(
|
|||||||
|
|
||||||
fun toWeatherData(): WeatherData = WeatherData(
|
fun toWeatherData(): WeatherData = WeatherData(
|
||||||
temperature = temp,
|
temperature = temp,
|
||||||
relativeHumidity = humidity,
|
relativeHumidity = humidity.toDouble(),
|
||||||
precipitation = rain?.h1 ?: 0.0,
|
precipitation = rain?.h1 ?: 0.0,
|
||||||
cloudCover = clouds.toDouble(),
|
cloudCover = clouds.toDouble(),
|
||||||
surfacePressure = pressure.toDouble(),
|
surfacePressure = pressure.toDouble(),
|
||||||
@ -35,9 +35,6 @@ data class OpenWeatherMapWeatherData(
|
|||||||
weather.firstOrNull()?.id ?: 800
|
weather.firstOrNull()?.id ?: 800
|
||||||
),
|
),
|
||||||
time = dt,
|
time = dt,
|
||||||
isNight = let {
|
|
||||||
dt !in sunrise..<sunset
|
|
||||||
},
|
|
||||||
isForecast = false
|
isForecast = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -14,17 +14,10 @@ data class OpenWeatherMapWeatherDataForLocation(
|
|||||||
val current: OpenWeatherMapWeatherData,
|
val current: OpenWeatherMapWeatherData,
|
||||||
val hourly: List<OpenWeatherMapForecastData>
|
val hourly: List<OpenWeatherMapForecastData>
|
||||||
){
|
){
|
||||||
fun toWeatherDataForLocation(distanceAlongRoute: Double?): WeatherDataForLocation {
|
fun toWeatherDataForLocation(distanceAlongRoute: Double?): WeatherDataForLocation = WeatherDataForLocation(
|
||||||
return WeatherDataForLocation(
|
current = current.toWeatherData(),
|
||||||
current = current.toWeatherData(),
|
coords = GpsCoordinates(lat, lon, bearing = null, distanceAlongRoute = distanceAlongRoute),
|
||||||
coords = GpsCoordinates(
|
timezone = timezone,
|
||||||
lat,
|
forecasts = hourly.map { it.toWeatherData() }
|
||||||
lon,
|
)
|
||||||
bearing = null,
|
|
||||||
distanceAlongRoute = distanceAlongRoute
|
|
||||||
),
|
|
||||||
timezone = timezone,
|
|
||||||
forecasts = hourly.map { it.toWeatherData(current) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ class OpenWeatherMapWeatherProvider(private val apiKey: String) : WeatherProvide
|
|||||||
profile: UserProfile?
|
profile: UserProfile?
|
||||||
): WeatherDataResponse {
|
): WeatherDataResponse {
|
||||||
|
|
||||||
val response = makeOpenWeatherMapRequest(karooSystem, coordinates, apiKey)
|
val response = makeOpenWeatherMapRequest(karooSystem, coordinates, apiKey, profile)
|
||||||
val responseBody = response.body?.let { String(it) } ?: throw Exception("Null response from OpenWeatherMap")
|
val responseBody = response.body?.let { String(it) } ?: throw Exception("Null response from OpenWeatherMap")
|
||||||
|
|
||||||
val responses = mutableListOf<WeatherDataForLocation>()
|
val responses = mutableListOf<WeatherDataForLocation>()
|
||||||
@ -89,15 +89,21 @@ class OpenWeatherMapWeatherProvider(private val apiKey: String) : WeatherProvide
|
|||||||
private suspend fun makeOpenWeatherMapRequest(
|
private suspend fun makeOpenWeatherMapRequest(
|
||||||
service: KarooSystemService,
|
service: KarooSystemService,
|
||||||
coordinates: List<GpsCoordinates>,
|
coordinates: List<GpsCoordinates>,
|
||||||
apiKey: String
|
apiKey: String,
|
||||||
|
profile: UserProfile?
|
||||||
): HttpResponseState.Complete {
|
): HttpResponseState.Complete {
|
||||||
val response = callbackFlow {
|
val response = callbackFlow {
|
||||||
// OpenWeatherMap only supports setting imperial or metric units for all measurements, not individually for distance / temperature
|
// OpenWeatherMap only supports setting imperial or metric units for all measurements, not individually for distance / temperature
|
||||||
|
val unitsString = if (profile?.preferredUnit?.temperature == UserProfile.PreferredUnit.UnitType.IMPERIAL || profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL) {
|
||||||
|
"imperial"
|
||||||
|
} else {
|
||||||
|
"metric"
|
||||||
|
}
|
||||||
val coordinate = coordinates.first()
|
val coordinate = coordinates.first()
|
||||||
|
|
||||||
// URL API 3.0 with onecall endpoint
|
// URL API 3.0 with onecall endpoint
|
||||||
val url = "https://api.openweathermap.org/data/3.0/onecall?lat=${coordinate.lat}&lon=${coordinate.lon}" +
|
val url = "https://api.openweathermap.org/data/3.0/onecall?lat=${coordinate.lat}&lon=${coordinate.lon}" +
|
||||||
"&appid=$apiKey&exclude=minutely,daily,alerts&units=metric"
|
"&appid=$apiKey&exclude=minutely,daily,alerts&units=${unitsString}"
|
||||||
|
|
||||||
Log.d(KarooHeadwindExtension.TAG, "Http request to OpenWeatherMap API 3.0: $url")
|
Log.d(KarooHeadwindExtension.TAG, "Http request to OpenWeatherMap API 3.0: $url")
|
||||||
|
|
||||||
|
|||||||
BIN
app/src/main/res/drawable/bx_clear.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
app/src/main/res/drawable/bx_cloud.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
app/src/main/res/drawable/bx_cloud_drizzle.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
app/src/main/res/drawable/bx_cloud_light_rain.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
app/src/main/res/drawable/bx_cloud_lightning.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
app/src/main/res/drawable/bx_cloud_rain.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
app/src/main/res/drawable/bx_cloud_snow.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
@ -1,40 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="128dp"
|
|
||||||
android:height="128dp"
|
|
||||||
android:viewportWidth="128"
|
|
||||||
android:viewportHeight="128">
|
|
||||||
<path
|
|
||||||
android:pathData="m106.54,56.4c-0.68,0 -1.35,0.05 -2.01,0.13 0.52,-1.75 0.81,-3.6 0.81,-5.52 0,-10.7 -8.67,-19.37 -19.37,-19.37 -4.55,0 -8.73,1.58 -12.04,4.21 -4.45,-8.44 -13.3,-14.2 -23.51,-14.2 -14.67,0 -26.56,11.89 -26.56,26.56 0,0.53 0.02,1.05 0.05,1.57 -11.06,1.36 -19.63,10.78 -19.63,22.2 0,12.22 9.81,22.15 21.98,22.36 4.08,7.08 12.2,11.94 21.59,12.01 9.08,0.07 17.03,-4.36 21.33,-11 3.47,3.79 8.44,6.19 13.99,6.19 7.94,0 14.74,-4.89 17.56,-11.81 1.82,0.65 3.76,1.03 5.8,1.03 9.49,0 17.18,-7.69 17.18,-17.18 0.01,-9.49 -7.68,-17.18 -17.17,-17.18z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="36.79"
|
|
||||||
android:centerY="18.87"
|
|
||||||
android:gradientRadius="114.63"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.14" android:color="#FFE3F2FD"/>
|
|
||||||
<item android:offset="1" android:color="#FF90CAF9"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m47.86,105c-8.55,0 -16.33,-4.46 -20.3,-11.34 -0.26,-0.46 -0.75,-0.78 -1.27,-0.79 -11.31,-0.2 -20.51,-9.57 -20.51,-20.87 0,-10.52 7.87,-19.42 18.31,-20.7 0.79,-0.1 1.36,-0.79 1.31,-1.58 -0.03,-0.5 -0.05,-1 -0.05,-1.5 0,-13.82 11.24,-25.06 25.06,-25.06 9.33,0 17.83,5.13 22.18,13.4 0.21,0.4 0.58,0.68 1.02,0.77 0.1,0.02 0.21,0.03 0.31,0.03 0.34,0 0.67,-0.11 0.93,-0.33 3.2,-2.54 7.04,-3.89 11.11,-3.89 9.86,0 17.87,8.02 17.87,17.87 0,1.71 -0.25,3.42 -0.75,5.09 -0.14,0.48 -0.03,1.01 0.29,1.39 0.29,0.34 0.71,0.53 1.15,0.53 0.06,0 0.12,0 0.17,-0.01 0.68,-0.08 1.28,-0.12 1.83,-0.12 8.64,0 15.68,7.03 15.68,15.68s-7.03,15.68 -15.68,15.68c-1.78,0 -3.56,-0.32 -5.3,-0.94 -0.17,-0.06 -0.34,-0.09 -0.51,-0.09 -0.59,0 -1.15,0.35 -1.39,0.93 -2.7,6.61 -9.05,10.88 -16.18,10.88 -4.88,0 -9.58,-2.08 -12.89,-5.71 -0.29,-0.31 -0.69,-0.49 -1.11,-0.49h-0.12c-0.46,0.04 -0.88,0.36 -1.13,0.76 -4.13,6.37 -11.73,10.4 -19.85,10.4h-0.18z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillAlpha="0.2">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="37.48"
|
|
||||||
android:centerY="20.46"
|
|
||||||
android:gradientRadius="111.26"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.14" android:color="#FFE3F2FD"/>
|
|
||||||
<item android:offset="1" android:color="#FF90CAF9"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m50.42,24.65c8.77,0 16.76,4.83 20.85,12.6 0.42,0.79 1.16,1.35 2.04,1.54 0.2,0.04 0.41,0.06 0.62,0.06 0.67,0 1.33,-0.23 1.87,-0.65 2.93,-2.33 6.45,-3.56 10.17,-3.56 9.03,0 16.37,7.34 16.37,16.37 0,1.57 -0.23,3.14 -0.68,4.67 -0.29,0.97 -0.07,2.01 0.58,2.78 0.57,0.68 1.42,1.07 2.3,1.07 0.12,0 0.23,-0.01 0.35,-0.02 0.62,-0.07 1.16,-0.11 1.66,-0.11 7.82,0 14.18,6.36 14.18,14.18s-6.36,14.18 -14.18,14.18c-1.61,0 -3.22,-0.29 -4.79,-0.85 -0.33,-0.12 -0.68,-0.18 -1.01,-0.18 -1.19,0 -2.3,0.71 -2.78,1.87 -2.47,6.04 -8.27,9.95 -14.79,9.95 -4.46,0 -8.75,-1.9 -11.78,-5.22 -0.57,-0.63 -1.38,-0.98 -2.22,-0.98 -0.08,0 -0.16,0 -0.25,0.01 -0.93,0.08 -1.77,0.4 -2.27,1.18 -3.86,5.94 -10.98,9.46 -18.6,9.46h-0.18c-8.02,0 -15.31,-3.92 -19.01,-10.34 -0.53,-0.91 -1.49,-1.4 -2.55,-1.42 -10.5,-0.18 -19.04,-8.81 -19.04,-19.3 0,-9.76 7.3,-18 16.99,-19.18 1.57,-0.19 2.72,-1.56 2.63,-3.14 -0.03,-0.53 -0.05,-0.98 -0.05,-1.4 0.01,-13 10.58,-23.57 23.57,-23.57m0,-3c-14.67,0 -26.56,11.89 -26.56,26.56 0,0.53 0.02,1.06 0.05,1.58 -11.06,1.36 -19.63,10.77 -19.63,22.19 0,12.22 9.81,21.97 21.98,22.17 4.08,7.08 12.2,11.84 21.59,11.84h0.21c8.99,0 16.85,-4.25 21.12,-10.84 3.47,3.8 8.45,6.29 14,6.29 7.94,0 14.74,-4.84 17.56,-11.77 1.82,0.65 3.76,1.05 5.8,1.05 9.49,0 17.18,-7.68 17.18,-17.16s-7.69,-17.17 -17.18,-17.17c-0.68,0 -1.35,0.05 -2.01,0.13 0.52,-1.75 0.81,-3.6 0.81,-5.52 0,-10.7 -8.67,-19.37 -19.37,-19.37 -4.55,0 -8.73,1.58 -12.04,4.21 -4.45,-8.43 -13.31,-14.19 -23.51,-14.19z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
</vector>
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="128dp"
|
|
||||||
android:height="128dp"
|
|
||||||
android:viewportWidth="128"
|
|
||||||
android:viewportHeight="128">
|
|
||||||
<path
|
|
||||||
android:pathData="m106.97,39.56c-0.68,0 -1.35,0.05 -2,0.13 0.52,-1.75 0.81,-3.59 0.81,-5.51 0,-10.68 -8.66,-19.34 -19.34,-19.34 -4.55,0 -8.72,1.58 -12.02,4.21 -4.45,-8.43 -13.29,-14.18 -23.48,-14.18 -14.64,0 -26.52,11.87 -26.52,26.52 0,0.53 0.02,1.05 0.05,1.57 -11.03,1.35 -19.58,10.75 -19.58,22.15 0,12.2 9.79,22.11 21.94,22.32 4.07,7.07 12.18,11.92 21.55,11.99 9.06,0.07 17,-4.35 21.3,-10.98 3.46,3.79 8.43,6.18 13.96,6.18 7.93,0 14.71,-4.88 17.53,-11.79 1.81,0.65 3.76,1.02 5.79,1.02 9.47,0 17.15,-7.68 17.15,-17.15 0,-9.46 -7.68,-17.14 -17.14,-17.14z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="59.47"
|
|
||||||
android:centerY="-5.18"
|
|
||||||
android:gradientRadius="120.22"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.26" android:color="#FFE3F2FD"/>
|
|
||||||
<item android:offset="0.92" android:color="#FF90CAF9"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m50.94,7.87c8.75,0 16.73,4.82 20.81,12.57 0.42,0.79 1.16,1.35 2.04,1.54 0.2,0.04 0.41,0.06 0.62,0.06 0.67,0 1.33,-0.23 1.87,-0.65 2.92,-2.32 6.43,-3.55 10.15,-3.55 9.01,0 16.34,7.33 16.34,16.34 0,1.56 -0.23,3.13 -0.68,4.66 -0.29,0.97 -0.07,2.01 0.58,2.78 0.57,0.68 1.42,1.07 2.3,1.07 0.12,0 0.23,-0.01 0.35,-0.02 0.62,-0.07 1.16,-0.11 1.66,-0.11 7.8,0 14.15,6.35 14.15,14.15s-6.35,14.15 -14.15,14.15c-1.61,0 -3.21,-0.29 -4.78,-0.85 -0.33,-0.12 -0.68,-0.18 -1.01,-0.18 -1.19,0 -2.3,0.71 -2.78,1.87 -2.46,6.03 -8.25,9.92 -14.76,9.92 -4.45,0 -8.74,-1.9 -11.76,-5.21 -0.57,-0.63 -1.38,-0.98 -2.22,-0.98 -0.08,0 -0.16,0 -0.25,0.01 -0.93,0.08 -1.77,0.37 -2.27,1.15 -3.85,5.93 -10.96,9.41 -18.56,9.41h-0.19c-8.01,0 -15.28,-3.87 -18.97,-10.28 -0.53,-0.91 -1.49,-1.38 -2.55,-1.4 -10.47,-0.18 -18.99,-8.79 -18.99,-19.26 0,-9.74 7.29,-17.95 16.95,-19.14 1.57,-0.19 2.72,-1.56 2.63,-3.14 -0.03,-0.52 -0.05,-0.98 -0.05,-1.4 0.01,-12.96 10.56,-23.51 23.52,-23.51m0,-3c-14.64,0 -26.52,11.87 -26.52,26.52 0,0.53 0.02,1.06 0.05,1.58 -11.03,1.35 -19.58,10.74 -19.58,22.14 0,12.2 9.79,21.89 21.94,22.1 4.07,7.07 12.17,11.79 21.55,11.79h0.21c8.98,0 16.82,-4.2 21.08,-10.78 3.46,3.79 8.43,6.29 13.98,6.29 7.93,0 14.71,-4.82 17.53,-11.74 1.81,0.65 3.76,1.05 5.79,1.05 9.47,0 17.15,-7.66 17.15,-17.13s-7.68,-17.14 -17.15,-17.14c-0.68,0 -1.35,0.05 -2,0.13 0.52,-1.75 0.81,-3.59 0.81,-5.51 0,-10.68 -8.66,-19.34 -19.34,-19.34 -4.55,0 -8.72,1.58 -12.02,4.21 -4.45,-8.42 -13.29,-14.17 -23.48,-14.17z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m91.26,111.28c-1.78,3.88 -6.36,5.58 -10.24,3.8 -3.88,-1.78 -5.58,-6.36 -3.8,-10.24 1.78,-3.88 13.36,-11.57 13.36,-11.57 0,0 2.46,14.13 0.68,18.01z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m91.26,111.28c-1.78,3.88 -6.36,5.58 -10.24,3.8 -3.88,-1.78 -5.58,-6.36 -3.8,-10.24 1.78,-3.88 13.36,-11.57 13.36,-11.57 0,0 2.46,14.13 0.68,18.01z"
|
|
||||||
android:fillColor="#90caf9"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m50.84,113.15c-1.78,3.88 -6.36,5.58 -10.24,3.8 -3.88,-1.78 -5.58,-6.36 -3.8,-10.24 1.78,-3.88 13.36,-11.57 13.36,-11.57 0,0 2.46,14.13 0.68,18.01z"
|
|
||||||
android:fillColor="#90caf9"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m48.68,98.59c0.74,5.36 1.22,11.83 0.35,13.72 -0.93,2.03 -2.97,3.34 -5.21,3.34 -0.82,0 -1.62,-0.18 -2.38,-0.52 -2.87,-1.32 -4.13,-4.72 -2.82,-7.59 0.88,-1.91 5.78,-5.89 10.06,-8.95m1.48,-3.45c0,0 -11.58,7.7 -13.36,11.57 -1.78,3.88 -0.08,8.46 3.8,10.24 1.04,0.48 2.14,0.71 3.21,0.71 2.93,0 5.72,-1.67 7.02,-4.5 1.79,-3.89 -0.67,-18.02 -0.67,-18.02z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m89.1,96.72c0.74,5.36 1.22,11.83 0.35,13.72 -0.93,2.03 -2.97,3.34 -5.21,3.34 -0.82,0 -1.62,-0.18 -2.38,-0.52 -1.39,-0.64 -2.45,-1.78 -2.98,-3.21 -0.53,-1.43 -0.47,-2.99 0.16,-4.38 0.88,-1.91 5.78,-5.89 10.06,-8.95m1.48,-3.45c0,0 -11.58,7.7 -13.36,11.57 -1.78,3.88 -0.08,8.46 3.8,10.24 1.04,0.48 2.14,0.71 3.21,0.71 2.93,0 5.72,-1.67 7.02,-4.5 1.79,-3.89 -0.67,-18.02 -0.67,-18.02z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m89.1,96.72c0.74,5.36 1.22,11.83 0.35,13.72 -0.93,2.03 -2.97,3.34 -5.21,3.34 -0.82,0 -1.62,-0.18 -2.38,-0.52 -1.39,-0.64 -2.45,-1.78 -2.98,-3.21 -0.53,-1.43 -0.47,-2.99 0.16,-4.38 0.88,-1.91 5.78,-5.89 10.06,-8.95m1.48,-3.45c0,0 -11.58,7.7 -13.36,11.57 -1.78,3.88 -0.08,8.46 3.8,10.24 1.04,0.48 2.14,0.71 3.21,0.71 2.93,0 5.72,-1.67 7.02,-4.5 1.79,-3.89 -0.67,-18.02 -0.67,-18.02z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
</vector>
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="128dp"
|
|
||||||
android:height="128dp"
|
|
||||||
android:viewportWidth="128"
|
|
||||||
android:viewportHeight="128">
|
|
||||||
<path
|
|
||||||
android:pathData="m51.04,121.76 l13.8,-24.27c0.39,-0.68 -0.1,-1.53 -0.89,-1.54l-26.19,-0.1c-0.95,0 -1.39,-1.17 -0.68,-1.8l34.24,-30.28c0.85,-0.75 2.12,0.23 1.6,1.24l-10.37,20.07c-0.35,0.68 0.14,1.5 0.91,1.5l26.78,0.17c0.94,0.01 1.38,1.16 0.68,1.79l-38.3,34.49c-0.87,0.79 -2.16,-0.25 -1.58,-1.27z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:startX="59.01"
|
|
||||||
android:startY="73.87"
|
|
||||||
android:endX="71.67"
|
|
||||||
android:endY="118.12"
|
|
||||||
android:type="linear">
|
|
||||||
<item android:offset="0" android:color="#FFFBC02D"/>
|
|
||||||
<item android:offset="1" android:color="#FFFFEB3B"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m65.41,73.01 l-5.52,10.69c-0.65,1.25 -0.6,2.72 0.13,3.93s2.01,1.94 3.42,1.94l21.69,0.14 -25.47,22.93 7.78,-13.68c0.71,-1.24 0.7,-2.78 -0.02,-4.01 -0.71,-1.23 -2.05,-2 -3.47,-2.01l-21.01,-0.08zM71.99,63.51c-0.23,0 -0.46,0.08 -0.67,0.27l-34.24,30.28c-0.71,0.63 -0.27,1.8 0.68,1.8l26.19,0.1c0.79,0 1.28,0.85 0.89,1.54l-13.8,24.27c-0.44,0.77 0.19,1.55 0.9,1.55 0.23,0 0.47,-0.08 0.68,-0.27l38.3,-34.49c0.7,-0.63 0.26,-1.79 -0.68,-1.79l-26.78,-0.17c-0.77,-0.01 -1.26,-0.82 -0.91,-1.5l10.36,-20.06c0.4,-0.79 -0.22,-1.53 -0.92,-1.53z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m103.18,36.62c-0.63,0 -1.24,0.05 -1.85,0.12 0.48,-1.61 0.74,-3.32 0.74,-5.08 0,-9.85 -7.99,-17.84 -17.84,-17.84 -4.19,0 -8.04,1.46 -11.09,3.88 -4.09,-7.78 -12.25,-13.08 -21.65,-13.08 -13.51,0 -24.46,10.95 -24.46,24.46 0,0.49 0.02,0.97 0.05,1.45 -10.19,1.24 -18.07,9.91 -18.07,20.43 0,11.26 9.03,20.4 20.24,20.59 3.76,6.52 11.23,10.99 19.88,11.06 8.36,0.06 15.69,-4.01 19.65,-10.13 3.19,3.49 7.78,5.7 12.88,5.7 7.31,0 13.57,-4.5 16.18,-10.88 1.67,0.6 3.47,0.95 5.34,0.95 8.74,0 15.82,-7.08 15.82,-15.82 -0.01,-8.73 -7.09,-15.81 -15.82,-15.81z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="59.36"
|
|
||||||
android:centerY="-4.66"
|
|
||||||
android:gradientRadius="110.91"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.26" android:color="#FFE3F2FD"/>
|
|
||||||
<item android:offset="0.92" android:color="#FF90CAF9"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m51.49,7.62c7.99,0 15.27,4.4 19,11.47 0.42,0.79 1.16,1.35 2.04,1.54 0.2,0.04 0.41,0.06 0.62,0.06 0.67,0 1.33,-0.23 1.87,-0.65 2.65,-2.11 5.84,-3.23 9.22,-3.23 8.18,0 14.84,6.66 14.84,14.84 0,1.42 -0.21,2.84 -0.62,4.23 -0.29,0.97 -0.07,2.01 0.58,2.78 0.57,0.68 1.42,1.07 2.3,1.07 0.12,0 0.23,-0.01 0.35,-0.02 0.56,-0.07 1.05,-0.1 1.5,-0.1 7.07,0 12.82,5.75 12.82,12.82s-5.75,12.82 -12.82,12.82c-1.45,0 -2.91,-0.26 -4.33,-0.77 -0.33,-0.12 -0.68,-0.18 -1.01,-0.18 -1.19,0 -2.3,0.71 -2.78,1.87 -2.23,5.47 -7.49,9.01 -13.4,9.01 -4.04,0 -7.93,-1.72 -10.68,-4.73 -0.57,-0.63 -1.38,-0.98 -2.22,-0.98 -0.08,0 -0.16,0 -0.25,0.01 -0.93,0.08 -1.77,0.77 -2.27,1.55 -3.51,5.42 -9.99,8.97 -16.93,8.97h-0.17c-7.31,0 -13.94,-3.91 -17.3,-9.76 -0.53,-0.91 -1.49,-1.58 -2.55,-1.6 -9.54,-0.16 -17.29,-8.1 -17.29,-17.63 0,-8.87 6.64,-16.4 15.44,-17.48 1.57,-0.19 2.72,-1.59 2.63,-3.17 -0.03,-0.48 -0.04,-0.9 -0.04,-1.29 -0.01,-11.82 9.62,-21.45 21.45,-21.45m0,-3c-13.51,0 -24.46,10.95 -24.46,24.46 0,0.49 0.02,0.98 0.05,1.46 -10.18,1.24 -18.07,9.91 -18.07,20.42 0,11.26 9.03,20.58 20.24,20.77 3.75,6.53 11.23,11.27 19.88,11.27h0.19c8.28,0 15.51,-4.26 19.45,-10.33 3.2,3.5 7.78,5.61 12.89,5.61 7.31,0 13.57,-4.55 16.18,-10.93 1.67,0.6 3.47,0.92 5.34,0.92 8.74,0 15.82,-7.09 15.82,-15.83s-7.08,-15.82 -15.82,-15.82c-0.63,0 -1.24,0.04 -1.85,0.11 0.48,-1.61 0.74,-3.32 0.74,-5.08 0,-9.85 -7.99,-17.84 -17.84,-17.84 -4.19,0 -8.04,1.46 -11.09,3.88 -4.09,-7.77 -12.25,-13.07 -21.65,-13.07z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
</vector>
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="128dp"
|
|
||||||
android:height="128dp"
|
|
||||||
android:viewportWidth="128"
|
|
||||||
android:viewportHeight="128">
|
|
||||||
<path
|
|
||||||
android:pathData="m51.04,121.76 l13.8,-24.27c0.39,-0.68 -0.1,-1.53 -0.89,-1.54l-26.19,-0.1c-0.95,0 -1.39,-1.17 -0.68,-1.8l34.24,-30.28c0.85,-0.75 2.12,0.23 1.6,1.24l-10.37,20.07c-0.35,0.68 0.14,1.5 0.91,1.5l26.78,0.17c0.94,0.01 1.38,1.16 0.68,1.79l-38.3,34.49c-0.87,0.79 -2.16,-0.25 -1.58,-1.27z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:startX="59.01"
|
|
||||||
android:startY="73.87"
|
|
||||||
android:endX="71.67"
|
|
||||||
android:endY="118.12"
|
|
||||||
android:type="linear">
|
|
||||||
<item android:offset="0" android:color="#FFFBC02D"/>
|
|
||||||
<item android:offset="1" android:color="#FFFFEB3B"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m65.41,73.01 l-5.52,10.69c-0.65,1.25 -0.6,2.72 0.13,3.93s2.01,1.94 3.42,1.94l21.69,0.14 -25.47,22.93 7.78,-13.68c0.71,-1.24 0.7,-2.78 -0.02,-4.01 -0.71,-1.23 -2.05,-2 -3.47,-2.01l-21.01,-0.08zM71.99,63.51c-0.23,0 -0.46,0.08 -0.67,0.27l-34.24,30.28c-0.71,0.63 -0.27,1.8 0.68,1.8l26.19,0.1c0.79,0 1.28,0.85 0.89,1.54l-13.8,24.27c-0.44,0.77 0.19,1.55 0.9,1.55 0.23,0 0.47,-0.08 0.68,-0.27l38.3,-34.49c0.7,-0.63 0.26,-1.79 -0.68,-1.79l-26.78,-0.17c-0.77,-0.01 -1.26,-0.82 -0.91,-1.5l10.36,-20.06c0.4,-0.79 -0.22,-1.53 -0.92,-1.53z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m20.02,85.12c-1.44,3.13 -5.14,4.51 -8.28,3.07 -3.13,-1.44 -4.51,-5.14 -3.07,-8.28s10.8,-9.36 10.8,-9.36 1.99,11.43 0.55,14.57z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m23.71,107.43c-1.44,3.13 -5.14,4.51 -8.28,3.07 -3.13,-1.44 -4.51,-5.14 -3.07,-8.28 1.44,-3.13 10.8,-9.36 10.8,-9.36s1.99,11.43 0.55,14.57z"
|
|
||||||
android:fillColor="#90caf9"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m44.6,119.67c-1.44,3.13 -5.14,4.51 -8.28,3.07 -3.13,-1.44 -4.51,-5.14 -3.07,-8.28s10.8,-9.36 10.8,-9.36 1.99,11.43 0.55,14.57z"
|
|
||||||
android:fillColor="#90caf9"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m112.91,85.12c-1.44,3.13 -5.14,4.51 -8.28,3.07 -3.13,-1.44 -4.51,-5.14 -3.07,-8.28 1.44,-3.13 10.8,-9.36 10.8,-9.36s1.98,11.43 0.55,14.57z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m88.84,119.67c-1.44,3.13 -5.14,4.51 -8.28,3.07 -3.13,-1.44 -4.51,-5.14 -3.07,-8.28 1.44,-3.13 10.8,-9.36 10.8,-9.36s1.99,11.43 0.55,14.57z"
|
|
||||||
android:fillColor="#90caf9"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m116.01,107.46c-1.44,3.13 -5.14,4.51 -8.28,3.07 -3.13,-1.44 -4.51,-5.14 -3.07,-8.28 1.44,-3.13 10.8,-9.36 10.8,-9.36s1.99,11.44 0.55,14.57z"
|
|
||||||
android:fillColor="#90caf9"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m17.97,74.03c0.58,4.44 0.81,8.97 0.23,10.25 -0.69,1.5 -2.21,2.48 -3.86,2.48 -0.61,0 -1.2,-0.13 -1.77,-0.39 -1.03,-0.47 -1.81,-1.32 -2.21,-2.38 -0.39,-1.06 -0.35,-2.22 0.12,-3.25 0.65,-1.41 4.21,-4.33 7.49,-6.71m1.5,-3.47s-9.36,6.22 -10.8,9.36c-1.44,3.13 -0.06,6.84 3.07,8.28 0.84,0.39 1.73,0.57 2.6,0.57 2.37,0 4.63,-1.35 5.68,-3.64 1.44,-3.15 -0.55,-14.57 -0.55,-14.57z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m21.66,96.34c0.58,4.44 0.81,8.97 0.23,10.25 -0.69,1.5 -2.21,2.48 -3.86,2.48 -0.61,0 -1.2,-0.13 -1.77,-0.39 -2.13,-0.98 -3.06,-3.5 -2.09,-5.63 0.65,-1.41 4.21,-4.33 7.49,-6.71m1.5,-3.48s-9.36,6.22 -10.8,9.36c-1.44,3.13 -0.06,6.84 3.07,8.28 0.84,0.39 1.73,0.57 2.6,0.57 2.37,0 4.63,-1.35 5.68,-3.64 1.44,-3.14 -0.55,-14.57 -0.55,-14.57z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m42.56,108.58c0.58,4.44 0.81,8.98 0.23,10.25 -0.69,1.5 -2.21,2.48 -3.86,2.48 -0.61,0 -1.2,-0.13 -1.77,-0.39 -1.03,-0.47 -1.81,-1.32 -2.21,-2.38 -0.39,-1.06 -0.35,-2.22 0.12,-3.25 0.65,-1.41 4.2,-4.33 7.49,-6.71m1.49,-3.48s-9.36,6.22 -10.8,9.36 -0.06,6.84 3.07,8.28c0.84,0.39 1.73,0.57 2.6,0.57 2.37,0 4.63,-1.35 5.68,-3.64 1.44,-3.14 -0.55,-14.57 -0.55,-14.57z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m110.86,74.03c0.58,4.44 0.81,8.97 0.23,10.25 -0.69,1.5 -2.21,2.48 -3.86,2.48 -0.61,0 -1.2,-0.13 -1.77,-0.39 -1.03,-0.47 -1.81,-1.32 -2.21,-2.38 -0.39,-1.06 -0.35,-2.22 0.12,-3.25 0.65,-1.41 4.21,-4.33 7.49,-6.71m1.5,-3.47s-9.36,6.22 -10.8,9.36c-1.44,3.13 -0.06,6.84 3.07,8.28 0.84,0.39 1.73,0.57 2.6,0.57 2.37,0 4.63,-1.35 5.68,-3.64 1.43,-3.15 -0.55,-14.57 -0.55,-14.57z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m86.79,108.58c0.58,4.44 0.81,8.97 0.23,10.25 -0.69,1.5 -2.21,2.48 -3.86,2.48 -0.61,0 -1.2,-0.13 -1.77,-0.39 -1.03,-0.47 -1.81,-1.32 -2.21,-2.38 -0.39,-1.06 -0.35,-2.22 0.12,-3.25 0.65,-1.41 4.21,-4.33 7.49,-6.71m1.5,-3.48s-9.36,6.22 -10.8,9.36c-1.44,3.13 -0.06,6.84 3.07,8.28 0.84,0.39 1.73,0.57 2.6,0.57 2.37,0 4.63,-1.35 5.68,-3.64 1.44,-3.14 -0.55,-14.57 -0.55,-14.57z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m113.96,96.37c0.58,4.44 0.81,8.98 0.23,10.25 -0.69,1.5 -2.21,2.48 -3.86,2.48 -0.61,0 -1.2,-0.13 -1.77,-0.39 -2.13,-0.98 -3.06,-3.5 -2.09,-5.63 0.65,-1.4 4.21,-4.33 7.49,-6.71m1.5,-3.47s-9.36,6.22 -10.8,9.36c-1.44,3.13 -0.06,6.84 3.07,8.28 0.84,0.39 1.73,0.57 2.6,0.57 2.37,0 4.63,-1.35 5.68,-3.64 1.44,-3.14 -0.55,-14.57 -0.55,-14.57z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m103.18,36.62c-0.63,0 -1.24,0.05 -1.85,0.12 0.48,-1.61 0.74,-3.32 0.74,-5.08 0,-9.85 -7.99,-17.84 -17.84,-17.84 -4.19,0 -8.04,1.46 -11.09,3.88 -4.09,-7.78 -12.25,-13.08 -21.65,-13.08 -13.51,0 -24.46,10.95 -24.46,24.46 0,0.49 0.02,0.97 0.05,1.45 -10.19,1.24 -18.07,9.91 -18.07,20.43 0,11.26 9.03,20.4 20.24,20.59 3.76,6.52 11.23,10.99 19.88,11.06 8.36,0.06 15.69,-4.01 19.65,-10.13 3.19,3.49 7.78,5.7 12.88,5.7 7.31,0 13.57,-4.5 16.18,-10.88 1.67,0.6 3.47,0.95 5.34,0.95 8.74,0 15.82,-7.08 15.82,-15.82 -0.01,-8.73 -7.09,-15.81 -15.82,-15.81z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="59.36"
|
|
||||||
android:centerY="-4.66"
|
|
||||||
android:gradientRadius="110.91"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.26" android:color="#FFE3F2FD"/>
|
|
||||||
<item android:offset="0.92" android:color="#FF90CAF9"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m51.49,7.62c7.99,0 15.27,4.4 19,11.47 0.42,0.79 1.16,1.35 2.04,1.54 0.2,0.04 0.41,0.06 0.62,0.06 0.67,0 1.33,-0.23 1.87,-0.65 2.65,-2.11 5.84,-3.23 9.22,-3.23 8.18,0 14.84,6.66 14.84,14.84 0,1.42 -0.21,2.84 -0.62,4.23 -0.29,0.97 -0.07,2.01 0.58,2.78 0.57,0.68 1.42,1.07 2.3,1.07 0.12,0 0.23,-0.01 0.35,-0.02 0.56,-0.07 1.05,-0.1 1.5,-0.1 7.07,0 12.82,5.75 12.82,12.82s-5.75,12.82 -12.82,12.82c-1.45,0 -2.91,-0.26 -4.33,-0.77 -0.33,-0.12 -0.68,-0.18 -1.01,-0.18 -1.19,0 -2.3,0.71 -2.78,1.87 -2.23,5.47 -7.49,9.01 -13.4,9.01 -4.04,0 -7.93,-1.72 -10.68,-4.73 -0.57,-0.63 -1.38,-0.98 -2.22,-0.98 -0.08,0 -0.16,0 -0.25,0.01 -0.93,0.08 -1.77,0.77 -2.27,1.55 -3.51,5.42 -9.99,8.97 -16.93,8.97h-0.17c-7.31,0 -13.94,-3.91 -17.3,-9.76 -0.53,-0.91 -1.49,-1.58 -2.55,-1.6 -9.54,-0.16 -17.29,-8.1 -17.29,-17.63 0,-8.87 6.64,-16.4 15.44,-17.48 1.57,-0.19 2.72,-1.59 2.63,-3.17 -0.03,-0.48 -0.04,-0.9 -0.04,-1.29 -0.01,-11.82 9.62,-21.45 21.45,-21.45m0,-3c-13.51,0 -24.46,10.95 -24.46,24.46 0,0.49 0.02,0.98 0.05,1.46 -10.18,1.24 -18.07,9.91 -18.07,20.42 0,11.26 9.03,20.58 20.24,20.77 3.75,6.53 11.23,11.27 19.88,11.27h0.19c8.28,0 15.51,-4.26 19.45,-10.33 3.2,3.5 7.78,5.61 12.89,5.61 7.31,0 13.57,-4.55 16.18,-10.93 1.67,0.6 3.47,0.92 5.34,0.92 8.74,0 15.82,-7.09 15.82,-15.83s-7.08,-15.82 -15.82,-15.82c-0.63,0 -1.24,0.04 -1.85,0.11 0.48,-1.61 0.74,-3.32 0.74,-5.08 0,-9.85 -7.99,-17.84 -17.84,-17.84 -4.19,0 -8.04,1.46 -11.09,3.88 -4.09,-7.77 -12.25,-13.07 -21.65,-13.07z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
</vector>
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="128dp"
|
|
||||||
android:height="128dp"
|
|
||||||
android:viewportWidth="128"
|
|
||||||
android:viewportHeight="128">
|
|
||||||
<path
|
|
||||||
android:pathData="m106.97,39.56c-0.68,0 -1.35,0.05 -2,0.13 0.52,-1.75 0.81,-3.59 0.81,-5.51 0,-10.68 -8.66,-19.34 -19.34,-19.34 -4.55,0 -8.72,1.58 -12.02,4.21 -4.45,-8.43 -13.29,-14.18 -23.48,-14.18 -14.64,0 -26.52,11.87 -26.52,26.52 0,0.53 0.02,1.05 0.05,1.57 -11.03,1.35 -19.58,10.75 -19.58,22.15 0,12.2 9.79,22.11 21.94,22.32 4.07,7.07 12.18,11.92 21.55,11.99 9.06,0.07 17,-4.35 21.3,-10.98 3.46,3.79 8.43,6.18 13.96,6.18 7.93,0 14.71,-4.88 17.53,-11.79 1.81,0.65 3.76,1.02 5.79,1.02 9.47,0 17.15,-7.68 17.15,-17.15 0,-9.46 -7.68,-17.14 -17.14,-17.14z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="59.47"
|
|
||||||
android:centerY="-5.18"
|
|
||||||
android:gradientRadius="120.22"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.26" android:color="#FFE3F2FD"/>
|
|
||||||
<item android:offset="0.92" android:color="#FF90CAF9"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m50.94,7.87c8.75,0 16.73,4.82 20.81,12.57 0.42,0.79 1.16,1.35 2.04,1.54 0.2,0.04 0.41,0.06 0.62,0.06 0.67,0 1.33,-0.23 1.87,-0.65 2.92,-2.32 6.43,-3.55 10.15,-3.55 9.01,0 16.34,7.33 16.34,16.34 0,1.56 -0.23,3.13 -0.68,4.66 -0.29,0.97 -0.07,2.01 0.58,2.78 0.57,0.68 1.42,1.07 2.3,1.07 0.12,0 0.23,-0.01 0.35,-0.02 0.62,-0.07 1.16,-0.11 1.66,-0.11 7.8,0 14.15,6.35 14.15,14.15s-6.35,14.15 -14.15,14.15c-1.61,0 -3.21,-0.29 -4.78,-0.85 -0.33,-0.12 -0.68,-0.18 -1.01,-0.18 -1.19,0 -2.3,0.71 -2.78,1.87 -2.46,6.03 -8.25,9.92 -14.76,9.92 -4.45,0 -8.74,-1.9 -11.76,-5.21 -0.57,-0.63 -1.38,-0.98 -2.22,-0.98 -0.08,0 -0.16,0 -0.25,0.01 -0.93,0.08 -1.77,0.37 -2.27,1.15 -3.85,5.93 -10.96,9.41 -18.56,9.41h-0.19c-8.01,0 -15.28,-3.87 -18.97,-10.28 -0.53,-0.91 -1.49,-1.38 -2.55,-1.4 -10.47,-0.18 -18.99,-8.79 -18.99,-19.26 0,-9.74 7.29,-17.95 16.95,-19.14 1.57,-0.19 2.72,-1.56 2.63,-3.14 -0.03,-0.52 -0.05,-0.98 -0.05,-1.4 0.01,-12.96 10.56,-23.51 23.52,-23.51m0,-3c-14.64,0 -26.52,11.87 -26.52,26.52 0,0.53 0.02,1.06 0.05,1.58 -11.03,1.35 -19.58,10.74 -19.58,22.14 0,12.2 9.79,21.89 21.94,22.1 4.07,7.07 12.17,11.79 21.55,11.79h0.21c8.98,0 16.82,-4.2 21.08,-10.78 3.46,3.79 8.43,6.29 13.98,6.29 7.93,0 14.71,-4.82 17.53,-11.74 1.81,0.65 3.76,1.05 5.79,1.05 9.47,0 17.15,-7.66 17.15,-17.13s-7.68,-17.14 -17.15,-17.14c-0.68,0 -1.35,0.05 -2,0.13 0.52,-1.75 0.81,-3.59 0.81,-5.51 0,-10.68 -8.66,-19.34 -19.34,-19.34 -4.55,0 -8.72,1.58 -12.02,4.21 -4.45,-8.42 -13.29,-14.17 -23.48,-14.17z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m97.36,119.15c-1.78,3.88 -6.36,5.58 -10.24,3.8s-5.58,-6.36 -3.8,-10.24 13.36,-11.57 13.36,-11.57 2.46,14.13 0.68,18.01z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m97.36,119.15c-1.78,3.88 -6.36,5.58 -10.24,3.8s-5.58,-6.36 -3.8,-10.24 13.36,-11.57 13.36,-11.57 2.46,14.13 0.68,18.01z"
|
|
||||||
android:fillColor="#90caf9"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m25.59,96.63c-1.78,3.88 -6.36,5.58 -10.24,3.8s-5.58,-6.36 -3.8,-10.24 13.36,-11.57 13.36,-11.57 2.46,14.13 0.68,18.01z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m23.42,82.08c0.74,5.36 1.22,11.83 0.35,13.72 -0.93,2.03 -2.97,3.34 -5.21,3.34 -0.82,0 -1.62,-0.18 -2.38,-0.52 -1.39,-0.64 -2.45,-1.78 -2.98,-3.21s-0.47,-2.99 0.16,-4.38c0.89,-1.91 5.79,-5.9 10.06,-8.95m1.49,-3.46s-11.58,7.7 -13.36,11.57c-1.78,3.88 -0.08,8.46 3.8,10.24 1.04,0.48 2.14,0.71 3.21,0.71 2.93,0 5.72,-1.67 7.02,-4.5 1.79,-3.89 -0.67,-18.02 -0.67,-18.02z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m39.66,119.15c-1.78,3.88 -6.36,5.58 -10.24,3.8s-5.58,-6.36 -3.8,-10.24 13.36,-11.57 13.36,-11.57 2.46,14.13 0.68,18.01z"
|
|
||||||
android:fillColor="#90caf9"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m37.5,104.59c0.74,5.36 1.22,11.83 0.35,13.72 -0.93,2.03 -2.97,3.34 -5.21,3.34 -0.82,0 -1.62,-0.18 -2.38,-0.52 -2.87,-1.32 -4.13,-4.72 -2.82,-7.59 0.88,-1.91 5.78,-5.89 10.06,-8.95m1.48,-3.45s-11.58,7.7 -13.36,11.57c-1.78,3.88 -0.08,8.46 3.8,10.24 1.04,0.48 2.14,0.71 3.21,0.71 2.93,0 5.72,-1.67 7.02,-4.5 1.79,-3.89 -0.67,-18.02 -0.67,-18.02z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m69.22,107.89c-1.78,3.88 -6.36,5.58 -10.24,3.8s-5.58,-6.36 -3.8,-10.24 13.36,-11.57 13.36,-11.57 2.46,14.13 0.68,18.01z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m67.05,93.33c0.74,5.36 1.22,11.83 0.35,13.72 -0.93,2.03 -2.97,3.34 -5.21,3.34 -0.82,0 -1.62,-0.18 -2.38,-0.52 -2.87,-1.32 -4.13,-4.72 -2.82,-7.59 0.88,-1.91 5.78,-5.89 10.06,-8.95m1.49,-3.45s-11.58,7.7 -13.36,11.57c-1.78,3.88 -0.08,8.46 3.8,10.24 1.04,0.48 2.14,0.71 3.22,0.71 2.93,0 5.72,-1.67 7.02,-4.5 1.78,-3.89 -0.68,-18.02 -0.68,-18.02z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m115.66,96.63c-1.78,3.88 -6.36,5.58 -10.24,3.8s-5.58,-6.36 -3.8,-10.24 13.36,-11.57 13.36,-11.57 2.46,14.13 0.68,18.01z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m113.49,82.08c0.74,5.36 1.22,11.83 0.35,13.72 -0.93,2.03 -2.97,3.34 -5.21,3.34 -0.82,0 -1.62,-0.18 -2.38,-0.52 -2.87,-1.32 -4.13,-4.72 -2.82,-7.59 0.88,-1.91 5.78,-5.9 10.06,-8.95m1.49,-3.46s-11.58,7.7 -13.36,11.57c-1.78,3.88 -0.08,8.46 3.8,10.24 1.04,0.48 2.14,0.71 3.21,0.71 2.93,0 5.72,-1.67 7.02,-4.5 1.79,-3.89 -0.67,-18.02 -0.67,-18.02z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m95.2,104.59c0.74,5.36 1.22,11.83 0.35,13.72 -0.93,2.03 -2.97,3.34 -5.21,3.34 -0.82,0 -1.62,-0.18 -2.38,-0.52 -1.39,-0.64 -2.45,-1.78 -2.98,-3.21s-0.47,-2.99 0.16,-4.38c0.88,-1.91 5.78,-5.89 10.06,-8.95m1.48,-3.45s-11.58,7.7 -13.36,11.57c-1.78,3.88 -0.08,8.46 3.8,10.24 1.04,0.48 2.14,0.71 3.21,0.71 2.93,0 5.72,-1.67 7.02,-4.5 1.79,-3.89 -0.67,-18.02 -0.67,-18.02z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m95.2,104.59c0.74,5.36 1.22,11.83 0.35,13.72 -0.93,2.03 -2.97,3.34 -5.21,3.34 -0.82,0 -1.62,-0.18 -2.38,-0.52 -1.39,-0.64 -2.45,-1.78 -2.98,-3.21s-0.47,-2.99 0.16,-4.38c0.88,-1.91 5.78,-5.89 10.06,-8.95m1.48,-3.45s-11.58,7.7 -13.36,11.57c-1.78,3.88 -0.08,8.46 3.8,10.24 1.04,0.48 2.14,0.71 3.21,0.71 2.93,0 5.72,-1.67 7.02,-4.5 1.79,-3.89 -0.67,-18.02 -0.67,-18.02z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
</vector>
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="128dp"
|
|
||||||
android:height="128dp"
|
|
||||||
android:viewportWidth="128"
|
|
||||||
android:viewportHeight="128">
|
|
||||||
<path
|
|
||||||
android:pathData="m106.97,37.87c-0.68,0 -1.35,0.05 -2,0.12 0.52,-1.71 0.81,-3.51 0.81,-5.38 0,-10.43 -8.66,-18.88 -19.34,-18.88 -4.55,0 -8.72,1.54 -12.02,4.11 -4.45,-8.23 -13.29,-13.84 -23.48,-13.84 -14.64,0 -26.51,11.59 -26.51,25.89 0,0.51 0.02,1.02 0.05,1.53 -11.04,1.32 -19.59,10.5 -19.59,21.63 0,11.91 9.79,21.59 21.94,21.79 4.07,6.9 12.18,11.63 21.55,11.7 9.06,0.07 17,-4.25 21.3,-10.72 3.46,3.7 8.43,6.03 13.96,6.03 7.93,0 14.71,-4.76 17.53,-11.51 1.81,0.64 3.76,1 5.79,1 9.47,0 17.15,-7.49 17.15,-16.74 0,-9.24 -7.68,-16.73 -17.14,-16.73z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="59.47"
|
|
||||||
android:centerY="-5.81"
|
|
||||||
android:gradientRadius="120.22"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.26" android:color="#FFE3F2FD"/>
|
|
||||||
<item android:offset="0.92" android:color="#FF90CAF9"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m50.94,7c8.76,0 16.74,4.7 20.83,12.26 0.42,0.78 1.16,1.33 2.02,1.51 0.21,0.04 0.41,0.06 0.62,0.06 0.66,0 1.31,-0.22 1.84,-0.63 2.93,-2.27 6.45,-3.48 10.18,-3.48 9.01,0 16.34,7.12 16.34,15.88 0,1.51 -0.23,3.03 -0.68,4.51 -0.29,0.97 -0.08,2.02 0.56,2.79 0.57,0.69 1.42,1.08 2.3,1.08 0.11,0 0.23,-0.01 0.34,-0.02 0.62,-0.07 1.16,-0.1 1.66,-0.1 7.8,0 14.15,6.16 14.15,13.74s-6.35,13.74 -14.15,13.74c-1.61,0 -3.23,-0.28 -4.8,-0.83 -0.33,-0.12 -0.66,-0.17 -0.99,-0.17 -1.18,0 -2.29,0.7 -2.77,1.84 -2.46,5.87 -8.25,9.67 -14.77,9.67 -4.46,0 -8.76,-1.86 -11.78,-5.09 -0.57,-0.61 -1.36,-0.95 -2.19,-0.95 -0.08,0 -0.17,0 -0.25,0.01 -0.91,0.08 -1.74,0.79 -2.25,1.56 -3.83,5.8 -10.95,9.62 -18.56,9.62h-0.19c-8.02,-1 -15.3,-4.21 -18.99,-10.46 -0.53,-0.9 -1.49,-1.57 -2.53,-1.59 -10.47,-0.18 -18.99,-8.66 -18.99,-18.84 0,-9.47 7.29,-17.51 16.95,-18.67 1.58,-0.19 2.73,-1.59 2.64,-3.17 -0.03,-0.51 -0.05,-0.96 -0.05,-1.37 0,-12.63 10.55,-22.9 23.51,-22.9m0,-3c-14.64,0 -26.51,11.59 -26.51,25.89 0,0.52 0.02,1.03 0.05,1.54 -11.04,1.32 -19.59,10.49 -19.59,21.62 0,11.91 9.79,21.8 21.94,22.01 4.07,6.9 12.17,10.94 21.55,11.94h0.21c8.98,0 16.82,-4.53 21.08,-10.96 3.46,3.7 8.43,5.93 13.98,5.93 7.93,0 14.71,-4.82 17.53,-11.57 1.81,0.64 3.76,0.97 5.79,0.97 9.47,0 17.15,-7.51 17.15,-16.75s-7.68,-16.75 -17.15,-16.75c-0.68,0 -1.35,0.05 -2,0.12 0.52,-1.71 0.81,-3.51 0.81,-5.38 0,-10.43 -8.66,-18.88 -19.34,-18.88 -4.55,0 -8.72,1.54 -12.02,4.11 -4.45,-8.23 -13.29,-13.84 -23.48,-13.84z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m21.61,104.5 l-0.63,0.02c-0.83,0.03 -1.52,-0.62 -1.55,-1.45l-0.67,-21.17c-0.03,-0.83 0.62,-1.52 1.45,-1.55l0.63,-0.02c0.83,-0.03 1.52,0.62 1.55,1.45l0.68,21.17c0.02,0.83 -0.63,1.52 -1.46,1.55z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m30.95,95.56 l-6.15,-3.26 5.93,-3.64c0.87,-0.53 1.17,-1.73 0.67,-2.67s-1.61,-1.28 -2.48,-0.74l-8.09,4.97 -8.39,-4.44c-0.9,-0.48 -1.99,-0.07 -2.42,0.9 -0.44,0.97 -0.06,2.15 0.84,2.63l6.16,3.25 -5.93,3.64c-0.87,0.53 -1.17,1.73 -0.67,2.67s1.61,1.28 2.48,0.74l8.09,-4.97 8.39,4.44c0.9,0.48 1.99,0.07 2.42,-0.9s0.05,-2.15 -0.85,-2.62z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m97.88,82.66 l0.36,-0.51c0.48,-0.67 1.42,-0.83 2.09,-0.35l17.25,12.29c0.67,0.48 0.83,1.42 0.35,2.09l-0.36,0.51c-0.48,0.67 -1.42,0.83 -2.09,0.35l-17.25,-12.28c-0.67,-0.49 -0.83,-1.42 -0.35,-2.1z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m99.33,95.51 l6.32,-2.92 -0.7,6.93c-0.1,1.01 0.67,1.98 1.72,2.16s1.99,-0.5 2.09,-1.52l0.95,-9.44 8.62,-3.98c0.93,-0.43 1.26,-1.53 0.75,-2.47s-1.67,-1.35 -2.6,-0.92l-6.32,2.92 0.7,-6.93c0.1,-1.02 -0.67,-1.98 -1.72,-2.16s-1.99,0.5 -2.09,1.52l-0.95,9.44 -8.62,3.98c-0.93,0.43 -1.26,1.53 -0.75,2.47s1.68,1.35 2.6,0.92z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m62.17,112.31 l-0.61,-0.13c-0.81,-0.17 -1.33,-0.97 -1.15,-1.78l4.46,-20.71c0.17,-0.81 0.97,-1.33 1.78,-1.15l0.61,0.13c0.81,0.17 1.33,0.97 1.15,1.78l-4.46,20.71c-0.17,0.81 -0.97,1.33 -1.78,1.15z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m73.4,105.89 l-5.19,-4.65 6.64,-2.1c0.97,-0.31 1.55,-1.4 1.3,-2.43 -0.26,-1.04 -1.25,-1.63 -2.22,-1.32l-9.05,2.86 -7.07,-6.33c-0.76,-0.68 -1.91,-0.55 -2.57,0.29s-0.58,2.07 0.18,2.75l5.19,4.65 -6.64,2.1c-0.97,0.31 -1.55,1.4 -1.3,2.43 0.25,1.04 1.25,1.63 2.22,1.32l9.05,-2.86 7.07,6.33c0.76,0.68 1.91,0.55 2.57,-0.29s0.58,-2.07 -0.18,-2.75z"
|
|
||||||
android:fillColor="#64b5f6"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m32.23,117.52c-0.45,-0.45 -0.45,-1.18 0,-1.63l9.23,-9.23c0.45,-0.45 1.18,-0.45 1.63,0s0.45,1.18 0,1.63l-9.23,9.23c-0.45,0.45 -1.18,0.45 -1.63,0z"
|
|
||||||
android:fillColor="#90caf9"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m40.57,118.1 l-1.17,-4.27 4.27,1.17c0.62,0.17 1.31,-0.21 1.53,-0.85s-0.11,-1.3 -0.73,-1.47l-5.82,-1.59 -1.59,-5.82c-0.17,-0.62 -0.83,-0.95 -1.47,-0.73s-1.02,0.91 -0.85,1.53l1.17,4.27 -4.27,-1.17c-0.62,-0.17 -1.31,0.21 -1.53,0.85s0.11,1.3 0.73,1.47l5.82,1.59 1.59,5.82c0.17,0.62 0.83,0.95 1.47,0.73s1.02,-0.9 0.85,-1.53z"
|
|
||||||
android:fillColor="#90caf9"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m88.94,117.06c-0.58,-0.27 -0.83,-0.95 -0.56,-1.53l5.48,-11.85c0.27,-0.58 0.95,-0.83 1.53,-0.56s0.83,0.95 0.56,1.53l-5.48,11.85c-0.27,0.58 -0.95,0.83 -1.53,0.56z"
|
|
||||||
android:fillColor="#90caf9"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m96.97,114.73 l-2.57,-3.6 4.41,-0.38c0.65,-0.06 1.16,-0.65 1.14,-1.33 -0.01,-0.68 -0.55,-1.18 -1.19,-1.13l-6.01,0.52 -3.5,-4.91c-0.38,-0.53 -1.11,-0.61 -1.63,-0.18s-0.65,1.2 -0.27,1.73l2.57,3.6 -4.41,0.38c-0.65,0.06 -1.16,0.65 -1.14,1.33 0.01,0.68 0.55,1.18 1.19,1.13l6.01,-0.52 3.5,4.91c0.38,0.53 1.11,0.61 1.63,0.18s0.64,-1.21 0.27,-1.73z"
|
|
||||||
android:fillColor="#90caf9"/>
|
|
||||||
</vector>
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="128dp"
|
|
||||||
android:height="128dp"
|
|
||||||
android:viewportWidth="128"
|
|
||||||
android:viewportHeight="128">
|
|
||||||
<path
|
|
||||||
android:pathData="m89.47,28.93c-2.46,-9.66 -7.29,-18.09 -13.69,-24.84 20.75,5.42 38.01,21.66 43.67,43.91 8.29,32.59 -11.41,65.72 -43.99,74.01 -27.79,7.07 -55.96,-6.22 -68.8,-30.49 12.29,7.12 27.26,9.64 42.12,5.86 30.14,-7.65 48.36,-38.31 40.69,-68.45z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="67.56"
|
|
||||||
android:centerY="24.47"
|
|
||||||
android:gradientRadius="96.59"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.28" android:color="#FFFFF157"/>
|
|
||||||
<item android:offset="0.52" android:color="#FFFEEE54"/>
|
|
||||||
<item android:offset="0.72" android:color="#FFFAE44A"/>
|
|
||||||
<item android:offset="0.9" android:color="#FFF4D538"/>
|
|
||||||
<item android:offset="1" android:color="#FFF0C92C"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m91.78,80.3c0.61,6.13 6.41,10.57 12.96,9.92 6.54,-0.65 11.35,-6.15 10.74,-12.28s-6.41,-10.57 -12.96,-9.92c-6.54,0.65 -11.35,6.15 -10.74,12.28z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="103.31"
|
|
||||||
android:centerY="75.44"
|
|
||||||
android:gradientRadius="14.31"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.01" android:color="#FFE0A800"/>
|
|
||||||
<item android:offset="0.61" android:color="#1BE0A800"/>
|
|
||||||
<item android:offset="0.68" android:color="#00E0A800"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m89.42,103.89c1.77,3.82 6.29,5.48 10.09,3.72 3.8,-1.77 5.44,-6.29 3.67,-10.11s-6.29,-5.48 -10.09,-3.72c-3.8,1.77 -5.44,6.3 -3.67,10.11z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="95.12"
|
|
||||||
android:centerY="92.32"
|
|
||||||
android:gradientRadius="13.45"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.01" android:color="#FFE0A800"/>
|
|
||||||
<item android:offset="0.61" android:color="#1BE0A800"/>
|
|
||||||
<item android:offset="0.68" android:color="#00E0A800"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m107.44,62.08c1.21,2.61 4.31,3.75 6.91,2.54s3.73,-4.31 2.51,-6.92c-1.21,-2.61 -4.31,-3.75 -6.91,-2.54 -2.6,1.2 -3.73,4.3 -2.51,6.92z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="111.34"
|
|
||||||
android:centerY="54.15"
|
|
||||||
android:gradientRadius="9.2"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.01" android:color="#FFE0A800"/>
|
|
||||||
<item android:offset="0.61" android:color="#1BE0A800"/>
|
|
||||||
<item android:offset="0.68" android:color="#00E0A800"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="M73.24,109.06m-8.97,0a8.97,8.97 0,1 1,17.94 0a8.97,8.97 0,1 1,-17.94 0">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="73.01"
|
|
||||||
android:centerY="105.52"
|
|
||||||
android:gradientRadius="15.24"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.01" android:color="#FFE0A800"/>
|
|
||||||
<item android:offset="0.61" android:color="#1BE0A800"/>
|
|
||||||
<item android:offset="0.68" android:color="#00E0A800"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m84.57,10.4c15.75,7.23 27.62,21.23 31.98,38.34 7.87,30.93 -10.89,62.5 -41.83,70.37 -4.7,1.19 -9.51,1.8 -14.31,1.8 -18.06,0 -34.78,-8.35 -45.62,-22.3 6.43,2.32 13.23,3.53 20.08,3.53 4.91,0 9.84,-0.62 14.65,-1.84 31.7,-8.06 50.93,-40.41 42.86,-72.11 -1.61,-6.33 -4.27,-12.35 -7.81,-17.79m-8.79,-6.31c6.41,6.75 11.23,15.18 13.69,24.84 7.67,30.14 -10.55,60.79 -40.69,68.46 -4.65,1.18 -9.32,1.75 -13.91,1.75 -10.06,0 -19.77,-2.72 -28.21,-7.61 10.51,19.87 31.31,32.38 53.75,32.38 4.97,0 10.01,-0.61 15.05,-1.89 32.59,-8.29 52.28,-41.43 43.99,-74.01 -5.66,-22.26 -22.92,-38.5 -43.67,-43.92z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
</vector>
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="128dp"
|
|
||||||
android:height="128dp"
|
|
||||||
android:viewportWidth="128"
|
|
||||||
android:viewportHeight="128">
|
|
||||||
<path
|
|
||||||
android:pathData="m64.6,124c-20.1,0 -35.56,-19.48 -35.56,-36.18 0,-11.75 5.26,-25.36 12.68,-44.22 0.93,-2.78 2.16,-5.57 3.4,-8.66 3.54,-8.84 6.66,-18.42 11.41,-26.71 3.24,-5.66 11.46,-5.65 14.58,0.08 4.43,8.14 7.45,16.96 12.05,27.25 12.99,29.07 16.7,40.82 16.7,52.57 0.3,16.39 -15.47,35.87 -35.26,35.87z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="67.14"
|
|
||||||
android:centerY="19.26"
|
|
||||||
android:gradientRadius="79.34"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.46" android:color="#FF29B6F6"/>
|
|
||||||
<item android:offset="1" android:color="#FF1E88E5"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m86.34,101.71c-4.55,7.02 -14.84,5.69 -14.84,-5.97 0,-7.45 1.52,-45.74 7.92,-40.39 10.41,8.72 13.38,36.43 6.92,46.36z"
|
|
||||||
android:fillColor="#81d4fa"/>
|
|
||||||
</vector>
|
|
||||||
BIN
app/src/main/res/drawable/droplet_regular.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
@ -1,43 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="128dp"
|
|
||||||
android:height="128dp"
|
|
||||||
android:viewportWidth="128"
|
|
||||||
android:viewportHeight="128">
|
|
||||||
<path
|
|
||||||
android:pathData="m81.56,35.12 l23.3,-13.38c1.48,-0.85 3.12,0.83 2.24,2.29l-13.86,23.01c-2.07,3.44 -0.28,7.91 3.6,8.95l25.94,7.01c1.65,0.45 1.62,2.79 -0.03,3.2l-26.08,6.47c-3.9,0.97 -5.79,5.4 -3.79,8.88l13.38,23.3c0.85,1.48 -0.83,3.12 -2.29,2.24l-23.01,-13.85c-3.44,-2.07 -7.91,-0.28 -8.95,3.6l-7.01,25.94c-0.45,1.65 -2.79,1.62 -3.2,-0.03l-6.47,-26.08c-0.97,-3.9 -5.4,-5.79 -8.88,-3.79l-23.3,13.38c-1.48,0.85 -3.12,-0.83 -2.24,-2.29l13.86,-23.02c2.07,-3.44 0.28,-7.91 -3.6,-8.95l-25.95,-7.01c-1.65,-0.45 -1.62,-2.79 0.03,-3.2l26.08,-6.47c3.9,-0.97 5.79,-5.4 3.79,-8.88l-13.38,-23.3c-0.85,-1.48 0.83,-3.12 2.29,-2.24l23.02,13.86c3.44,2.07 7.91,0.28 8.95,-3.6l7.01,-25.94c0.45,-1.65 2.79,-1.62 3.2,0.03l6.47,26.08c0.97,3.9 5.4,5.79 8.88,3.79z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="64.01"
|
|
||||||
android:centerY="64"
|
|
||||||
android:gradientRadius="55.57"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.39" android:color="#FFFF8F00"/>
|
|
||||||
<item android:offset="0.82" android:color="#FFFFB300"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="M64.07,63.97m-30.03,0a30.03,30.03 0,1 1,60.06 0a30.03,30.03 0,1 1,-60.06 0">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:centerX="64.07"
|
|
||||||
android:centerY="63.97"
|
|
||||||
android:gradientRadius="37.05"
|
|
||||||
android:type="radial">
|
|
||||||
<item android:offset="0.58" android:color="#FFFFEB3B"/>
|
|
||||||
<item android:offset="0.84" android:color="#FFFBC02D"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m64.11,35.99c3.74,0 7.4,0.74 10.87,2.21 14.21,6.01 20.88,22.47 14.87,36.68 -4.39,10.38 -14.52,17.08 -25.81,17.08 -3.74,0 -7.4,-0.74 -10.87,-2.21 -14.21,-6.02 -20.88,-22.47 -14.87,-36.69 4.39,-10.37 14.52,-17.07 25.81,-17.07m0,-2c-11.69,0 -22.82,6.88 -27.66,18.3 -6.44,15.23 0.7,32.86 15.93,39.3 3.8,1.61 7.75,2.37 11.65,2.37 11.69,0 22.82,-6.88 27.66,-18.3 6.44,-15.23 -0.7,-32.86 -15.93,-39.3 -3.8,-1.61 -7.76,-2.37 -11.65,-2.37z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#eee"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m64.55,11.02 l5.22,21.04c1,4.04 4.62,6.87 8.79,6.87 1.57,0 3.12,-0.42 4.5,-1.21l18.8,-10.8 -11.19,18.57c-1.48,2.45 -1.71,5.38 -0.64,8.04s3.27,4.61 6.03,5.36l20.92,5.66 -21.04,5.22c-2.78,0.69 -5.02,2.6 -6.14,5.23s-0.95,5.57 0.48,8.05l10.8,18.8 -18.57,-11.18c-1.41,-0.85 -3.02,-1.3 -4.66,-1.3 -4.08,0 -7.68,2.75 -8.74,6.69l-5.66,20.92 -5.22,-21.04c-1,-4.04 -4.62,-6.87 -8.79,-6.87 -1.57,0 -3.12,0.42 -4.5,1.21l-18.8,10.8 11.18,-18.57c1.48,-2.45 1.71,-5.38 0.64,-8.04s-3.27,-4.61 -6.03,-5.36l-20.92,-5.66 21.04,-5.22c2.78,-0.69 5.02,-2.6 6.14,-5.23s0.95,-5.57 -0.48,-8.05l-10.8,-18.8 18.57,11.18c1.41,0.85 3.02,1.3 4.66,1.3 4.08,0 7.68,-2.75 8.74,-6.69zM64.61,4c-0.69,0 -1.37,0.41 -1.59,1.22l-7.02,25.94c-0.75,2.76 -3.23,4.47 -5.85,4.47 -1.05,0 -2.12,-0.28 -3.11,-0.87l-23.02,-13.86c-0.28,-0.17 -0.58,-0.25 -0.86,-0.25 -1.16,0 -2.11,1.3 -1.43,2.49l13.38,23.3c2,3.48 0.11,7.91 -3.79,8.88l-26.07,6.47c-1.66,0.41 -1.68,2.75 -0.03,3.2l25.94,7.01c3.88,1.05 5.67,5.51 3.6,8.95l-13.86,23.03c-0.72,1.19 0.23,2.52 1.41,2.52 0.27,0 0.55,-0.07 0.83,-0.23l23.3,-13.38c0.96,-0.55 1.99,-0.81 3,-0.81 2.66,0 5.18,1.77 5.88,4.59l6.47,26.08c0.21,0.83 0.91,1.25 1.6,1.25s1.37,-0.41 1.59,-1.22l7.02,-25.94c0.75,-2.76 3.23,-4.47 5.85,-4.47 1.05,0 2.12,0.28 3.11,0.87l23.02,13.86c0.28,0.17 0.58,0.25 0.86,0.25 1.16,0 2.11,-1.3 1.43,-2.49l-13.38,-23.3c-2,-3.48 -0.11,-7.91 3.79,-8.88l26.08,-6.47c1.66,-0.41 1.68,-2.75 0.03,-3.2l-25.95,-7.01c-3.88,-1.05 -5.67,-5.51 -3.6,-8.95l13.86,-23.02c0.72,-1.19 -0.23,-2.52 -1.41,-2.52 -0.27,0 -0.55,0.07 -0.83,0.23l-23.3,13.38c-0.96,0.55 -1.99,0.81 -3,0.81 -2.66,0 -5.18,-1.77 -5.88,-4.59l-6.47,-26.09c-0.21,-0.83 -0.91,-1.25 -1.6,-1.25z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#eee"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
</vector>
|
|
||||||
BIN
app/src/main/res/drawable/thermometer.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
@ -1,38 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="128dp"
|
|
||||||
android:height="128dp"
|
|
||||||
android:viewportWidth="128"
|
|
||||||
android:viewportHeight="128">
|
|
||||||
<path
|
|
||||||
android:pathData="M76,80.34V16.29C76,9.77 70.82,4 64.3,4h-1.55C56.24,4 51,9.77 51,16.29v64.04c-7,4.2 -11.24,11.68 -11.24,20.2c0,13.14 10.64,23.8 23.79,23.8s23.74,-10.65 23.74,-23.8C87.28,92.01 83,84.54 76,80.34z"
|
|
||||||
android:fillColor="#E1F5FE"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m69.92,85.89v-62.07c0,-3.53 -2.86,-6.39 -6.39,-6.39s-6.39,2.86 -6.39,6.39v62.08c-5.82,2.54 -9.83,8.44 -9.58,15.25 0.3,8.19 6.99,14.96 15.18,15.36 9.19,0.44 16.78,-6.87 16.78,-15.96 -0.01,-6.57 -3.95,-12.19 -9.6,-14.66z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:startX="67.01"
|
|
||||||
android:startY="38.59"
|
|
||||||
android:endX="63.28"
|
|
||||||
android:endY="104.92"
|
|
||||||
android:type="linear">
|
|
||||||
<item android:offset="0.6" android:color="#FFEF5350"/>
|
|
||||||
<item android:offset="1" android:color="#FFE53935"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:pathData="m62.87,39.76h-11.92v-6.39h11.92c1.66,0 3,1.34 3,3v0.39c0,1.66 -1.34,3 -3,3z"
|
|
||||||
android:fillColor="#616161"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m62.87,58.32h-11.92v-6.39h11.92c1.66,0 3,1.34 3,3v0.39c0,1.65 -1.34,3 -3,3z"
|
|
||||||
android:fillColor="#616161"/>
|
|
||||||
<path
|
|
||||||
android:pathData="m62.87,76.88h-11.92v-6.39h11.92c1.66,0 3,1.34 3,3v0.39c0,1.65 -1.34,3 -3,3z"
|
|
||||||
android:fillColor="#616161"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M64.15,7C68.87,7 73,11.26 73,16.29v64.04c0,1.05 0.55,2.03 1.46,2.57c6.15,3.69 9.82,10.28 9.82,17.63c0,11.47 -9.3,20.8 -20.74,20.8c-11.46,0 -20.79,-9.33 -20.79,-20.8c0,-7.36 3.66,-13.95 9.79,-17.63c0.9,-0.54 1.46,-1.52 1.46,-2.57V16.29C54,11.26 58.01,7 62.76,7H64M64.3,4h-1.55C56.24,4 51,9.77 51,16.29v64.04c-7,4.2 -11.24,11.68 -11.24,20.2c0,13.14 10.64,23.8 23.79,23.8s23.74,-10.65 23.74,-23.8c0,-8.52 -4.28,-16 -11.28,-20.2V16.29C76,9.77 70.82,4 64.3,4L64.3,4z"
|
|
||||||
android:strokeAlpha="0.2"
|
|
||||||
android:fillColor="#424242"
|
|
||||||
android:fillAlpha="0.2"/>
|
|
||||||
</vector>
|
|
||||||
BIN
app/src/main/res/drawable/water_regular.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
@ -3,4 +3,6 @@ plugins {
|
|||||||
alias(libs.plugins.android.application) apply false
|
alias(libs.plugins.android.application) apply false
|
||||||
alias(libs.plugins.jetbrains.kotlin.android) apply false
|
alias(libs.plugins.jetbrains.kotlin.android) apply false
|
||||||
alias(libs.plugins.compose.compiler) apply false
|
alias(libs.plugins.compose.compiler) apply false
|
||||||
|
alias(libs.plugins.google.gms.google.services) apply false
|
||||||
|
alias(libs.plugins.google.firebase.crashlytics) apply false
|
||||||
}
|
}
|
||||||
@ -11,15 +11,20 @@ androidxComposeMaterial = "1.3.1"
|
|||||||
glance = "1.1.1"
|
glance = "1.1.1"
|
||||||
kotlinxSerializationJson = "1.8.0"
|
kotlinxSerializationJson = "1.8.0"
|
||||||
mapboxSdkTurf = "7.3.1"
|
mapboxSdkTurf = "7.3.1"
|
||||||
|
firebaseCrashlytics = "19.4.2"
|
||||||
|
googleGmsGoogleServices = "4.4.2"
|
||||||
|
googleFirebaseCrashlytics = "3.0.3"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||||
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||||
|
google-gms-google-services = { id = "com.google.gms.google-services", version.ref = "googleGmsGoogleServices" }
|
||||||
|
google-firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "googleFirebaseCrashlytics" }
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
|
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
|
||||||
hammerhead-karoo-ext = { group = "io.hammerhead", name = "karoo-ext", version = "1.1.5" }
|
hammerhead-karoo-ext = { group = "io.hammerhead", name = "karoo-ext", version = "1.1.3" }
|
||||||
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidxCore" }
|
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidxCore" }
|
||||||
|
|
||||||
# compose
|
# compose
|
||||||
@ -38,6 +43,7 @@ androidx-glance-appwidget-preview = { group = "androidx.glance", name = "glance-
|
|||||||
androidx-glance-preview = { group = "androidx.glance", name = "glance-preview", version.ref = "glance" }
|
androidx-glance-preview = { group = "androidx.glance", name = "glance-preview", version.ref = "glance" }
|
||||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||||
mapbox-sdk-turf = { module = "com.mapbox.mapboxsdk:mapbox-sdk-turf", version.ref = "mapboxSdkTurf" }
|
mapbox-sdk-turf = { module = "com.mapbox.mapboxsdk:mapbox-sdk-turf", version.ref = "mapboxSdkTurf" }
|
||||||
|
firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics", version.ref = "firebaseCrashlytics" }
|
||||||
|
|
||||||
[bundles]
|
[bundles]
|
||||||
androidx-lifeycle = ["androidx-lifecycle-runtime-compose", "androidx-lifecycle-viewmodel-compose"]
|
androidx-lifeycle = ["androidx-lifecycle-runtime-compose", "androidx-lifecycle-viewmodel-compose"]
|
||||||
|
|||||||