fix #7: Set units of measurement to karoo profile preferences on first load

This commit is contained in:
Tim Kluge 2024-12-13 17:56:20 +01:00
parent 8d30e62015
commit a4347511a5
7 changed files with 45 additions and 19 deletions

View File

@ -7,12 +7,15 @@ import androidx.datastore.preferences.core.stringPreferencesKey
import de.timklge.karooheadwind.datatypes.GpsCoordinates
import de.timklge.karooheadwind.screens.HeadwindSettings
import de.timklge.karooheadwind.screens.HeadwindStats
import de.timklge.karooheadwind.screens.PrecipitationUnit
import de.timklge.karooheadwind.screens.WindUnit
import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.DataType
import io.hammerhead.karooext.models.HttpResponseState
import io.hammerhead.karooext.models.OnHttpResponse
import io.hammerhead.karooext.models.OnStreamState
import io.hammerhead.karooext.models.StreamState
import io.hammerhead.karooext.models.UserProfile
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.channels.awaitClose
@ -24,6 +27,7 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
@ -86,12 +90,22 @@ fun Context.streamCurrentWeatherData(): Flow<OpenMeteoCurrentWeatherResponse> {
}.filterNotNull().distinctUntilChanged().filter { it.current.time * 1000 >= System.currentTimeMillis() - (1000 * 60 * 60 * 12) }
}
fun Context.streamSettings(): Flow<HeadwindSettings> {
fun Context.streamSettings(karooSystemService: KarooSystemService): Flow<HeadwindSettings> {
return dataStore.data.map { settingsJson ->
try {
jsonWithUnknownKeys.decodeFromString<HeadwindSettings>(
settingsJson[settingsKey] ?: HeadwindSettings.defaultSettings
)
if (settingsJson.contains(settingsKey)){
jsonWithUnknownKeys.decodeFromString<HeadwindSettings>(settingsJson[settingsKey]!!)
} else {
val defaultSettings = jsonWithUnknownKeys.decodeFromString<HeadwindSettings>(HeadwindSettings.defaultSettings)
val preferredUnits = karooSystemService.streamUserProfile().first().preferredUnit
val preferredMetric = preferredUnits.distance == UserProfile.PreferredUnit.UnitType.METRIC
defaultSettings.copy(
windUnit = if (preferredMetric) WindUnit.KILOMETERS_PER_HOUR else WindUnit.MILES_PER_HOUR,
precipitationUnit = if (preferredMetric) PrecipitationUnit.MILLIMETERS else PrecipitationUnit.INCH
)
}
} catch(e: Throwable){
Log.e(KarooHeadwindExtension.TAG, "Failed to read preferences", e)
jsonWithUnknownKeys.decodeFromString<HeadwindSettings>(HeadwindSettings.defaultSettings)
@ -112,6 +126,17 @@ fun Context.streamStats(): Flow<HeadwindStats> {
}.distinctUntilChanged()
}
fun KarooSystemService.streamUserProfile(): Flow<UserProfile> {
return callbackFlow {
val listenerId = addConsumer { userProfile: UserProfile ->
trySendBlocking(userProfile)
}
awaitClose {
removeConsumer(listenerId)
}
}
}
@OptIn(FlowPreview::class)
suspend fun KarooSystemService.makeOpenMeteoHttpRequest(gpsCoordinates: GpsCoordinates, settings: HeadwindSettings): HttpResponseState.Complete {
return callbackFlow {

View File

@ -75,7 +75,7 @@ class KarooHeadwindExtension : KarooExtension("karoo-headwind", "1.0.0-beta2") {
}
}
streamSettings()
streamSettings(karooSystem)
.filter { it.welcomeDialogAccepted }
.combine(gpsFlow) { settings, gps -> settings to gps }
.map { (settings, gps) ->

View File

@ -72,7 +72,7 @@ class HeadwindDirectionDataType(
karooSystem.streamDataFlow(dataTypeId)
.mapNotNull { (it as? StreamState.Streaming)?.dataPoint?.singleValue }
.combine(context.streamCurrentWeatherData()) { value, data -> value to data }
.combine(context.streamSettings()) { (value, data), settings -> StreamData(value, data, settings) }
.combine(context.streamSettings(karooSystem)) { (value, data), settings -> StreamData(value, data, settings) }
.onCompletion {
// Clear view on completion
val result = glance.compose(context, DpSize.Unspecified) { }
@ -83,7 +83,7 @@ class HeadwindDirectionDataType(
val windSpeed = streamData.data.current.windSpeed
val windDirection = streamData.value
val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed
val windSpeedText = "${headwindSpeed.roundToInt()}"
val windSpeedText = headwindSpeed.roundToInt().toString()
val result = glance.compose(context, DpSize.Unspecified) {
HeadwindDirection(baseBitmap, windDirection.roundToInt(), config.textSize, windSpeedText)

View File

@ -28,7 +28,7 @@ class HeadwindSpeedDataType(
val job = CoroutineScope(Dispatchers.IO).launch {
karooSystem.getRelativeHeadingFlow(context)
.combine(context.streamCurrentWeatherData()) { value, data -> value to data }
.combine(context.streamSettings()) { (value, data), settings -> StreamData(value, data, settings) }
.combine(context.streamSettings(karooSystem)) { (value, data), settings -> StreamData(value, data, settings) }
.collect { streamData ->
val windSpeed = streamData.data.current.windSpeed
val windDirection = streamData.value

View File

@ -68,7 +68,7 @@ class WeatherDataType(
val viewJob = CoroutineScope(Dispatchers.IO).launch {
context.streamCurrentWeatherData()
.combine(context.streamSettings()) { data, settings -> StreamData(data, settings) }
.combine(context.streamSettings(karooSystem)) { data, settings -> StreamData(data, settings) }
.onCompletion {
// Clear view on completion
val result = glance.compose(context, DpSize.Unspecified) { }

View File

@ -17,14 +17,12 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
data class DropdownOption(val id: String, val name: String)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Dropdown(label: String, options: List<DropdownOption>, initialSelection: DropdownOption, onSelect: (selectedOption: DropdownOption) -> Unit) {
fun Dropdown(label: String, options: List<DropdownOption>, selected: DropdownOption, onSelect: (selectedOption: DropdownOption) -> Unit) {
var expanded by remember { mutableStateOf(false) }
var selected by remember { mutableStateOf(initialSelection) }
ExposedDropdownMenuBox(
expanded = expanded,
@ -51,9 +49,8 @@ fun Dropdown(label: String, options: List<DropdownOption>, initialSelection: Dro
DropdownMenuItem(
text = { Text(option.name, style = MaterialTheme.typography.bodyLarge) },
onClick = {
selected = option
expanded = false
onSelect(selected)
onSelect(option)
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)

View File

@ -100,7 +100,7 @@ fun MainScreen() {
var savedDialogVisible by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
ctx.streamSettings().collect { settings ->
ctx.streamSettings(karooSystem).collect { settings ->
selectedWindUnit = settings.windUnit
selectedPrecipitationUnit = settings.precipitationUnit
welcomeDialogVisible = !settings.welcomeDialogAccepted
@ -123,14 +123,18 @@ fun MainScreen() {
.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(10.dp)) {
val windSpeedUnitDropdownOptions = WindUnit.entries.toList().map { unit -> DropdownOption(unit.id, unit.label) }
val windSpeedUnitInitialSelection = windSpeedUnitDropdownOptions.find { option -> option.id == selectedWindUnit.id }!!
Dropdown(label = "Wind Speed Unit", options = windSpeedUnitDropdownOptions, initialSelection = windSpeedUnitInitialSelection) { selectedOption ->
val windSpeedUnitInitialSelection by remember(selectedWindUnit) {
mutableStateOf(windSpeedUnitDropdownOptions.find { option -> option.id == selectedWindUnit.id }!!)
}
Dropdown(label = "Wind Speed Unit", options = windSpeedUnitDropdownOptions, selected = windSpeedUnitInitialSelection) { selectedOption ->
selectedWindUnit = WindUnit.entries.find { unit -> unit.id == selectedOption.id }!!
}
val precipitationUnitDropdownOptions = PrecipitationUnit.entries.toList().map { unit -> DropdownOption(unit.id, unit.label) }
val precipitationUnitInitialSelection = precipitationUnitDropdownOptions.find { option -> option.id == selectedPrecipitationUnit.id }!!
Dropdown(label = "Precipitation Unit", options = precipitationUnitDropdownOptions, initialSelection = precipitationUnitInitialSelection) { selectedOption ->
val precipitationUnitInitialSelection by remember(selectedPrecipitationUnit) {
mutableStateOf(precipitationUnitDropdownOptions.find { option -> option.id == selectedPrecipitationUnit.id }!!)
}
Dropdown(label = "Precipitation Unit", options = precipitationUnitDropdownOptions, selected = precipitationUnitInitialSelection) { selectedOption ->
selectedPrecipitationUnit = PrecipitationUnit.entries.find { unit -> unit.id == selectedOption.id }!!
}