Added several tweaks to Settings and RadioControl screens

This commit is contained in:
Arty Bishop committed 2026-04-10 14:13:53 +01:00
1 parent 4a3a01729b
commit a94f95874b
14 files changed
+514 -505

No files matched your search

@@ -60,6 +60,8 @@ private val allModes = listOf(
"PSK", "PSK31", "PSK63", "QPSK", "QPSK31", "QPSK63", "SSTV", "USB", "WSJT"
)
private val hourSteps = listOf(1, 2, 4, 8, 12, 24, 48, 72, 96, 120, 144, 168, 192, 216, 240)
@Preview
@Composable
private fun PassesDialogPreview() {
@@ -68,26 +70,27 @@ private fun PassesDialogPreview() {
@Composable
internal fun PassesDialog(hours: Int, elevation: Double, cancel: () -> Unit, accept: (Int, Double) -> Unit) {
val hoursValue = remember { mutableIntStateOf(hours) }
val hoursIndex = remember { mutableIntStateOf(hourSteps.indexOfFirst { it >= hours }.coerceAtLeast(0)) }
val elevationValueNew = remember { mutableDoubleStateOf(elevation) }
val onAccept = {
accept(hoursValue.intValue, elevationValueNew.doubleValue).also { cancel() }
accept(hourSteps[hoursIndex.intValue], elevationValueNew.doubleValue).also { cancel() }
}
SharedDialog(title = stringResource(R.string.pass_filter_title), onCancel = cancel, onAccept = onAccept) {
SliderRow(
title = stringResource(R.string.pass_filter_elev),
value = elevationValueNew.doubleValue,
valuePostfix = "°",
displayValue = "${elevationValueNew.doubleValue.toInt()}°",
valueResId = R.drawable.ic_elevation,
valueRange = 0f..60f
) { elevationValueNew.doubleValue = it.toDouble() }
SliderRow(
title = stringResource(R.string.pass_filter_hours),
value = hoursValue.intValue.toDouble(),
valuePostfix = "h",
value = hoursIndex.intValue.toDouble(),
displayValue = "${hourSteps[hoursIndex.intValue]}h",
valueResId = R.drawable.ic_clock,
valueRange = 1f..240f
) { hoursValue.intValue = it.toInt() }
valueRange = 0f..(hourSteps.size - 1).toFloat(),
steps = hourSteps.size - 2
) { hoursIndex.intValue = it.toInt().coerceIn(0, hourSteps.size - 1) }
}
}
@@ -95,9 +98,10 @@ internal fun PassesDialog(hours: Int, elevation: Double, cancel: () -> Unit, acc
private fun SliderRow(
title: String,
value: Double,
valuePostfix: String,
displayValue: String,
valueResId: Int,
valueRange: ClosedFloatingPointRange<Float>,
steps: Int = 0,
onChange: (Float) -> Unit
) {
Column(
@@ -122,13 +126,13 @@ private fun SliderRow(
modifier = Modifier.size(20.dp)
)
Text(
text = "${value.toInt()}$valuePostfix",
text = displayValue,
fontSize = 18.sp,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.primary
)
}
Slider(value = value.toFloat(), onValueChange = onChange, valueRange = valueRange)
Slider(value = value.toFloat(), onValueChange = onChange, valueRange = valueRange, steps = steps)
}
}
@@ -34,11 +34,11 @@ data class PassesState(
val shouldSeeWhatsNew: Boolean = false
)
sealed class PassesAction {
data object DismissWhatsNew : PassesAction()
data class FilterPasses(val hoursAhead: Int, val minElevation: Double) : PassesAction()
data class FilterRadios(val modes: List<String>) : PassesAction()
data object RefreshPasses : PassesAction()
data object TogglePassesDialog : PassesAction()
data object ToggleRadiosDialog : PassesAction()
sealed interface PassesAction {
data object DismissWhatsNew : PassesAction
data class FilterPasses(val hoursAhead: Int, val minElevation: Double) : PassesAction
data class FilterRadios(val modes: List<String>) : PassesAction
data object RefreshPasses : PassesAction
data object TogglePassesDialog : PassesAction
data object ToggleRadiosDialog : PassesAction
}
@@ -34,6 +34,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
@@ -57,15 +58,22 @@ class PassesViewModel(
val uiState: StateFlow<PassesState> = _uiState
init {
// React to raw pass list changes — stops the refreshing indicator on first emission
// Show refreshing indicator whenever the selected satellites list changes
viewModelScope.launch {
var initialLoadDone = false
satelliteRepo.passes.collectLatest { _ ->
if (!initialLoadDone) {
initialLoadDone = true
delay(1000) // Artificial delay to show the refreshing state on first load
settingsRepo.selectedIds.collectLatest { selectedIds ->
_uiState.update { it.copy(isRefreshing = true) }
if (selectedIds.isEmpty()) {
// No satellites selected — show indicator briefly, then stop
delay(1000)
_uiState.update { it.copy(isRefreshing = false) }
}
// For non-empty selections, the passes collector below will clear isRefreshing
}
}
// Stop refreshing whenever new passes arrive (from initial load, selection change, or filter)
viewModelScope.launch {
satelliteRepo.passes.drop(1).collect { _ ->
_uiState.update { it.copy(isRefreshing = false) }
}
}
// Local tick loop — computes pass progress and countdown timer every second