fix: sync dialogs use typed values directly (save+sync in one step); LoTW card wording; center map on station grid when entering grid mode; center grid labels in cells; update-check falls back to GitHub accelerator mirrors

This commit is contained in:
atsunatsu committed 2026-09-07 07:22:41 +08:00
1 parent be6473e692
commit c7ca77a943
10 files changed
+113 -43

No files matched your search

@@ -124,8 +124,8 @@ class MaidenheadGridOverlay : Overlay() {
canvas.drawLine(0f, y, canvas.width.toFloat(), y, linePaint)
}
// Labels: place at the top-left corner of each cell, only when the cell
// is large enough on screen to hold a label (avoid clutter at low zoom)
// Labels: centered in each cell, only when the cell is large enough on
// screen to hold a label (avoid clutter at low zoom)
val showLabels = when {
zoom >= GRID_ZOOM_SUB -> true
zoom >= FIELD_ZOOM_LABELS -> true
@@ -140,20 +140,25 @@ class MaidenheadGridOverlay : Overlay() {
val pixelsPerDegree = Math.abs(y2 - y1)
if (pixelsPerDegree * cellLat < MIN_LABEL_CELL_PX) return
val labelOffset = 8f
labelPaint.textAlign = Paint.Align.CENTER
val fontMetrics = labelPaint.fontMetrics
val textHalfHeight = (fontMetrics.descent + fontMetrics.ascent) / 2f
for (row in firstRow..lastRow) {
val lat = row * cellLat
if (lat < -90.0 || lat >= 90.0) continue
val topLatCell = lat + cellLat
if (topLatCell > 90.0) continue
val y = projectionToY(projection, topLatCell) ?: continue
if (y < -labelPaint.textSize || y > canvas.height) continue
val yTop = projectionToY(projection, topLatCell) ?: continue
val yBottom = projectionToY(projection, lat) ?: continue
val yCenter = (yTop + yBottom) / 2f - textHalfHeight
if (yBottom < 0f || yTop > canvas.height) continue
for (col in firstCol..lastCol) {
val lon = col * cellLon
val x = projectionToX(projection, lon, centerLon) ?: continue
if (x < -200f || x > canvas.width) continue
val xLeft = projectionToX(projection, lon, centerLon) ?: continue
val xRight = projectionToX(projection, lon + cellLon, centerLon) ?: continue
if (xRight < 0f || xLeft > canvas.width) continue
val label = cellLabel(lat, lon, zoom)
canvas.drawText(label, x + labelOffset, y + labelPaint.textSize + labelOffset, labelPaint)
canvas.drawText(label, (xLeft + xRight) / 2f, yCenter, labelPaint)
}
}
}
@@ -42,7 +42,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
@@ -159,8 +161,15 @@ private fun MapScreen(uiState: MapState, onAction: (MapAction) -> Unit, mapView:
}
ElevatedCard(modifier = Modifier.weight(1f)) {
Box(contentAlignment = Alignment.BottomCenter) {
// Track grid-mode transitions so the map only re-centers when the
// mode is switched ON, not on every recomposition.
var prevGridMode by remember { mutableStateOf(uiState.isGridMode) }
AndroidView({ mapView }) { view ->
setGridMode(uiState.isGridMode, uiState.workedGrids, view)
setGridMode(
uiState.isGridMode, uiState.workedGrids, view,
if (uiState.isGridMode && !prevGridMode) uiState.stationPosition else null
)
prevGridMode = uiState.isGridMode
if (!uiState.isGridMode) {
uiState.stationPosition?.let { setStationPosition(it, view) }
uiState.track?.let { setSatelliteTrack(it, view) }
@@ -269,7 +278,12 @@ private fun MapDataCards(data: MapData) {
// region Map overlay helpers
/** Toggle the grid-mode layer visibility on/off without recreating any overlay. */
private fun setGridMode(gridMode: Boolean, workedGrids: Set<String>, mapView: MapView) {
private fun setGridMode(
gridMode: Boolean,
workedGrids: Set<String>,
mapView: MapView,
stationPosition: GeoPos?
) {
try {
val gridOverlay = mapView.overlays[OVERLAY_GRID]
if (gridOverlay is MaidenheadGridOverlay) {
@@ -286,6 +300,18 @@ private fun setGridMode(gridMode: Boolean, workedGrids: Set<String>, mapView: Ma
for (index in OVERLAY_STATION..OVERLAY_MOON) {
mapView.overlays.getOrNull(index)?.isEnabled = !gridMode
}
// Entering grid mode: center on the station's current grid square,
// keeping the current zoom level unchanged.
if (gridMode) {
val pos = stationPosition ?: return
val lat = pos.latitude
val lon = pos.longitude
val fieldLat = ((lat + 90.0) / 10.0).toInt().coerceIn(0, 17)
val fieldLon = ((lon + 180.0) / 20.0).toInt().coerceIn(0, 17)
val centerLat = fieldLat * 10.0 + 5.0
val centerLon = fieldLon * 20.0 + 10.0
mapView.controller.setCenter(GeoPoint(centerLat, centerLon))
}
} catch (e: Exception) {
println(e)
}
@@ -84,6 +84,7 @@ class MapViewModel(
}
val (selectedCatNum, _) = satelliteRepo.selectedPass.value
selectDefaultSatellite(if (selectedCatNum != 0) selectedCatNum else -1)
getStationPosition()
}
fun onAction(action: MapAction) {