mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-03 11:17:25 +00:00
Added several tweaks to Settings and RadioControl screens
This commit is contained in:
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
|
||||
}
|
||||
+14
-6
@@ -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
|
||||
|
||||
Reference in new issue
Block a user