mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Added DeepSpace passes filter, fixed refresh issue (#208)
This commit is contained in:
1 parent
d2b3184084
commit
8265b73d75
10 files changed
+112
-68
No files matched your search
+31
-28
@@ -31,6 +31,7 @@ import kotlinx.coroutines.CoroutineDispatcher
|
|||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
@@ -45,6 +46,9 @@ class SatelliteRepo(
|
|||||||
private val _passes = MutableStateFlow<List<OrbitalPass>>(emptyList())
|
private val _passes = MutableStateFlow<List<OrbitalPass>>(emptyList())
|
||||||
override val passes: StateFlow<List<OrbitalPass>> = _passes
|
override val passes: StateFlow<List<OrbitalPass>> = _passes
|
||||||
|
|
||||||
|
private val _isCalculating = MutableStateFlow(false)
|
||||||
|
override val isCalculating: StateFlow<Boolean> = _isCalculating
|
||||||
|
|
||||||
private val _satellites = MutableStateFlow<List<OrbitalObject>>(emptyList())
|
private val _satellites = MutableStateFlow<List<OrbitalObject>>(emptyList())
|
||||||
override val satellites: StateFlow<List<OrbitalObject>> = _satellites
|
override val satellites: StateFlow<List<OrbitalObject>> = _satellites
|
||||||
|
|
||||||
@@ -53,7 +57,7 @@ class SatelliteRepo(
|
|||||||
override suspend fun initRepository() = withContext(dispatcher) {
|
override suspend fun initRepository() = withContext(dispatcher) {
|
||||||
settingsRepo.selectedIds.collect { selectedIds ->
|
settingsRepo.selectedIds.collect { selectedIds ->
|
||||||
_satellites.update { localStorage.getEntriesWithIds(selectedIds) }
|
_satellites.update { localStorage.getEntriesWithIds(selectedIds) }
|
||||||
val (hoursAhead, minElevation, modes) = settingsRepo.passesSettings.value
|
val (_, hoursAhead, minElevation, modes) = settingsRepo.passesSettings.value
|
||||||
calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes)
|
calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,41 +99,40 @@ class SatelliteRepo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun calculatePasses(time: Long, hoursAhead: Int, minElevation: Double, modes: List<String>) {
|
override suspend fun calculatePasses(time: Long, hoursAhead: Int, minElevation: Double, modes: List<String>) {
|
||||||
|
_isCalculating.value = true
|
||||||
// Normalize to the start of the current minute so that coarse 60-second stepping
|
// Normalize to the start of the current minute so that coarse 60-second stepping
|
||||||
// in getLeoPass always begins from the same phase, producing stable AOS/LOS times
|
// in getLeoPass always begins from the same phase, producing stable AOS/LOS times
|
||||||
val normalizedTime = time / 60_000L * 60_000L
|
val normalizedTime = time / 60_000L * 60_000L
|
||||||
val currentSatellites = _satellites.value
|
val currentSatellites = _satellites.value
|
||||||
if (currentSatellites.isNotEmpty()) {
|
withContext(dispatcher) {
|
||||||
withContext(dispatcher) {
|
val idsWithModes = localStorage.getIdsWithModes(modes)
|
||||||
val idsWithModes = localStorage.getIdsWithModes(modes)
|
val stationPos = settingsRepo.stationPosition.value
|
||||||
val stationPos = settingsRepo.stationPosition.value
|
val filteredSatellites = if (idsWithModes.isEmpty()) {
|
||||||
val filteredSatellites = if (idsWithModes.isEmpty()) {
|
currentSatellites
|
||||||
currentSatellites
|
} else {
|
||||||
} else {
|
currentSatellites.filter { it.data.catnum in idsWithModes }
|
||||||
currentSatellites.filter { it.data.catnum in idsWithModes }
|
}
|
||||||
}
|
// Compute passes for each satellite in parallel
|
||||||
// Compute passes for each satellite in parallel
|
val passLists = coroutineScope {
|
||||||
val passLists = coroutineScope {
|
filteredSatellites.map { satellite ->
|
||||||
filteredSatellites.map { satellite ->
|
async { satellite.getPasses(stationPos, normalizedTime, hoursAhead) }
|
||||||
async { satellite.getPasses(stationPos, normalizedTime, hoursAhead) }
|
}.awaitAll()
|
||||||
}.awaitAll()
|
}
|
||||||
}
|
// Flatten and filter in a single pass
|
||||||
// Flatten and filter in a single pass
|
val timeFuture = normalizedTime + (hoursAhead * 60L * 60L * 1000L)
|
||||||
val timeFuture = normalizedTime + (hoursAhead * 60L * 60L * 1000L)
|
val newPasses = ArrayList<OrbitalPass>()
|
||||||
val newPasses = ArrayList<OrbitalPass>()
|
for (list in passLists) {
|
||||||
for (list in passLists) {
|
for (pass in list) {
|
||||||
for (pass in list) {
|
if (pass.losTime > time && pass.aosTime < timeFuture && pass.maxElevation > minElevation) {
|
||||||
if (pass.losTime > time && pass.aosTime < timeFuture && pass.maxElevation > minElevation) {
|
newPasses.add(pass)
|
||||||
newPasses.add(pass)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newPasses.sortBy { it.aosTime }
|
|
||||||
_passes.update { newPasses }
|
|
||||||
}
|
}
|
||||||
} else {
|
newPasses.sortBy { it.aosTime }
|
||||||
_passes.update { emptyList() }
|
delay(1000) // Simulate loading time for better UX
|
||||||
|
_passes.update { newPasses }
|
||||||
}
|
}
|
||||||
|
_isCalculating.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun OrbitalObject.getPasses(pos: GeoPos, time: Long, hours: Int): List<OrbitalPass> {
|
private fun OrbitalObject.getPasses(pos: GeoPos, time: Long, hours: Int): List<OrbitalPass> {
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ class SettingsRepo(
|
|||||||
private val keyBluetoothFrequencyState = "bluetoothFrequencyState"
|
private val keyBluetoothFrequencyState = "bluetoothFrequencyState"
|
||||||
private val keyBluetoothFrequencyAddress = "bluetoothFrequencyAddress"
|
private val keyBluetoothFrequencyAddress = "bluetoothFrequencyAddress"
|
||||||
private val keyBluetoothFrequencyFormat = "bluetoothFrequencyFormat"
|
private val keyBluetoothFrequencyFormat = "bluetoothFrequencyFormat"
|
||||||
|
private val keyFilterShowDeepSpace = "filterShowDeepSpace"
|
||||||
private val keyFilterHoursAhead = "filterHoursAhead"
|
private val keyFilterHoursAhead = "filterHoursAhead"
|
||||||
private val keyFilterMinElevation = "filterMinElevation"
|
private val keyFilterMinElevation = "filterMinElevation"
|
||||||
private val keyNumberOfRadios = "numberOfRadios"
|
private val keyNumberOfRadios = "numberOfRadios"
|
||||||
@@ -121,6 +122,7 @@ class SettingsRepo(
|
|||||||
override val passesSettings: StateFlow<PassesSettings> = _passesSettings
|
override val passesSettings: StateFlow<PassesSettings> = _passesSettings
|
||||||
|
|
||||||
override fun setPassesSettings(settings: PassesSettings) = preferences.edit {
|
override fun setPassesSettings(settings: PassesSettings) = preferences.edit {
|
||||||
|
putBoolean(keyFilterShowDeepSpace, settings.showDeepSpace)
|
||||||
putInt(keyFilterHoursAhead, settings.hoursAhead)
|
putInt(keyFilterHoursAhead, settings.hoursAhead)
|
||||||
putLong(keyFilterMinElevation, settings.minElevation.toRawBits())
|
putLong(keyFilterMinElevation, settings.minElevation.toRawBits())
|
||||||
putString(keySelectedModes, settings.selectedModes.joinToString(separatorComma))
|
putString(keySelectedModes, settings.selectedModes.joinToString(separatorComma))
|
||||||
@@ -128,11 +130,12 @@ class SettingsRepo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getPassesSettings(): PassesSettings {
|
private fun getPassesSettings(): PassesSettings {
|
||||||
|
val showDeepSpace = preferences.getBoolean(keyFilterShowDeepSpace, true)
|
||||||
val hoursAhead = preferences.getInt(keyFilterHoursAhead, 24)
|
val hoursAhead = preferences.getInt(keyFilterHoursAhead, 24)
|
||||||
val minElevation = Double.fromBits(preferences.getLong(keyFilterMinElevation, 16.0.toRawBits()))
|
val minElevation = Double.fromBits(preferences.getLong(keyFilterMinElevation, 16.0.toRawBits()))
|
||||||
val selectedModesString = preferences.getString(keySelectedModes, null)
|
val selectedModesString = preferences.getString(keySelectedModes, null)
|
||||||
val selectedModes = selectedModesString?.split(separatorComma)?.sorted() ?: emptyList()
|
val selectedModes = selectedModesString?.split(separatorComma)?.sorted() ?: emptyList()
|
||||||
return PassesSettings(hoursAhead, minElevation, selectedModes)
|
return PassesSettings(showDeepSpace, hoursAhead, minElevation, selectedModes)
|
||||||
}
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ data class DatabaseState(
|
|||||||
)
|
)
|
||||||
|
|
||||||
data class PassesSettings(
|
data class PassesSettings(
|
||||||
|
val showDeepSpace: Boolean = true,
|
||||||
val hoursAhead: Int,
|
val hoursAhead: Int,
|
||||||
val minElevation: Double,
|
val minElevation: Double,
|
||||||
val selectedModes: List<String>
|
val selectedModes: List<String>
|
||||||
|
|||||||
+3
@@ -31,6 +31,9 @@ interface ISatelliteRepo {
|
|||||||
/** Raw calculated passes (without live progress). Updated on selection/filter change. */
|
/** Raw calculated passes (without live progress). Updated on selection/filter change. */
|
||||||
val passes: StateFlow<List<OrbitalPass>>
|
val passes: StateFlow<List<OrbitalPass>>
|
||||||
|
|
||||||
|
/** Whether the repo is currently calculating passes. */
|
||||||
|
val isCalculating: StateFlow<Boolean>
|
||||||
|
|
||||||
/** Load satellite objects from DB based on the current selection. */
|
/** Load satellite objects from DB based on the current selection. */
|
||||||
suspend fun initRepository()
|
suspend fun initRepository()
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
<string name="pass_filter_title">Filter passes</string>
|
<string name="pass_filter_title">Filter passes</string>
|
||||||
<string name="pass_filter_elev">Minimal elevation</string>
|
<string name="pass_filter_elev">Minimal elevation</string>
|
||||||
<string name="pass_filter_hours">Hours ahead</string>
|
<string name="pass_filter_hours">Hours ahead</string>
|
||||||
|
<string name="pass_filter_deep_space">DeepSpace (period >225min)</string>
|
||||||
<string name="pass_time_placeholder" translatable="false"> -- : -- : -- </string>
|
<string name="pass_time_placeholder" translatable="false"> -- : -- : -- </string>
|
||||||
<string name="pass_modes_title">Select modulation type</string>
|
<string name="pass_modes_title">Select modulation type</string>
|
||||||
<string name="pass_satId" translatable="false">%05d</string>
|
<string name="pass_satId" translatable="false">%05d</string>
|
||||||
|
|||||||
@@ -32,12 +32,15 @@ import androidx.compose.material3.Checkbox
|
|||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Slider
|
import androidx.compose.material3.Slider
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableDoubleStateOf
|
import androidx.compose.runtime.mutableDoubleStateOf
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
@@ -65,17 +68,29 @@ private val hourSteps = listOf(1, 2, 4, 8, 12, 24, 48, 72, 96, 120, 144, 168, 19
|
|||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
private fun PassesDialogPreview() {
|
private fun PassesDialogPreview() {
|
||||||
MainTheme { PassesDialog(24, 16.0, {}) { _, _ -> } }
|
MainTheme { PassesDialog(24, 16.0, true, {}) { _, _, _ -> } }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun PassesDialog(hours: Int, elevation: Double, cancel: () -> Unit, accept: (Int, Double) -> Unit) {
|
internal fun PassesDialog(
|
||||||
|
hours: Int,
|
||||||
|
elevation: Double,
|
||||||
|
showDeepSpace: Boolean,
|
||||||
|
cancel: () -> Unit,
|
||||||
|
accept: (Int, Double, Boolean) -> Unit
|
||||||
|
) {
|
||||||
val hoursIndex = remember { mutableIntStateOf(hourSteps.indexOfFirst { it >= hours }.coerceAtLeast(0)) }
|
val hoursIndex = remember { mutableIntStateOf(hourSteps.indexOfFirst { it >= hours }.coerceAtLeast(0)) }
|
||||||
val elevationValueNew = remember { mutableDoubleStateOf(elevation) }
|
val elevationValueNew = remember { mutableDoubleStateOf(elevation) }
|
||||||
|
var deepSpaceEnabled by remember { mutableStateOf(showDeepSpace) }
|
||||||
val onAccept = {
|
val onAccept = {
|
||||||
accept(hourSteps[hoursIndex.intValue], elevationValueNew.doubleValue).also { cancel() }
|
accept(hourSteps[hoursIndex.intValue], elevationValueNew.doubleValue, deepSpaceEnabled).also { cancel() }
|
||||||
}
|
}
|
||||||
SharedDialog(title = stringResource(R.string.pass_filter_title), onCancel = cancel, onAccept = onAccept) {
|
SharedDialog(title = stringResource(R.string.pass_filter_title), onCancel = cancel, onAccept = onAccept) {
|
||||||
|
ToggleRow(
|
||||||
|
title = stringResource(R.string.pass_filter_deep_space),
|
||||||
|
checked = deepSpaceEnabled,
|
||||||
|
onCheckedChange = { deepSpaceEnabled = it }
|
||||||
|
)
|
||||||
SliderRow(
|
SliderRow(
|
||||||
title = stringResource(R.string.pass_filter_elev),
|
title = stringResource(R.string.pass_filter_elev),
|
||||||
value = elevationValueNew.doubleValue,
|
value = elevationValueNew.doubleValue,
|
||||||
@@ -188,3 +203,20 @@ internal fun RadiosDialog(modes: List<String>, cancel: () -> Unit, accept: (List
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ToggleRow(title: String, checked: Boolean, onCheckedChange: (Boolean) -> Unit) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.padding(horizontal = LocalSpacing.current.large)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
color = MaterialTheme.colorScheme.onSurface
|
||||||
|
)
|
||||||
|
Switch(checked = checked, onCheckedChange = onCheckedChange)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -100,9 +100,10 @@ private fun PassesScreen(
|
|||||||
PassesDialog(
|
PassesDialog(
|
||||||
hours = uiState.hours,
|
hours = uiState.hours,
|
||||||
elevation = uiState.elevation,
|
elevation = uiState.elevation,
|
||||||
|
showDeepSpace = uiState.showDeepSpace,
|
||||||
cancel = { onAction(PassesAction.TogglePassesDialog) }
|
cancel = { onAction(PassesAction.TogglePassesDialog) }
|
||||||
) { hours, elevation ->
|
) { hours, elevation, showDeepSpace ->
|
||||||
onAction(PassesAction.FilterPasses(hours, elevation))
|
onAction(PassesAction.FilterPasses(hours, elevation, showDeepSpace))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (uiState.isRadiosDialogShown) {
|
if (uiState.isRadiosDialogShown) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ data class PassesState(
|
|||||||
val isNextTimeAos: Boolean = true,
|
val isNextTimeAos: Boolean = true,
|
||||||
val hours: Int = 24,
|
val hours: Int = 24,
|
||||||
val elevation: Double = 16.0,
|
val elevation: Double = 16.0,
|
||||||
|
val showDeepSpace: Boolean = true,
|
||||||
val modes: List<String> = emptyList(),
|
val modes: List<String> = emptyList(),
|
||||||
val itemsList: List<OrbitalPass> = emptyList(),
|
val itemsList: List<OrbitalPass> = emptyList(),
|
||||||
val shouldSeeWhatsNew: Boolean = false
|
val shouldSeeWhatsNew: Boolean = false
|
||||||
@@ -36,7 +37,7 @@ data class PassesState(
|
|||||||
|
|
||||||
sealed interface PassesAction {
|
sealed interface PassesAction {
|
||||||
data object DismissWhatsNew : PassesAction
|
data object DismissWhatsNew : PassesAction
|
||||||
data class FilterPasses(val hoursAhead: Int, val minElevation: Double) : PassesAction
|
data class FilterPasses(val hoursAhead: Int, val minElevation: Double, val showDeepSpace: Boolean) : PassesAction
|
||||||
data class FilterRadios(val modes: List<String>) : PassesAction
|
data class FilterRadios(val modes: List<String>) : PassesAction
|
||||||
data object RefreshPasses : PassesAction
|
data object RefreshPasses : PassesAction
|
||||||
data object TogglePassesDialog : PassesAction
|
data object TogglePassesDialog : PassesAction
|
||||||
|
|||||||
+30
-31
@@ -34,7 +34,6 @@ import kotlinx.coroutines.delay
|
|||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.drop
|
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -51,6 +50,7 @@ class PassesViewModel(
|
|||||||
nextPass = defaultPass,
|
nextPass = defaultPass,
|
||||||
hours = settingsRepo.passesSettings.value.hoursAhead,
|
hours = settingsRepo.passesSettings.value.hoursAhead,
|
||||||
elevation = settingsRepo.passesSettings.value.minElevation,
|
elevation = settingsRepo.passesSettings.value.minElevation,
|
||||||
|
showDeepSpace = settingsRepo.passesSettings.value.showDeepSpace,
|
||||||
modes = settingsRepo.passesSettings.value.selectedModes,
|
modes = settingsRepo.passesSettings.value.selectedModes,
|
||||||
shouldSeeWhatsNew = settingsRepo.otherSettings.value.shouldSeeWhatsNew
|
shouldSeeWhatsNew = settingsRepo.otherSettings.value.shouldSeeWhatsNew
|
||||||
)
|
)
|
||||||
@@ -58,29 +58,20 @@ class PassesViewModel(
|
|||||||
val uiState: StateFlow<PassesState> = _uiState
|
val uiState: StateFlow<PassesState> = _uiState
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Show refreshing indicator whenever the selected satellites list changes
|
// Refresh indicator: mirrors the repo's isCalculating state
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
settingsRepo.selectedIds.collectLatest { selectedIds ->
|
satelliteRepo.isCalculating.collect { calculating ->
|
||||||
_uiState.update { it.copy(isRefreshing = true) }
|
_uiState.update { it.copy(isRefreshing = calculating) }
|
||||||
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
|
// Local tick loop — computes pass progress and countdown timer every second
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
val timeNow = System.currentTimeMillis()
|
val timeNow = System.currentTimeMillis()
|
||||||
val processed = computePassProgress(satelliteRepo.passes.value, timeNow)
|
val showDeepSpace = _uiState.value.showDeepSpace
|
||||||
|
val allPasses = satelliteRepo.passes.value
|
||||||
|
val filtered = if (showDeepSpace) allPasses else allPasses.filter { !it.isDeepSpace }
|
||||||
|
val processed = computePassProgress(filtered, timeNow)
|
||||||
val (nextPass, nextTime, isAos) = resolveNextPass(processed, timeNow)
|
val (nextPass, nextTime, isAos) = resolveNextPass(processed, timeNow)
|
||||||
_uiState.update {
|
_uiState.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
@@ -108,11 +99,17 @@ class PassesViewModel(
|
|||||||
fun onAction(action: PassesAction) {
|
fun onAction(action: PassesAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
PassesAction.DismissWhatsNew -> settingsRepo.setWhatsNewDismissed()
|
PassesAction.DismissWhatsNew -> settingsRepo.setWhatsNewDismissed()
|
||||||
is PassesAction.FilterPasses -> applyFilter(action.hoursAhead, action.minElevation, _uiState.value.modes)
|
is PassesAction.FilterPasses ->
|
||||||
is PassesAction.FilterRadios -> applyFilter(_uiState.value.hours, _uiState.value.elevation, action.modes)
|
applyFilter(action.hoursAhead, action.minElevation, action.showDeepSpace, _uiState.value.modes)
|
||||||
|
|
||||||
|
is PassesAction.FilterRadios ->
|
||||||
|
applyFilter(_uiState.value.hours, _uiState.value.elevation, _uiState.value.showDeepSpace, action.modes)
|
||||||
PassesAction.RefreshPasses -> refreshPasses()
|
PassesAction.RefreshPasses -> refreshPasses()
|
||||||
PassesAction.TogglePassesDialog -> _uiState.update { it.copy(isPassesDialogShown = !it.isPassesDialogShown) }
|
PassesAction.TogglePassesDialog ->
|
||||||
PassesAction.ToggleRadiosDialog -> _uiState.update { it.copy(isRadiosDialogShown = !it.isRadiosDialogShown) }
|
_uiState.update { it.copy(isPassesDialogShown = !it.isPassesDialogShown) }
|
||||||
|
|
||||||
|
PassesAction.ToggleRadiosDialog ->
|
||||||
|
_uiState.update { it.copy(isRadiosDialogShown = !it.isRadiosDialogShown) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,22 +150,24 @@ class PassesViewModel(
|
|||||||
return Triple(defaultPass, "00:00:00", true)
|
return Triple(defaultPass, "00:00:00", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun applyFilter(hoursAhead: Int, minElevation: Double, modes: List<String>) = viewModelScope.launch {
|
private fun applyFilter(
|
||||||
_uiState.update { it.copy(isRefreshing = true) }
|
hoursAhead: Int,
|
||||||
settingsRepo.setPassesSettings(PassesSettings(hoursAhead, minElevation, modes))
|
minElevation: Double,
|
||||||
_uiState.update { it.copy(hours = hoursAhead, elevation = minElevation, modes = modes) }
|
showDeepSpace: Boolean,
|
||||||
satelliteRepo.calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes)
|
modes: List<String>
|
||||||
_uiState.update { it.copy(isRefreshing = false) }
|
) = viewModelScope.launch {
|
||||||
|
settingsRepo.setPassesSettings(PassesSettings(showDeepSpace, hoursAhead, minElevation, modes))
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(hours = hoursAhead, elevation = minElevation, showDeepSpace = showDeepSpace, modes = modes)
|
||||||
|
}
|
||||||
|
if (showDeepSpace) satelliteRepo.calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshPasses() = viewModelScope.launch {
|
private fun refreshPasses() = viewModelScope.launch {
|
||||||
_uiState.update { it.copy(isRefreshing = true) }
|
val (_, hoursAhead, minElevation, modes) = settingsRepo.passesSettings.value
|
||||||
val (hoursAhead, minElevation, modes) = settingsRepo.passesSettings.value
|
|
||||||
satelliteRepo.calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes)
|
satelliteRepo.calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes)
|
||||||
_uiState.update { it.copy(isRefreshing = false) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||||
val applicationKey = ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY
|
val applicationKey = ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
appVersionCode = "420"
|
appVersionCode = "420"
|
||||||
#noinspection UnusedVersionCatalogEntry
|
#noinspection UnusedVersionCatalogEntry
|
||||||
appVersionName = "4.2.0"
|
appVersionName = "4.2.0"
|
||||||
#noinspection UnusedVersionCatalogEntry
|
#noinspection GradleDependency,UnusedVersionCatalogEntry
|
||||||
compileSdk = "36"
|
compileSdk = "36"
|
||||||
#noinspection UnusedVersionCatalogEntry
|
#noinspection UnusedVersionCatalogEntry
|
||||||
minSdk = "24"
|
minSdk = "24"
|
||||||
@@ -12,7 +12,7 @@ jdkVersion = "17"
|
|||||||
#noinspection UnusedVersionCatalogEntry
|
#noinspection UnusedVersionCatalogEntry
|
||||||
packageName = "com.rtbishop.look4sat"
|
packageName = "com.rtbishop.look4sat"
|
||||||
|
|
||||||
android-gradle-plugin = "9.1.0"
|
android-gradle-plugin = "9.1.1"
|
||||||
google-ksp = "2.3.6"
|
google-ksp = "2.3.6"
|
||||||
kotlin = "2.3.20"
|
kotlin = "2.3.20"
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user