Implemented a basic map data card on MapScreen

This commit is contained in:
Arty Bishop committed 2025-12-27 15:01:47 +00:00
1 parent 880fe10bfd
commit fdbdc513f1
12 files changed
+102 -65

No files matched your search

+3 -4
View File
@@ -14,11 +14,10 @@ android {
compileSdk = 35
defaultConfig {
applicationId = "com.rtbishop.look4sat"
minSdk = 26
minSdk = 24
targetSdk = 35
versionCode = 314
versionName = "3.1.4"
resourceConfigurations.addAll(listOf("en", "ru", "si", "zh-rCN", "anydpi"))
versionCode = 400
versionName = "4.0.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildFeatures {
-14
View File
@@ -1,14 +0,0 @@
# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**
# A resource is loaded with a relative path so the package of this class must be preserved.
-adaptresourcefilenames okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*
# OkHttp platform used only on JVM and when Conscrypt and other security providers are available.
-dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**
@@ -10,18 +10,26 @@ import android.graphics.Rect
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
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
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
@@ -86,6 +94,7 @@ private fun MapScreen(uiState: State<MapState>) {
val rotateMod = Modifier.rotate(180f)
val timeString = uiState.value.mapData?.aosTime ?: "00:00:00"
val isTimeAos = uiState.value.mapData?.isTimeAos ?: true
val osmInfo = "Wikimedia maps | Map data © OpenStreetMap contributors"
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
TimerRow {
CardIcon(onClick = selectPrev, iconId = R.drawable.ic_arrow, modifier = rotateMod)
@@ -93,14 +102,48 @@ private fun MapScreen(uiState: State<MapState>) {
CardIcon(onClick = selectNext, iconId = R.drawable.ic_arrow)
}
NextPassRow(pass = uiState.value.orbitalPass)
ElevatedCard(modifier = Modifier.fillMaxSize()) {
MapView(modifier = Modifier.fillMaxSize(), isLightUi = uiState.value.isLightUi) { 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) }
ElevatedCard(modifier = Modifier.weight(1f)) {
Box(contentAlignment = Alignment.BottomCenter) {
MapView(isLightUi = uiState.value.isLightUi) { 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)
}
}
}
}
@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)
}
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))
}
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)
}
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))
}
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)
}
}
}
@@ -195,30 +238,6 @@ private fun setFootprint(orbitalPos: OrbitalPos, mapView: MapView) {
}
}
//private fun handleMapData(mapData: MapData) {
// binding.apply {
// mapTimer.text = mapData.aosTime
// mapDataPeriod.text = String.format(getString(R.string.map_period, mapData.period))
// mapDataPhase.text = String.format(getString(R.string.map_phase), mapData.phase)
// mapAzimuth.text = String.format(getString(R.string.map_azimuth), mapData.azimuth)
// mapElevation.text = String.format(getString(R.string.map_elevation), mapData.elevation)
// mapDataAlt.text = String.format(getString(R.string.map_altitude), mapData.altitude)
// mapDataDst.text = String.format(getString(R.string.map_distance), mapData.range)
// mapDataLat.text =
// String.format(getString(R.string.map_latitude), mapData.osmPos.lat)
// mapDataLon.text =
// String.format(getString(R.string.map_longitude), mapData.osmPos.lon)
// mapDataQth.text = String.format(getString(R.string.map_qth), mapData.qthLoc)
// mapDataVel.text = String.format(getString(R.string.map_velocity), mapData.velocity)
// if (mapData.eclipsed) {
// mapDataVisibility.text = getString(R.string.map_eclipsed)
// } else {
// mapDataVisibility.text = getString(R.string.map_visible)
// }
// }
// binding.mapView.invalidate()
//}
@Composable
private fun MapView(
modifier: Modifier = Modifier,
@@ -237,9 +256,10 @@ private fun rememberMapViewWithLifecycle(isLightTheme: Boolean): MapView {
setMultiTouchControls(true)
setUseDataConnection(false)
setTileSource(tileSource)
minZoomLevel = getMinZoom(resources.displayMetrics.heightPixels) + 0.25
maxZoomLevel = 8.0
controller.setZoom(minZoomLevel + 1)
minZoomLevel = getMinZoom(resources.displayMetrics.heightPixels)
maxZoomLevel = 7.0
controller.setCenter(GeoPoint(48.8575, 6.3514))
controller.setZoom(minZoomLevel + 2)
zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
overlayManager.tilesOverlay.loadingBackgroundColor = Color.TRANSPARENT
overlayManager.tilesOverlay.loadingLineColor = Color.TRANSPARENT
@@ -1,8 +1,15 @@
package com.rtbishop.look4sat.presentation.radar
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.MarqueeSpacing
import androidx.compose.foundation.background
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -23,6 +30,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
@@ -80,7 +88,7 @@ private fun RadarScreen(uiState: RadarState, navigateBack: () -> Unit) {
CardIcon(onClick = addToCalendar, iconId = R.drawable.ic_calendar)
}
NextPassRow(pass = uiState.currentPass ?: getDefaultPass())
Box(contentAlignment = Alignment.Center, modifier = Modifier.aspectRatio(1f)) {
Box(contentAlignment = Alignment.BottomCenter, modifier = Modifier.aspectRatio(1f)) {
uiState.orbitalPos?.let { position ->
ElevatedCard {
RadarViewCompose(
@@ -127,6 +135,30 @@ private fun RadarScreen(uiState: RadarState, navigateBack: () -> Unit) {
)
}
}
if (uiState.orbitalPos.eclipsed) {
val infiniteTransition = rememberInfiniteTransition()
val textAlpha = infiniteTransition.animateFloat(
initialValue = 1.0f,
targetValue = 0.0f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 500,
delayMillis = 25,
easing = LinearEasing
),
repeatMode = RepeatMode.Reverse
))
Text(
text = "Eclipsed!",
fontSize = 18.sp,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier
.alpha(textAlpha.value)
.border(2.dp, MaterialTheme.colorScheme.primary, MaterialTheme.shapes.medium)
.padding(16.dp)
)
}
}
}
ElevatedCard(modifier = Modifier.fillMaxSize()) {
@@ -53,7 +53,7 @@ fun RadarViewCompose(
val radarColor = MaterialTheme.colorScheme.secondary
val trackColor = MaterialTheme.colorScheme.primary
val aimColor = MaterialTheme.colorScheme.error
val strokeWidth = 4f
val strokeWidth = 6f
val animTransition = rememberInfiniteTransition(label = "animScale")
val animSpec = infiniteRepeatable<Float>(tween(1000))
val animScale = animTransition.animateFloat(16f, 64f, animSpec, label = "animScale")
@@ -167,7 +167,7 @@ private fun DrawScope.drawInfo(radius: Float, color: Color, measurer: TextMeasur
}
private fun DrawScope.drawTrack(path: Path, effect: PathEffect, color: Color, effectColor: Color) {
drawPath(path, color, style = Stroke(4f))
drawPath(path, color, style = Stroke(6f))
drawPath(path, effectColor, style = Stroke(pathEffect = effect))
}
@@ -213,7 +213,7 @@ private fun createTrackPath(positions: List<OrbitalPos>, radius: Float): Path {
private fun createTrackEffect(trackPath: Path): PathEffect {
val shape = Path()
val shapeRadius = 16f
val shapeRadius = 24f
val angle = 120.0.toRadians()
shape.moveTo((shapeRadius * cos(angle)).toFloat(), (shapeRadius * sin(angle)).toFloat())
for (i in 1 until 3) {
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB