mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
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:
1 parent
b295500d14
commit
cf1e2b99b4
12 files changed
+66
-7
No files matched your search
@@ -48,6 +48,12 @@ interface Look4SatDao {
|
||||
@Query("SELECT catnum FROM radios WHERE downlinkMode IN (:modes) AND isAlive = 1")
|
||||
suspend fun getIdsWithModes(modes: List<String>): List<Int>
|
||||
|
||||
/** Like [getIdsWithModes] but only matches transponder records with an uplink,
|
||||
* excluding downlink-only beacons/telemetry that share the same mode label
|
||||
* (e.g. CW beacons, FM voice-synthesis beacons) from FM/Linear filter fallback. */
|
||||
@Query("SELECT catnum FROM radios WHERE downlinkMode IN (:modes) AND uplinkLow IS NOT NULL AND isAlive = 1")
|
||||
suspend fun getIdsWithModesAndUplink(modes: List<String>): List<Int>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM radios")
|
||||
suspend fun getRadiosTotal(): Int
|
||||
|
||||
|
||||
@@ -67,6 +67,8 @@ class SatelliteRepo(
|
||||
|
||||
override suspend fun getSatelliteIdsWithModes(modes: List<String>) = localStorage.getIdsWithModes(modes)
|
||||
|
||||
override suspend fun getSatelliteIdsWithModesAndUplink(modes: List<String>) = localStorage.getIdsWithModesAndUplink(modes)
|
||||
|
||||
override suspend fun initRepository() = withContext(dispatcher) {
|
||||
combine(
|
||||
settingsRepo.selectedIds,
|
||||
|
||||
@@ -50,7 +50,7 @@ class SelectionRepo(
|
||||
null // null = no filtering
|
||||
} else {
|
||||
val ids = resolveTypeIds(types)
|
||||
if (ids.isEmpty()) null else ids.toHashSet()
|
||||
if (ids.isEmpty()) emptySet() else ids.toHashSet()
|
||||
}
|
||||
currentItems.map { items ->
|
||||
if (catnumSet == null) items else items.filter { it.catnum in catnumSet }
|
||||
@@ -72,9 +72,9 @@ class SelectionRepo(
|
||||
val idsSet = mutableSetOf<Int>()
|
||||
types.forEach { type ->
|
||||
when (type) {
|
||||
"AMSAT Live FM" -> idsSet.addAll(settingsRepo.getAmSatFmCatnums())
|
||||
"AMSAT Live Linear" -> idsSet.addAll(settingsRepo.getAmSatLinearCatnums())
|
||||
"Live SSTV" -> idsSet.addAll(localSource.getIdsWithModes(listOf("SSTV")))
|
||||
Sources.virtualTypeNames[0] -> idsSet.addAll(settingsRepo.getAmSatFmCatnums())
|
||||
Sources.virtualTypeNames[1] -> idsSet.addAll(settingsRepo.getAmSatLinearCatnums())
|
||||
Sources.virtualTypeNames[2] -> idsSet.addAll(localSource.getIdsWithModes(listOf("SSTV")))
|
||||
else -> idsSet.addAll(settingsRepo.getSatelliteTypesIds(listOf(type)))
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ class SelectionRepo(
|
||||
|
||||
override fun getTypesList() = buildList {
|
||||
// 三个转发器/活动虚拟类型排在最前.
|
||||
addAll(listOf("AMSAT Live FM", "AMSAT Live Linear", "Live SSTV"))
|
||||
addAll(Sources.virtualTypeNames)
|
||||
addAll(Sources.satelliteDataUrls.keys.sorted().toMutableList().apply { removeAt(0) })
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ class LocalSource(private val look4SatDao: Look4SatDao) : ILocalSource {
|
||||
override suspend fun deleteEntries() = look4SatDao.deleteEntries()
|
||||
|
||||
override suspend fun getIdsWithModes(modes: List<String>) = look4SatDao.getIdsWithModes(modes)
|
||||
override suspend fun getIdsWithModesAndUplink(modes: List<String>) = look4SatDao.getIdsWithModesAndUplink(modes)
|
||||
|
||||
private fun FrameworkEntry.toDomain() = OrbitalData(
|
||||
this.name, this.epoch, this.meanmo, this.eccn, this.incl,
|
||||
|
||||
@@ -180,6 +180,7 @@ private class FakeLocalSource : ILocalSource {
|
||||
}
|
||||
|
||||
override suspend fun getIdsWithModes(modes: List<String>): List<Int> = emptyList()
|
||||
override suspend fun getIdsWithModesAndUplink(modes: List<String>): List<Int> = emptyList()
|
||||
|
||||
override suspend fun getRadiosTotal(): Int = insertedRadios.size
|
||||
|
||||
|
||||
+21
@@ -156,6 +156,26 @@ class SelectionRepoSearchTest {
|
||||
assertEquals(sampleItems.size, repo.getEntriesFlow().first().size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `virtual type with empty AMSAT list shows empty not everything`() = runTest {
|
||||
// 根因2回归: AMSAT 清单未同步(空)时, 选虚拟类型应显示空列表, 而非全部卫星.
|
||||
val repo = createRepo(items = sampleItems, amSatFm = emptySet())
|
||||
repo.setTypes(listOf("AMSAT Live FM"))
|
||||
assertTrue(repo.getEntriesFlow().first().isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `virtual type combined with regular type unions both lists`() = runTest {
|
||||
val repo = createRepo(
|
||||
items = sampleItems,
|
||||
amSatFm = setOf(25544),
|
||||
amSatLinear = setOf(7530)
|
||||
)
|
||||
repo.setTypes(listOf("AMSAT Live FM", "AMSAT Live Linear"))
|
||||
val results = repo.getEntriesFlow().first()
|
||||
assertEquals(setOf(25544, 7530), results.map { it.catnum }.toSet())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `types list has virtual transponder types first and keeps All`() {
|
||||
val repo = createRepo(sampleItems)
|
||||
@@ -192,6 +212,7 @@ private class FakeLocalSourceForSearch(
|
||||
override suspend fun insertEntries(entries: List<OrbitalData>) = Unit
|
||||
override suspend fun deleteEntries() = Unit
|
||||
override suspend fun getIdsWithModes(modes: List<String>): List<Int> = sstvIds
|
||||
override suspend fun getIdsWithModesAndUplink(modes: List<String>): List<Int> = sstvIds
|
||||
override suspend fun getRadiosTotal(): Int = 0
|
||||
override suspend fun getRadiosWithId(id: Int): List<SatRadio> = emptyList()
|
||||
override suspend fun insertRadios(radios: List<SatRadio>, isCustom: Boolean) = Unit
|
||||
|
||||
+5
@@ -70,4 +70,9 @@ interface ISatelliteRepo {
|
||||
* Empty modes -> empty result; used to filter the mutual-match satellite
|
||||
* set to transponder satellites (FM voice / linear). */
|
||||
suspend fun getSatelliteIdsWithModes(modes: List<String>): List<Int>
|
||||
|
||||
/** Like [getSatelliteIdsWithModes] but only matches records with an uplink
|
||||
* (real transponders), excluding downlink-only beacons/telemetry that share
|
||||
* the same mode label. Used by the FM/Linear fallback filter. */
|
||||
suspend fun getSatelliteIdsWithModesAndUplink(modes: List<String>): List<Int>
|
||||
}
|
||||
@@ -29,6 +29,7 @@ interface ILocalSource {
|
||||
suspend fun insertEntries(entries: List<OrbitalData>)
|
||||
suspend fun deleteEntries()
|
||||
suspend fun getIdsWithModes(modes: List<String>): List<Int>
|
||||
suspend fun getIdsWithModesAndUplink(modes: List<String>): List<Int>
|
||||
suspend fun getRadiosTotal(): Int
|
||||
suspend fun getRadiosWithId(id: Int): List<SatRadio>
|
||||
suspend fun insertRadios(radios: List<SatRadio>, isCustom: Boolean = false)
|
||||
|
||||
@@ -62,4 +62,10 @@ object Sources {
|
||||
"FM" to "https://www.amsat.org/live-fm-satellites/",
|
||||
"Linear" to "https://www.amsat.org/live-linear-satellites/"
|
||||
)
|
||||
|
||||
/** Virtual satellite-selection types: transponder/activity filters shown
|
||||
* at the top of the type picker. They resolve to live lists (AMSAT pages
|
||||
* or mode=SSTV radios) instead of persisted per-type IDs, and are
|
||||
* mutually exclusive with the regular TLE-source types in the picker. */
|
||||
val virtualTypeNames = listOf("AMSAT Live FM", "AMSAT Live Linear", "Live SSTV")
|
||||
}
|
||||
Reference in new issue
Block a user