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

@@ -307,11 +307,14 @@ class MutualViewModel(
val amSatFm = settingsRepo.getAmSatFmCatnums()
val amSatLinear = settingsRepo.getAmSatLinearCatnums()
val filteredSatellites = if (amSatFm.isEmpty() && amSatLinear.isEmpty()) {
// 回退到数据库模式过滤: 只用带上行频率的转发器记录, 排除纯下行
// 信标/遥测(如 CW 信标、FM 语音合成信标), 避免 ISS/IO-86/FO-29 等
// 因共享模式标签(CW/FM)被误判进错误类别.
val filterModes = buildList {
if (state.filterFM) add("FM")
if (state.filterLinear) addAll(listOf("USB", "LSB", "CW", "SSB"))
}
val idsWithModes = satelliteRepo.getSatelliteIdsWithModes(filterModes)
val idsWithModes = satelliteRepo.getSatelliteIdsWithModesAndUplink(filterModes)
if (idsWithModes.isEmpty()) satellites
else satellites.filter { it.data.catnum in idsWithModes }
} else {
@@ -45,6 +45,7 @@ class FakeSatelliteRepo(
override suspend fun getRadios(sat: OrbitalObject, pos: GeoPos, radios: List<SatRadio>, time: Long): List<SatRadio> = TODO()
override suspend fun getRadiosWithId(id: Int): List<SatRadio> = TODO()
override suspend fun getSatelliteIdsWithModes(modes: List<String>): List<Int> = emptyList()
override suspend fun getSatelliteIdsWithModesAndUplink(modes: List<String>): List<Int> = emptyList()
}
/**