mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 19:17:21 +00:00
fix(nav,radar,wavelog): 4.5.2 third overwrite - log page entry visible, freq format 3 decimals, direct freq extraction
User-test fixes (3rd overwrite, version stays 4.5.2/452):
1. Log page was invisible everywhere outside the radar tab:
- allNavItems in MainScreen.kt was missing Screen.WavelogLog ->
not in bottom nav, not in More menu
- SettingsScreen UI-order lists were missing the WavelogLog row ->
not in page order settings either
Now the Log page appears in the More menu (default sub menu tail,
migration appends it) AND in UI settings page-order lists.
2. Frequency display: formatFrequency was MHz.kHz.Hz (145.900.000);
now MHz.kHz (145.900) per request. Applies to transceiver panel
and Log page alike (shared formatter).
3. Log tab frequency: now extracts the exact numbers shown in the
transceiver panel (txBaseFrequencyHz for TX, uplinkLow/uplinkHigh
range for linear) - no re-computation, no extra decimals. Upload
uses the same tuned frequency (Hz precision kept internally).
4. Log page (More menu) table: date+time column (MM-dd HH:mm),
row separators (table lines), uploaded checkmark kept.
Verified: check_strings OK (8 files); :app:compileDebugKotlin
BUILD SUCCESSFUL (includes upstream merge 1a552417).
This commit is contained in:
1 parent
1a55241791
commit
ab1a0c0891
5 files changed
+53
-61
No files matched your search
@@ -148,7 +148,7 @@ fun MainScreen(navigateToRadar: () -> Unit = {}) {
|
||||
val trackingState by container.radioTrackingService.state.collectAsStateWithLifecycle()
|
||||
val otherSettings by container.settingsRepo.otherSettings.collectAsStateWithLifecycle()
|
||||
// UI 设置: 按 screenOrder 排序(空 = 默认顺序), 再按 hiddenScreens 过滤(设置页固定保留)
|
||||
val allNavItems = listOf(Screen.Satellites, Screen.Passes, Screen.Radar, Screen.Mutual, Screen.Roaming, Screen.CwDecode, Screen.Map, Screen.Settings)
|
||||
val allNavItems = listOf(Screen.Satellites, Screen.Passes, Screen.Radar, Screen.Mutual, Screen.Roaming, Screen.CwDecode, Screen.WavelogLog, Screen.Map, Screen.Settings)
|
||||
.sortedBy { screen ->
|
||||
// 未知(新页面如 CwDecode 不在旧持久化顺序里): 用默认顺序位置(漫游↔地图), 再兜底最后
|
||||
val idx = otherSettings.screenOrder.indexOf(screen.screenId)
|
||||
|
||||
+1
-2
@@ -518,6 +518,5 @@ fun formatFrequency(frequencyHz: Long): String {
|
||||
if (frequencyHz <= 0) return "---"
|
||||
val mhz = frequencyHz / 1_000_000
|
||||
val khz = (frequencyHz % 1_000_000) / 1_000
|
||||
val hz = frequencyHz % 1_000
|
||||
return String.format(Locale.ENGLISH, "%d.%03d.%03d", mhz, khz, hz)
|
||||
return String.format(Locale.ENGLISH, "%d.%03d", mhz, khz)
|
||||
}
|
||||
@@ -229,26 +229,14 @@ private fun ExpandedLogInput(
|
||||
var callsign by remember { mutableStateOf("") }
|
||||
var mode by remember { mutableStateOf(radio.uplinkMode ?: "FM") }
|
||||
|
||||
// 回车那一刻的频率(与雷达页 Doppler 面板一致): 优先用当前调谐 TX 频率
|
||||
fun currentFreqs(): Pair<Long, Long> {
|
||||
val uplinkBase = radio.uplinkLow ?: radio.downlinkLow ?: 0L
|
||||
val downlinkBase = radio.downlinkLow ?: radio.uplinkLow ?: 0L
|
||||
// 调谐基准(用户在当前转发器上调的)优先; 否则转发器标称下限
|
||||
val tx = txBaseFrequencyHz ?: (if (orbitalPos != null) orbitalPos.getUplinkFreq(uplinkBase) else uplinkBase)
|
||||
val rx = if (orbitalPos != null) {
|
||||
// 线性转发器: 按映射算下行; FM: 标称下行加多普勒
|
||||
DopplerFrequencyCalculator.computeDownlinkFromUplink(tx, radio, orbitalPos)
|
||||
?: orbitalPos.getDownlinkFreq(downlinkBase)
|
||||
} else downlinkBase
|
||||
return tx to rx
|
||||
}
|
||||
|
||||
val savedMsg = stringResource(id = R.string.wavelog_saved)
|
||||
|
||||
fun submit() {
|
||||
val call = callsign.trim().uppercase()
|
||||
if (call.length < 3) return
|
||||
val (tx, rx) = currentFreqs()
|
||||
// 频率直接取转发器栏的数字(不再多普勒再计算): TX = 当前调谐, RX = 下行基准
|
||||
val tx = txBaseFrequencyHz ?: (radio.uplinkLow ?: radio.downlinkLow ?: 0L)
|
||||
val rx = radio.downlinkLow ?: radio.uplinkLow ?: 0L
|
||||
queue.add(
|
||||
WavelogQso(
|
||||
id = UUID.randomUUID().toString(),
|
||||
@@ -265,35 +253,31 @@ private fun ExpandedLogInput(
|
||||
showToast(savedMsg)
|
||||
}
|
||||
|
||||
val (txHz, rxHz) = currentFreqs()
|
||||
// 线性转发器: 显示频段区间(多普勒修正); FM: 单频
|
||||
val isLinear = DopplerFrequencyCalculator.isLinearTransponder(radio)
|
||||
val uplinkLow = radio.uplinkLow
|
||||
val uplinkHigh = radio.uplinkHigh
|
||||
val downlinkLow = radio.downlinkLow
|
||||
val downlinkHigh = radio.downlinkHigh
|
||||
val txRange = if (isLinear && uplinkLow != null && uplinkHigh != null && orbitalPos != null) {
|
||||
val lo = orbitalPos.getUplinkFreq(uplinkLow)
|
||||
val hi = orbitalPos.getUplinkFreq(uplinkHigh)
|
||||
"${formatFrequency(minOf(lo, hi))}–${formatFrequency(maxOf(lo, hi))}"
|
||||
} else null
|
||||
val rxRange = if (isLinear && downlinkLow != null && downlinkHigh != null && orbitalPos != null) {
|
||||
val lo = orbitalPos.getDownlinkFreq(downlinkLow)
|
||||
val hi = orbitalPos.getDownlinkFreq(downlinkHigh)
|
||||
"${formatFrequency(minOf(lo, hi))}–${formatFrequency(maxOf(lo, hi))}"
|
||||
} else null
|
||||
// 频率显示与转发器栏完全一致(不再另算): TX = 当前调谐(txBaseFrequencyHz), 线性附加频段范围
|
||||
val txForDisplay = txBaseFrequencyHz ?: (radio.uplinkLow ?: radio.downlinkLow ?: 0L)
|
||||
val upLow = radio.uplinkLow
|
||||
val upHigh = radio.uplinkHigh
|
||||
val isLinearRange = upLow != null && upHigh != null && upLow != upHigh
|
||||
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = "TX ${txRange ?: formatFrequency(txHz)}",
|
||||
text = "TX ",
|
||||
fontSize = 12.sp,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Text(
|
||||
text = "RX ${rxRange ?: formatFrequency(rxHz)}",
|
||||
fontSize = 12.sp,
|
||||
text = "${formatFrequency(txForDisplay)} MHz",
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
if (isLinearRange) {
|
||||
Text(
|
||||
text = " (${formatFrequency(upLow)} – ${formatFrequency(upHigh)})",
|
||||
fontSize = 11.sp,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
OutlinedTextField(
|
||||
value = callsign,
|
||||
|
||||
+29
-21
@@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -81,34 +82,41 @@ fun WavelogLogScreen(
|
||||
modifier = Modifier.padding(vertical = 12.dp)
|
||||
)
|
||||
} else {
|
||||
entries.forEach { entry ->
|
||||
entries.forEachIndexed { index, entry ->
|
||||
SwipeDeleteRow(
|
||||
onDelete = {
|
||||
queue.remove(entry.id)
|
||||
refreshTick++
|
||||
}
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(MaterialTheme.colorScheme.surfaceContainer)
|
||||
.padding(horizontal = 10.dp, vertical = 8.dp)
|
||||
) {
|
||||
Cell(formatLocalTime(entry.timeUtcMs), 52.dp)
|
||||
Cell(formatFrequency(entry.freqTxHz), 70.dp)
|
||||
Cell(entry.satName, 0.dp, weight = 1.2f)
|
||||
Cell(entry.call, 0.dp, weight = 1f)
|
||||
Box(modifier = Modifier.width(44.dp)) {
|
||||
if (entry.uploaded) {
|
||||
Text(
|
||||
text = "✓",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = CheckGreen
|
||||
)
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(MaterialTheme.colorScheme.surfaceContainer)
|
||||
.padding(horizontal = 10.dp, vertical = 8.dp)
|
||||
) {
|
||||
Cell(formatLocalTime(entry.timeUtcMs), 74.dp)
|
||||
Cell(formatFrequency(entry.freqTxHz), 62.dp)
|
||||
Cell(entry.satName, 0.dp, weight = 1.2f)
|
||||
Cell(entry.call, 0.dp, weight = 1f)
|
||||
Box(modifier = Modifier.width(44.dp)) {
|
||||
if (entry.uploaded) {
|
||||
Text(
|
||||
text = "✓",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = CheckGreen
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 表格分隔线
|
||||
HorizontalDivider(
|
||||
thickness = 1.dp,
|
||||
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.25f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,5 +151,5 @@ private fun RowScope.Cell(text: String, width: androidx.compose.ui.unit.Dp, weig
|
||||
private fun formatLocalTime(utcMs: Long): String {
|
||||
val cal = Calendar.getInstance(TimeZone.getDefault())
|
||||
cal.timeInMillis = utcMs
|
||||
return "%02d:%02d".format(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE))
|
||||
return "%02d-%02d %02d:%02d".format(cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE))
|
||||
}
|
||||
+1
@@ -704,6 +704,7 @@ private fun UiSettingsCard(
|
||||
R.string.nav_mutual to "Mutual",
|
||||
R.string.nav_roaming to "Roaming",
|
||||
R.string.nav_cw to "CwDecode",
|
||||
R.string.nav_log to "WavelogLog",
|
||||
R.string.nav_map to "Map",
|
||||
R.string.nav_prefs to "Settings"
|
||||
) // name 必须与 Screen.screenId 一致 (R8 安全)
|
||||
|
||||
Reference in new issue
Block a user