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.datatypes.GpsCoordinates
|
||||||
import de.timklge.karooheadwind.screens.HeadwindSettings
|
import de.timklge.karooheadwind.screens.HeadwindSettings
|
||||||
import de.timklge.karooheadwind.screens.HeadwindStats
|
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.KarooSystemService
|
||||||
import io.hammerhead.karooext.models.DataType
|
import io.hammerhead.karooext.models.DataType
|
||||||
import io.hammerhead.karooext.models.HttpResponseState
|
import io.hammerhead.karooext.models.HttpResponseState
|
||||||
import io.hammerhead.karooext.models.OnHttpResponse
|
import io.hammerhead.karooext.models.OnHttpResponse
|
||||||
import io.hammerhead.karooext.models.OnStreamState
|
import io.hammerhead.karooext.models.OnStreamState
|
||||||
import io.hammerhead.karooext.models.StreamState
|
import io.hammerhead.karooext.models.StreamState
|
||||||
|
import io.hammerhead.karooext.models.UserProfile
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.TimeoutCancellationException
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
@ -24,6 +27,7 @@ import kotlinx.coroutines.flow.combine
|
|||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.mapNotNull
|
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) }
|
}.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 ->
|
return dataStore.data.map { settingsJson ->
|
||||||
try {
|
try {
|
||||||
jsonWithUnknownKeys.decodeFromString<HeadwindSettings>(
|
if (settingsJson.contains(settingsKey)){
|
||||||
settingsJson[settingsKey] ?: HeadwindSettings.defaultSettings
|
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){
|
} catch(e: Throwable){
|
||||||
Log.e(KarooHeadwindExtension.TAG, "Failed to read preferences", e)
|
Log.e(KarooHeadwindExtension.TAG, "Failed to read preferences", e)
|
||||||
jsonWithUnknownKeys.decodeFromString<HeadwindSettings>(HeadwindSettings.defaultSettings)
|
jsonWithUnknownKeys.decodeFromString<HeadwindSettings>(HeadwindSettings.defaultSettings)
|
||||||
@ -112,6 +126,17 @@ fun Context.streamStats(): Flow<HeadwindStats> {
|
|||||||
}.distinctUntilChanged()
|
}.distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun KarooSystemService.streamUserProfile(): Flow<UserProfile> {
|
||||||
|
return callbackFlow {
|
||||||
|
val listenerId = addConsumer { userProfile: UserProfile ->
|
||||||
|
trySendBlocking(userProfile)
|
||||||
|
}
|
||||||
|
awaitClose {
|
||||||
|
removeConsumer(listenerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(FlowPreview::class)
|
@OptIn(FlowPreview::class)
|
||||||
suspend fun KarooSystemService.makeOpenMeteoHttpRequest(gpsCoordinates: GpsCoordinates, settings: HeadwindSettings): HttpResponseState.Complete {
|
suspend fun KarooSystemService.makeOpenMeteoHttpRequest(gpsCoordinates: GpsCoordinates, settings: HeadwindSettings): HttpResponseState.Complete {
|
||||||
return callbackFlow {
|
return callbackFlow {
|
||||||
|
|||||||
@ -75,7 +75,7 @@ class KarooHeadwindExtension : KarooExtension("karoo-headwind", "1.0.0-beta2") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
streamSettings()
|
streamSettings(karooSystem)
|
||||||
.filter { it.welcomeDialogAccepted }
|
.filter { it.welcomeDialogAccepted }
|
||||||
.combine(gpsFlow) { settings, gps -> settings to gps }
|
.combine(gpsFlow) { settings, gps -> settings to gps }
|
||||||
.map { (settings, gps) ->
|
.map { (settings, gps) ->
|
||||||
|
|||||||
@ -72,7 +72,7 @@ class HeadwindDirectionDataType(
|
|||||||
karooSystem.streamDataFlow(dataTypeId)
|
karooSystem.streamDataFlow(dataTypeId)
|
||||||
.mapNotNull { (it as? StreamState.Streaming)?.dataPoint?.singleValue }
|
.mapNotNull { (it as? StreamState.Streaming)?.dataPoint?.singleValue }
|
||||||
.combine(context.streamCurrentWeatherData()) { value, data -> value to data }
|
.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 {
|
.onCompletion {
|
||||||
// Clear view on completion
|
// Clear view on completion
|
||||||
val result = glance.compose(context, DpSize.Unspecified) { }
|
val result = glance.compose(context, DpSize.Unspecified) { }
|
||||||
@ -83,7 +83,7 @@ class HeadwindDirectionDataType(
|
|||||||
val windSpeed = streamData.data.current.windSpeed
|
val windSpeed = streamData.data.current.windSpeed
|
||||||
val windDirection = streamData.value
|
val windDirection = streamData.value
|
||||||
val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed
|
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) {
|
val result = glance.compose(context, DpSize.Unspecified) {
|
||||||
HeadwindDirection(baseBitmap, windDirection.roundToInt(), config.textSize, windSpeedText)
|
HeadwindDirection(baseBitmap, windDirection.roundToInt(), config.textSize, windSpeedText)
|
||||||
|
|||||||
@ -28,7 +28,7 @@ class HeadwindSpeedDataType(
|
|||||||
val job = CoroutineScope(Dispatchers.IO).launch {
|
val job = CoroutineScope(Dispatchers.IO).launch {
|
||||||
karooSystem.getRelativeHeadingFlow(context)
|
karooSystem.getRelativeHeadingFlow(context)
|
||||||
.combine(context.streamCurrentWeatherData()) { value, data -> value to data }
|
.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 ->
|
.collect { streamData ->
|
||||||
val windSpeed = streamData.data.current.windSpeed
|
val windSpeed = streamData.data.current.windSpeed
|
||||||
val windDirection = streamData.value
|
val windDirection = streamData.value
|
||||||
|
|||||||
@ -68,7 +68,7 @@ class WeatherDataType(
|
|||||||
|
|
||||||
val viewJob = CoroutineScope(Dispatchers.IO).launch {
|
val viewJob = CoroutineScope(Dispatchers.IO).launch {
|
||||||
context.streamCurrentWeatherData()
|
context.streamCurrentWeatherData()
|
||||||
.combine(context.streamSettings()) { data, settings -> StreamData(data, settings) }
|
.combine(context.streamSettings(karooSystem)) { data, settings -> StreamData(data, settings) }
|
||||||
.onCompletion {
|
.onCompletion {
|
||||||
// Clear view on completion
|
// Clear view on completion
|
||||||
val result = glance.compose(context, DpSize.Unspecified) { }
|
val result = glance.compose(context, DpSize.Unspecified) { }
|
||||||
|
|||||||
@ -17,14 +17,12 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
|
||||||
data class DropdownOption(val id: String, val name: String)
|
data class DropdownOption(val id: String, val name: String)
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@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 expanded by remember { mutableStateOf(false) }
|
||||||
var selected by remember { mutableStateOf(initialSelection) }
|
|
||||||
|
|
||||||
ExposedDropdownMenuBox(
|
ExposedDropdownMenuBox(
|
||||||
expanded = expanded,
|
expanded = expanded,
|
||||||
@ -51,9 +49,8 @@ fun Dropdown(label: String, options: List<DropdownOption>, initialSelection: Dro
|
|||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(option.name, style = MaterialTheme.typography.bodyLarge) },
|
text = { Text(option.name, style = MaterialTheme.typography.bodyLarge) },
|
||||||
onClick = {
|
onClick = {
|
||||||
selected = option
|
|
||||||
expanded = false
|
expanded = false
|
||||||
onSelect(selected)
|
onSelect(option)
|
||||||
},
|
},
|
||||||
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
|
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -100,7 +100,7 @@ fun MainScreen() {
|
|||||||
var savedDialogVisible by remember { mutableStateOf(false) }
|
var savedDialogVisible by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
ctx.streamSettings().collect { settings ->
|
ctx.streamSettings(karooSystem).collect { settings ->
|
||||||
selectedWindUnit = settings.windUnit
|
selectedWindUnit = settings.windUnit
|
||||||
selectedPrecipitationUnit = settings.precipitationUnit
|
selectedPrecipitationUnit = settings.precipitationUnit
|
||||||
welcomeDialogVisible = !settings.welcomeDialogAccepted
|
welcomeDialogVisible = !settings.welcomeDialogAccepted
|
||||||
@ -123,14 +123,18 @@ fun MainScreen() {
|
|||||||
.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||||
|
|
||||||
val windSpeedUnitDropdownOptions = WindUnit.entries.toList().map { unit -> DropdownOption(unit.id, unit.label) }
|
val windSpeedUnitDropdownOptions = WindUnit.entries.toList().map { unit -> DropdownOption(unit.id, unit.label) }
|
||||||
val windSpeedUnitInitialSelection = windSpeedUnitDropdownOptions.find { option -> option.id == selectedWindUnit.id }!!
|
val windSpeedUnitInitialSelection by remember(selectedWindUnit) {
|
||||||
Dropdown(label = "Wind Speed Unit", options = windSpeedUnitDropdownOptions, initialSelection = windSpeedUnitInitialSelection) { selectedOption ->
|
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 }!!
|
selectedWindUnit = WindUnit.entries.find { unit -> unit.id == selectedOption.id }!!
|
||||||
}
|
}
|
||||||
|
|
||||||
val precipitationUnitDropdownOptions = PrecipitationUnit.entries.toList().map { unit -> DropdownOption(unit.id, unit.label) }
|
val precipitationUnitDropdownOptions = PrecipitationUnit.entries.toList().map { unit -> DropdownOption(unit.id, unit.label) }
|
||||||
val precipitationUnitInitialSelection = precipitationUnitDropdownOptions.find { option -> option.id == selectedPrecipitationUnit.id }!!
|
val precipitationUnitInitialSelection by remember(selectedPrecipitationUnit) {
|
||||||
Dropdown(label = "Precipitation Unit", options = precipitationUnitDropdownOptions, initialSelection = precipitationUnitInitialSelection) { selectedOption ->
|
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 }!!
|
selectedPrecipitationUnit = PrecipitationUnit.entries.find { unit -> unit.id == selectedOption.id }!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user