From 609c83ed3488e58ea99a10514f4ec9ee84176e63 Mon Sep 17 00:00:00 2001 From: Arty Bishop Date: Sat, 9 Aug 2025 11:32:59 +0100 Subject: [PATCH] Implemented landscape support for MapScreen --- .../look4sat/presentation/MainTheme.kt | 2 +- .../presentation/common/Components.kt | 4 +- .../look4sat/presentation/map/MapScreen.kt | 99 +++++++++++++------ .../presentation/passes/PassesDialog.kt | 2 +- .../presentation/passes/PassesScreen.kt | 4 +- .../presentation/radar/RadarScreen.kt | 1 + .../satellites/SatellitesScreen.kt | 2 - .../presentation/settings/SettingsScreen.kt | 1 - app/src/main/res/values-ru/strings.xml | 1 - app/src/main/res/values-si/strings.xml | 1 - app/src/main/res/values-zh-rCN/strings.xml | 1 - app/src/main/res/values/strings.xml | 2 +- .../look4sat/data/repository/SatelliteRepo.kt | 15 +-- 13 files changed, 87 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/MainTheme.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/MainTheme.kt index ab77848f..0d46b0d9 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/MainTheme.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/MainTheme.kt @@ -113,7 +113,7 @@ private val darkScheme = darkColorScheme( // surfaceContainerHigh = Color(0xFF121212), surfaceContainerHighest = Color(0xFF242424), // filled card background surfaceContainerLow = Color(0xFF202020), // elevated card background -// surfaceContainerLowest = Color(0xFF121212), + surfaceContainerLowest = Color(0xCC121212), // surfaceDim = Color(0xFF121212), ) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/common/Components.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/common/Components.kt index 9215fb96..f0b83921 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/common/Components.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/common/Components.kt @@ -1,6 +1,7 @@ package com.rtbishop.look4sat.presentation.common import androidx.compose.foundation.background +import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -117,7 +118,8 @@ fun NextPassRow(pass: OrbitalPass, modifier: Modifier = Modifier) { text = pass.name, modifier = Modifier .weight(1f) - .padding(end = 6.dp), + .padding(end = 6.dp) + .basicMarquee(), fontWeight = FontWeight.Medium, maxLines = 1, overflow = TextOverflow.Ellipsis diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapScreen.kt index a1750e70..23f84b75 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/map/MapScreen.kt @@ -11,8 +11,12 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults import androidx.compose.material3.ElevatedCard import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -26,7 +30,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.AndroidView @@ -99,7 +102,11 @@ private fun MapScreen(uiState: State, mapView: MapView) { val rotateMod = Modifier.rotate(180f) val timeString = uiState.value.mapData?.aosTime ?: "00:00:00" val isTimeAos = uiState.value.mapData?.isTimeAos ?: true - val osmInfo = "© OpenStreetMap contributors" + LaunchedEffect(uiState.value.track) { + val latitude = uiState.value.track?.get(0)?.get(0)?.latitude ?: 0.0 + val longitude = uiState.value.track?.get(0)?.get(0)?.longitude ?: 0.0 + mapView.controller.animateTo(GeoPoint(latitude, longitude)) + } Column(modifier = Modifier.layoutPadding(), verticalArrangement = Arrangement.spacedBy(6.dp)) { if (isVerticalLayout()) { TopBar { @@ -118,50 +125,80 @@ private fun MapScreen(uiState: State, mapView: MapView) { } ElevatedCard(modifier = Modifier.weight(1f)) { Box(contentAlignment = Alignment.BottomCenter) { - LaunchedEffect(uiState.value.track) { - val latitude = uiState.value.track?.get(0)?.get(0)?.latitude ?: 0.0 - val longitude = uiState.value.track?.get(0)?.get(0)?.longitude ?: 0.0 - mapView.controller.animateTo(GeoPoint(latitude, longitude)) - } AndroidView({ mapView }) { mapView -> uiState.value.stationPosition?.let { setStationPosition(it, mapView) } uiState.value.positions?.let { setPositions(it, mapView, onItemClick) } uiState.value.track?.let { setSatelliteTrack(it, mapView) } uiState.value.footprint?.let { setFootprint(it, mapView) } } - Text(text = osmInfo, textAlign = TextAlign.Center, fontSize = 14.sp) - } - } - uiState.value.mapData?.let { mapData -> - ElevatedCard { - MapDataCard(mapData) + uiState.value.mapData?.let { mapData -> + if (isVerticalLayout()) MapDataCard(mapData) else MapDataCards(mapData) + } } } } } @Composable -private fun MapDataCard(mapData: MapData) { - Column(modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)) { - Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) { - Text(text = stringResource(R.string.map_period, mapData.period), color = MaterialTheme.colorScheme.primary) - Text(text = stringResource(R.string.map_phase, mapData.phase), color = MaterialTheme.colorScheme.primary) +private fun MapDataCard(data: MapData) { + val textColor = MaterialTheme.colorScheme.primary + val cardColors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceContainerLowest) + Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.SpaceBetween) { + Text(text = "© OpenStreetMap contributors", fontSize = 14.sp) + Card(colors = cardColors) { + Column(modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)) { + Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) { + Text(text = stringResource(R.string.map_azimuth, data.azimuth)) + Text(text = stringResource(R.string.map_elevation, data.elevation)) + } + Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) { + Text(text = stringResource(R.string.map_altitude, data.altitude), color = textColor) + Text(text = stringResource(R.string.map_distance, data.range), color = textColor) + } + Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) { + Text(text = stringResource(R.string.map_latitude, data.osmPos.latitude)) + Text(text = stringResource(R.string.map_longitude, data.osmPos.longitude)) + } + Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) { + Text(text = stringResource(R.string.map_qth, data.qthLoc), color = textColor) + Text(text = stringResource(R.string.map_phase, data.phase), color = textColor) + } + } } - Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) { - Text(text = stringResource(R.string.map_azimuth, mapData.azimuth)) - Text(text = stringResource(R.string.map_elevation, mapData.elevation)) + } +} + +@Composable +private fun MapDataCards(data: MapData) { + val cardColors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceContainerLowest) + val paddingMod = Modifier.padding(horizontal = 8.dp, vertical = 4.dp).width(160.dp) + val osmText = "© OpenStreetMap contributors" + val textColor = MaterialTheme.colorScheme.primary + Box(modifier = Modifier.fillMaxSize()) { + Card(colors = cardColors, modifier = Modifier.align(Alignment.TopStart)) { + Column(horizontalAlignment = Alignment.Start, modifier = paddingMod) { + Text(text = stringResource(R.string.map_azimuth, data.azimuth)) + Text(text = stringResource(R.string.map_elevation, data.elevation), color = textColor) + } } - Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) { - Text(text = stringResource(R.string.map_altitude, mapData.altitude), color = MaterialTheme.colorScheme.primary) - Text(text = stringResource(R.string.map_distance, mapData.range), color = MaterialTheme.colorScheme.primary) + Card(colors = cardColors, modifier = Modifier.align(Alignment.TopEnd)) { + Column(horizontalAlignment = Alignment.End, modifier = paddingMod) { + Text(text = stringResource(R.string.map_altitude, data.altitude)) + Text(text = stringResource(R.string.map_distance, data.range), color = textColor) + } } - Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) { - Text(text = stringResource(R.string.map_latitude, mapData.osmPos.latitude)) - Text(text = stringResource(R.string.map_longitude, mapData.osmPos.longitude)) + Card(colors = cardColors, modifier = Modifier.align(Alignment.BottomStart)) { + Column(horizontalAlignment = Alignment.Start, modifier = paddingMod) { + Text(text = stringResource(R.string.map_phase, data.phase)) + Text(text = stringResource(R.string.map_qth, data.qthLoc), color = textColor) + } } - Row(horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) { - Text(text = stringResource(R.string.map_qth, mapData.qthLoc), color = MaterialTheme.colorScheme.primary) - Text(text = stringResource(R.string.map_velocity, mapData.velocity), color = MaterialTheme.colorScheme.primary) + Text(text = osmText, fontSize = 14.sp, modifier = Modifier.align(Alignment.BottomCenter)) + Card(colors = cardColors, modifier = Modifier.align(Alignment.BottomEnd)) { + Column(horizontalAlignment = Alignment.End, modifier = paddingMod) { + Text(text = stringResource(R.string.map_latitude, data.osmPos.latitude)) + Text(text = stringResource(R.string.map_longitude, data.osmPos.longitude), color = textColor) + } } } } @@ -306,6 +343,8 @@ private fun getColorFilter(): ColorMatrixColorFilter { return ColorMatrixColorFilter(negative) } +@Composable private fun getMinZoom(screenHeight: Int): Double { + if (!isVerticalLayout()) return 3.5 return MapView.getTileSystem().getLatitudeZoom(maxLat, minLat, screenHeight) } diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesDialog.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesDialog.kt index 0f013a9b..3f6b51c0 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesDialog.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesDialog.kt @@ -148,7 +148,7 @@ fun RadiosDialog(modes: List, cancel: () -> Unit, accept: (List) val onAccept = { accept(selected.toList()).also { cancel() } } SharedDialog(title = "Radios", onCancel = cancel, onAccept = onAccept) { LazyVerticalGrid( - columns = GridCells.Fixed(1), + columns = GridCells.Adaptive(240.dp), modifier = Modifier .fillMaxHeight(0.69f) .background(MaterialTheme.colorScheme.background), diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt index c833faeb..3750c2ac 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passes/PassesScreen.kt @@ -1,6 +1,7 @@ package com.rtbishop.look4sat.presentation.passes import androidx.compose.foundation.background +import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -201,7 +202,8 @@ private fun NearEarthPass( text = pass.name, modifier = Modifier .weight(1f) - .padding(end = 6.dp), + .padding(end = 6.dp) + .basicMarquee(), fontWeight = FontWeight.Medium, maxLines = 1, overflow = TextOverflow.Ellipsis diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarScreen.kt index 1f57e29f..ed37390e 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/radar/RadarScreen.kt @@ -82,6 +82,7 @@ private fun RadarScreen(uiState: RadarState, navigateUp: () -> Unit) { } } val upcomingPass = uiState.currentPass ?: getDefaultPass() + if (upcomingPass.losTime < System.currentTimeMillis()) navigateUp() Column(modifier = Modifier.layoutPadding(), verticalArrangement = Arrangement.spacedBy(6.dp)) { if (isVerticalLayout()) { TopBar { diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/satellites/SatellitesScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/satellites/SatellitesScreen.kt index 52e6e127..40ced428 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/satellites/SatellitesScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/satellites/SatellitesScreen.kt @@ -13,11 +13,9 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.text.BasicTextField import androidx.compose.material3.CardDefaults import androidx.compose.material3.Checkbox diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsScreen.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsScreen.kt index 6d4b7b2a..1c79296f 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsScreen.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/settings/SettingsScreen.kt @@ -13,7 +13,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.material3.ElevatedCard diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index b0efc137..4c9c101b 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -117,7 +117,6 @@ Элевация: %.1f° Широта: %.1f° Долгота: %.1f° - QTH Локатор: %s Видимый В тени Видимость: %s diff --git a/app/src/main/res/values-si/strings.xml b/app/src/main/res/values-si/strings.xml index 9b4b3f62..56968caa 100644 --- a/app/src/main/res/values-si/strings.xml +++ b/app/src/main/res/values-si/strings.xml @@ -117,7 +117,6 @@ උත්තෝලනය: %.1f° අක්‍ෂාංශ: %.1f° දේශාංශ: %.1f° - QTH Locator: %s දෘශ්‍ය අදෘශ්‍ය දෘශ්‍යතාව: %s diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index deb32e76..68598fa9 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -117,7 +117,6 @@ 仰角:%.1f° 纬度:%.1f° 经度:%.1f° - QTH 网格:%s 日照中 地影中 能见度:%s diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 75a8ff0d..dd1abf7d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -130,7 +130,7 @@ Elevation: %.1f° Latitude: %.1f° Longitude: %.1f° - QTH Locator: %s + QTH: %s Visible Eclipsed Visibility: %s diff --git a/data/src/main/java/com/rtbishop/look4sat/data/repository/SatelliteRepo.kt b/data/src/main/java/com/rtbishop/look4sat/data/repository/SatelliteRepo.kt index 639b5188..78c84fdd 100644 --- a/data/src/main/java/com/rtbishop/look4sat/data/repository/SatelliteRepo.kt +++ b/data/src/main/java/com/rtbishop/look4sat/data/repository/SatelliteRepo.kt @@ -51,7 +51,8 @@ class SatelliteRepo( settingsRepo.selectedIds.collect { selectedIds -> _satellites.update { localStorage.getEntriesWithIds(selectedIds) } val (hoursAhead, minElevation, modes) = settingsRepo.passesSettings.value - calculatePasses(System.currentTimeMillis(), hoursAhead, minElevation, modes) + val timeNow = 1000 * ((System.currentTimeMillis() + 500) / 1000) + calculatePasses(timeNow, hoursAhead, minElevation, modes) } } @@ -195,10 +196,10 @@ class SatelliteRepo( } } while (satPos.elevation < 0.0) - // refine to 3 seconds + // refine to 1 second calendarTimeMillis += -60L * 1000L do { - calendarTimeMillis += 3L * 1000L + calendarTimeMillis += 1L * 500L satPos = sat.getPosition(pos, calendarTimeMillis) elevation = satPos.elevation if (elevation > maxElevation) { @@ -207,7 +208,7 @@ class SatelliteRepo( } } while (satPos.elevation < 0.0) - val aos = satPos.time + val aos = 1000 * ((satPos.time + 500) / 1000) val aosAz = satPos.azimuth.toDegrees().round(1) // find when sat goes below @@ -221,10 +222,10 @@ class SatelliteRepo( } } while (satPos.elevation > 0.0) - // refine to 3 seconds + // refine to 1 second calendarTimeMillis += -30L * 1000L do { - calendarTimeMillis += 3L * 1000L + calendarTimeMillis += 1L * 500L satPos = sat.getPosition(pos, calendarTimeMillis) elevation = satPos.elevation if (elevation > maxElevation) { @@ -233,7 +234,7 @@ class SatelliteRepo( } } while (satPos.elevation > 0.0) - val los = satPos.time // val tca = (aos + los) / 2 + val los = 1000 * ((satPos.time + 500) / 1000) // val tca = (aos + los) / 2 val losAz = satPos.azimuth.toDegrees().round(1) val elev = maxElevation.toDegrees().round(1) return OrbitalPass(aos, aosAz, los, losAz, alt.toInt(), elev, sat)