fix: transponder filters - mutual exclusion and beacon-free fallback

Two correctness fixes for the FM/Linear/SSTV filters:

1. Satellite type picker: virtual transponder types (AMSAT Live FM,
   AMSAT Live Linear, Live SSTV) are now mutually exclusive with the
   regular TLE-source types - ticking a virtual type clears Amateur/
   CubeSat/etc and vice versa, so selecting 'AMSAT Live FM' no longer
   unions in hundreds of non-transponder satellites. Virtual types
   still combine with each other. Also: an empty virtual-type resolve
   now yields an empty list instead of falling back to 'show all'.

2. Mutual-match fallback: when the AMSAT lists are empty (first run /
   sync failure) the DB mode filter used downlinkMode alone, so any
   downlink-only beacon sharing a mode label was misclassified
   (ISS/IO-86 CW beacons into Linear, FO-29's FM Digitalker into FM).
   New getIdsWithModesAndUplink() requires uplinkLow IS NOT NULL,
   matching real transponders only. SSTV filter keeps the old query
   (SSTV sats are often downlink-only).

Shared virtual-type names moved to Sources.virtualTypeNames.
This commit is contained in:
atsunatsu committed 2026-09-24 00:51:13 +08:00
1 parent b295500d14
commit cf1e2b99b4
12 files changed
+66 -7

No files matched your search

@@ -42,6 +42,7 @@ import androidx.compose.ui.unit.dp
import com.rtbishop.look4sat.core.presentation.MainTheme
import com.rtbishop.look4sat.core.presentation.R
import com.rtbishop.look4sat.core.presentation.SharedDialog
import com.rtbishop.look4sat.core.domain.source.Sources
@Preview(showBackground = true)
@Composable
@@ -54,9 +55,20 @@ private fun MultiTypesDialogPreview() {
internal fun MultiTypesDialog(
allTypes: List<String>, types: List<String>, cancel: () -> Unit, accept: (List<String>) -> Unit
) {
// 虚拟类型(转发器/活动筛选)与普通 TLE 源类型互斥: 勾虚拟类型时取消普通类型,
// 勾普通类型时取消虚拟类型. 虚拟类型之间可多选组合.
val virtualTypes = Sources.virtualTypeNames
val selected = remember { mutableStateOf(types.toSet()) }
val toggle = { type: String ->
selected.value = if (type in selected.value) selected.value - type else selected.value + type
selected.value = if (type in selected.value) {
selected.value - type
} else if (type in virtualTypes) {
// 勾选虚拟类型: 移除所有普通类型, 保留已勾的虚拟类型.
(selected.value.filterTo(mutableSetOf()) { it in virtualTypes }) + type
} else {
// 勾选普通类型: 移除所有虚拟类型, 保留已勾的普通类型.
(selected.value.filterTo(mutableSetOf()) { it !in virtualTypes }) + type
}
}
val onAccept = { accept(selected.value.toList()) }
SharedDialog(title = stringResource(R.string.sat_type_title), onCancel = cancel, onAccept = onAccept) {