fix #7: Set units of measurement to karoo profile preferences on first load
This commit is contained in:
parent
8d30e62015
commit
a4347511a5
@ -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 {
|
||||
|
||||
@ -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) ->
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) { }
|
||||
|
||||
@ -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,
|
||||
)
|
||||
|
||||
@ -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 }!!
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user