fix(mutual/radar): bigger radar shortcut; no bounce-back on finished pass

- Pass card header: radar icon button enlarged to 48dp touch target with a
  24dp icon, spanning both header rows vertically (name/time + elevations);
  the pass info column narrows so the Opposite elevation shifts left.
- RadarDestination no longer auto-returns instantly when the mutual pass has
  already ended — the auto-return now only runs while the pass is actually in
  progress. Previously the collapsed-card radar shortcut appeared broken
  ('flash back to Mutual') whenever the computed pass had finished.
- Fakes: add the 4 last-sync bookkeeping members missed by the LoTW commit.
This commit is contained in:
atsunatsu committed 2026-09-16 16:53:46 +08:00
1 parent f3fdf61784
commit 0ce177cfbf
3 files changed
+64 -44

No files matched your search

@@ -567,50 +567,63 @@ private fun MutualPassCard(
.clickable(onClick = onClick) .clickable(onClick = onClick)
) { ) {
Column(modifier = Modifier.padding(12.dp)) { Column(modifier = Modifier.padding(12.dp)) {
Row( // Header: pass info (name/time + elevations) on the left, and a
modifier = Modifier.fillMaxWidth(), // larger radar shortcut on the right that spans both rows vertically.
horizontalArrangement = Arrangement.SpaceBetween, // The pass info column narrows, so the "Opposite" elevation shifts
verticalAlignment = Alignment.CenterVertically // left to make room for the taller button.
) { Row(verticalAlignment = Alignment.CenterVertically) {
Text( Column(modifier = Modifier.weight(1f)) {
text = pass.name, Row(
style = MaterialTheme.typography.bodyLarge, modifier = Modifier.fillMaxWidth(),
fontWeight = FontWeight.Medium, horizontalArrangement = Arrangement.SpaceBetween,
color = MaterialTheme.colorScheme.primary, verticalAlignment = Alignment.CenterVertically
modifier = Modifier.weight(1f) ) {
) Text(
Text( text = pass.name,
text = "${timeFormat.format(Date(pass.startTime))} - ${timeFormat.format(Date(pass.endTime))}", style = MaterialTheme.typography.bodyLarge,
style = MaterialTheme.typography.bodySmall, fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.primary,
) maxLines = 1,
// Radar shortcut, visible even on the collapsed card: icon only, overflow = TextOverflow.Ellipsis,
// rightmost position so the pass info shifts left. The card's own modifier = Modifier.weight(1f)
// click (expand) is not triggered by the IconButton's tap. )
IconButton(onClick = onNavigateToRadar) { Text(
text = "${timeFormat.format(Date(pass.startTime))} - ${timeFormat.format(Date(pass.endTime))}",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Spacer(Modifier.height(4.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = stringResource(R.string.mutual_elevation_you, pass.maxElevationA.toInt()),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.primary
)
Text(
text = stringResource(R.string.mutual_elevation_opposite, pass.maxElevationB.toInt()),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.tertiary
)
}
}
// Radar shortcut, visible even on the collapsed card: a taller
// button spanning both header rows. The card's own click
// (expand) is not triggered by the IconButton's tap.
IconButton(
onClick = onNavigateToRadar,
modifier = Modifier.size(48.dp)
) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_radar), painter = painterResource(id = R.drawable.ic_radar),
contentDescription = stringResource(R.string.mutual_open_radar), contentDescription = stringResource(R.string.mutual_open_radar),
modifier = Modifier.size(18.dp) modifier = Modifier.size(24.dp)
) )
} }
} }
Spacer(Modifier.height(4.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = stringResource(R.string.mutual_elevation_you, pass.maxElevationA.toInt()),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.primary
)
Text(
text = stringResource(R.string.mutual_elevation_opposite, pass.maxElevationB.toInt()),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.tertiary
)
}
AnimatedVisibility( AnimatedVisibility(
visible = isExpanded, visible = isExpanded,
@@ -116,4 +116,8 @@ class FakeSettingsRepo(initialPosition: GeoPos = GeoPos(23.13, 113.26)) : ISetti
override fun getRoamedGrids(): Set<String> = TODO() override fun getRoamedGrids(): Set<String> = TODO()
override fun setRoamedGrids(grids: Set<String>) = TODO() override fun setRoamedGrids(grids: Set<String>) = TODO()
override fun updateLoTWSettings(settings: LoTWSettings) = TODO() override fun updateLoTWSettings(settings: LoTWSettings) = TODO()
override fun getLastLotwSyncDate(): String = ""
override fun setLastLotwSyncDate(date: String) = Unit
override fun getLastLotwSyncCallsign(): String = ""
override fun setLastLotwSyncCallsign(callsign: String) = Unit
} }
@@ -101,14 +101,17 @@ fun RadarDestination(navigateUp: () -> Unit) {
} }
LaunchedEffect(mutualData.endTime) { LaunchedEffect(mutualData.endTime) {
if (mutualData.endTime <= 0L) return@LaunchedEffect if (mutualData.endTime <= 0L) return@LaunchedEffect
while (true) { // Auto-return only while the mutual pass is actually in progress. An
val remainingMs = mutualData.endTime - System.currentTimeMillis() // already-finished pass must NOT bounce the radar page back instantly
if (remainingMs <= 0L) { // (that made the pass-card radar shortcut look broken: tapping it while
navigateUpAndClearMutual() // the computed pass had ended returned to Mutual immediately).
return@LaunchedEffect var remainingMs = mutualData.endTime - System.currentTimeMillis()
} if (remainingMs <= 0L) return@LaunchedEffect
while (remainingMs > 0L) {
delay(remainingMs.coerceAtMost(1000L)) delay(remainingMs.coerceAtMost(1000L))
remainingMs = mutualData.endTime - System.currentTimeMillis()
} }
navigateUpAndClearMutual()
} }
// Sync actual permission state on every recomposition so it survives screen re-entry // Sync actual permission state on every recomposition so it survives screen re-entry
val hasPermission = ContextCompat.checkSelfPermission( val hasPermission = ContextCompat.checkSelfPermission(