mirror of
https://github.com/rt-bishop/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Implemented a basic map data card on MapScreen
This commit is contained in:
1 parent
880fe10bfd
commit
fdbdc513f1
12 files changed
+98
-61
No files matched your search
@@ -14,11 +14,10 @@ android {
|
|||||||
compileSdk = 35
|
compileSdk = 35
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "com.rtbishop.look4sat"
|
applicationId = "com.rtbishop.look4sat"
|
||||||
minSdk = 26
|
minSdk = 24
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 314
|
versionCode = 400
|
||||||
versionName = "3.1.4"
|
versionName = "4.0.0"
|
||||||
resourceConfigurations.addAll(listOf("en", "ru", "si", "zh-rCN", "anydpi"))
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
|
|||||||
Vendored
-14
@@ -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.BitmapDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
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.foundation.layout.padding
|
||||||
import androidx.compose.material3.ElevatedCard
|
import androidx.compose.material3.ElevatedCard
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.rotate
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.platform.LocalContext
|
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.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
@@ -86,6 +94,7 @@ private fun MapScreen(uiState: State<MapState>) {
|
|||||||
val rotateMod = Modifier.rotate(180f)
|
val rotateMod = Modifier.rotate(180f)
|
||||||
val timeString = uiState.value.mapData?.aosTime ?: "00:00:00"
|
val timeString = uiState.value.mapData?.aosTime ?: "00:00:00"
|
||||||
val isTimeAos = uiState.value.mapData?.isTimeAos ?: true
|
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)) {
|
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
TimerRow {
|
TimerRow {
|
||||||
CardIcon(onClick = selectPrev, iconId = R.drawable.ic_arrow, modifier = rotateMod)
|
CardIcon(onClick = selectPrev, iconId = R.drawable.ic_arrow, modifier = rotateMod)
|
||||||
@@ -93,13 +102,47 @@ private fun MapScreen(uiState: State<MapState>) {
|
|||||||
CardIcon(onClick = selectNext, iconId = R.drawable.ic_arrow)
|
CardIcon(onClick = selectNext, iconId = R.drawable.ic_arrow)
|
||||||
}
|
}
|
||||||
NextPassRow(pass = uiState.value.orbitalPass)
|
NextPassRow(pass = uiState.value.orbitalPass)
|
||||||
ElevatedCard(modifier = Modifier.fillMaxSize()) {
|
ElevatedCard(modifier = Modifier.weight(1f)) {
|
||||||
MapView(modifier = Modifier.fillMaxSize(), isLightUi = uiState.value.isLightUi) { mapView ->
|
Box(contentAlignment = Alignment.BottomCenter) {
|
||||||
|
MapView(isLightUi = uiState.value.isLightUi) { mapView ->
|
||||||
uiState.value.stationPosition?.let { setStationPosition(it, mapView) }
|
uiState.value.stationPosition?.let { setStationPosition(it, mapView) }
|
||||||
uiState.value.positions?.let { setPositions(it, mapView, onItemClick) }
|
uiState.value.positions?.let { setPositions(it, mapView, onItemClick) }
|
||||||
uiState.value.track?.let { setSatelliteTrack(it, mapView) }
|
uiState.value.track?.let { setSatelliteTrack(it, mapView) }
|
||||||
uiState.value.footprint?.let { setFootprint(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
|
@Composable
|
||||||
private fun MapView(
|
private fun MapView(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
@@ -237,9 +256,10 @@ private fun rememberMapViewWithLifecycle(isLightTheme: Boolean): MapView {
|
|||||||
setMultiTouchControls(true)
|
setMultiTouchControls(true)
|
||||||
setUseDataConnection(false)
|
setUseDataConnection(false)
|
||||||
setTileSource(tileSource)
|
setTileSource(tileSource)
|
||||||
minZoomLevel = getMinZoom(resources.displayMetrics.heightPixels) + 0.25
|
minZoomLevel = getMinZoom(resources.displayMetrics.heightPixels)
|
||||||
maxZoomLevel = 8.0
|
maxZoomLevel = 7.0
|
||||||
controller.setZoom(minZoomLevel + 1)
|
controller.setCenter(GeoPoint(48.8575, 6.3514))
|
||||||
|
controller.setZoom(minZoomLevel + 2)
|
||||||
zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
|
zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
|
||||||
overlayManager.tilesOverlay.loadingBackgroundColor = Color.TRANSPARENT
|
overlayManager.tilesOverlay.loadingBackgroundColor = Color.TRANSPARENT
|
||||||
overlayManager.tilesOverlay.loadingLineColor = Color.TRANSPARENT
|
overlayManager.tilesOverlay.loadingLineColor = Color.TRANSPARENT
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
package com.rtbishop.look4sat.presentation.radar
|
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.MarqueeSpacing
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.basicMarquee
|
import androidx.compose.foundation.basicMarquee
|
||||||
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -23,6 +30,7 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.rotate
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.painterResource
|
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)
|
CardIcon(onClick = addToCalendar, iconId = R.drawable.ic_calendar)
|
||||||
}
|
}
|
||||||
NextPassRow(pass = uiState.currentPass ?: getDefaultPass())
|
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 ->
|
uiState.orbitalPos?.let { position ->
|
||||||
ElevatedCard {
|
ElevatedCard {
|
||||||
RadarViewCompose(
|
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()) {
|
ElevatedCard(modifier = Modifier.fillMaxSize()) {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ fun RadarViewCompose(
|
|||||||
val radarColor = MaterialTheme.colorScheme.secondary
|
val radarColor = MaterialTheme.colorScheme.secondary
|
||||||
val trackColor = MaterialTheme.colorScheme.primary
|
val trackColor = MaterialTheme.colorScheme.primary
|
||||||
val aimColor = MaterialTheme.colorScheme.error
|
val aimColor = MaterialTheme.colorScheme.error
|
||||||
val strokeWidth = 4f
|
val strokeWidth = 6f
|
||||||
val animTransition = rememberInfiniteTransition(label = "animScale")
|
val animTransition = rememberInfiniteTransition(label = "animScale")
|
||||||
val animSpec = infiniteRepeatable<Float>(tween(1000))
|
val animSpec = infiniteRepeatable<Float>(tween(1000))
|
||||||
val animScale = animTransition.animateFloat(16f, 64f, animSpec, label = "animScale")
|
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) {
|
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))
|
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 {
|
private fun createTrackEffect(trackPath: Path): PathEffect {
|
||||||
val shape = Path()
|
val shape = Path()
|
||||||
val shapeRadius = 16f
|
val shapeRadius = 24f
|
||||||
val angle = 120.0.toRadians()
|
val angle = 120.0.toRadians()
|
||||||
shape.moveTo((shapeRadius * cos(angle)).toFloat(), (shapeRadius * sin(angle)).toFloat())
|
shape.moveTo((shapeRadius * cos(angle)).toFloat(), (shapeRadius * sin(angle)).toFloat())
|
||||||
for (i in 1 until 3) {
|
for (i in 1 until 3) {
|
||||||
|
|||||||
File renamed without changes.
File renamed without changes.
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
@@ -12,7 +12,7 @@ android {
|
|||||||
namespace = "com.rtbishop.look4sat.data"
|
namespace = "com.rtbishop.look4sat.data"
|
||||||
compileSdk = 35
|
compileSdk = 35
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 26
|
minSdk = 24
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[versions]
|
[versions]
|
||||||
android-gradle-plugin = "8.7.3"
|
android-gradle-plugin = "8.8.0"
|
||||||
google-ksp = "2.0.21-1.0.26"
|
google-ksp = "2.0.21-1.0.26"
|
||||||
kotlin = "2.0.21"
|
kotlin = "2.0.21"
|
||||||
|
|
||||||
@@ -7,18 +7,18 @@ androidx-core-ktx = "1.15.0"
|
|||||||
androidx-core-splashscreen = "1.0.1"
|
androidx-core-splashscreen = "1.0.1"
|
||||||
androidx-room = "2.6.1"
|
androidx-room = "2.6.1"
|
||||||
|
|
||||||
compose-bom = "2024.11.00"
|
compose-bom = "2025.01.00"
|
||||||
compose-activity = "1.9.3"
|
compose-activity = "1.10.0"
|
||||||
compose-lifecycle = "2.8.7"
|
compose-lifecycle = "2.8.7"
|
||||||
compose-navigation = "2.8.4"
|
compose-navigation = "2.8.5"
|
||||||
|
|
||||||
other-coroutines = "1.9.0"
|
other-coroutines = "1.10.1"
|
||||||
other-json = "20240303"
|
other-json = "20240303"
|
||||||
other-okhttp = "4.12.0"
|
other-okhttp = "4.12.0"
|
||||||
other-osmdroid = "6.1.20"
|
other-osmdroid = "6.1.20"
|
||||||
|
|
||||||
test-junit4 = "4.13.2"
|
test-junit4 = "4.13.2"
|
||||||
test-mockk = "1.13.13"
|
test-mockk = "1.13.14"
|
||||||
|
|
||||||
androidTest-junit = "1.2.1"
|
androidTest-junit = "1.2.1"
|
||||||
androidTest-espresso = "3.6.1"
|
androidTest-espresso = "3.6.1"
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
#Fri Oct 25 23:59:14 BST 2024
|
#Sat Jan 04 21:11:19 GMT 2025
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
Reference in new issue
Block a user