mirror of
https://github.com/rt-bishop/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Added navigation parameters to RadarScreen
This commit is contained in:
1 parent
049d84e261
commit
05b5af41ba
5 files changed
+308
-43
No files matched your search
@@ -39,6 +39,7 @@ import androidx.navigation.compose.NavHost
|
|||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import androidx.navigation.navArgument
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.presentation.entriesScreen.EntriesScreen
|
import com.rtbishop.look4sat.presentation.entriesScreen.EntriesScreen
|
||||||
import com.rtbishop.look4sat.presentation.mapScreen.MapScreen
|
import com.rtbishop.look4sat.presentation.mapScreen.MapScreen
|
||||||
@@ -89,7 +90,7 @@ private fun MainNavBar(navController: NavController) {
|
|||||||
val navBackStackEntry = navController.currentBackStackEntryAsState()
|
val navBackStackEntry = navController.currentBackStackEntryAsState()
|
||||||
val currentRoute = navBackStackEntry.value?.destination?.route
|
val currentRoute = navBackStackEntry.value?.destination?.route
|
||||||
items.forEach { item ->
|
items.forEach { item ->
|
||||||
NavigationBarItem(selected = currentRoute == item.route, onClick = {
|
NavigationBarItem(selected = currentRoute?.contains(item.route) ?: false, onClick = {
|
||||||
navController.navigate(item.route) {
|
navController.navigate(item.route) {
|
||||||
navController.graph.startDestinationRoute?.let { route ->
|
navController.graph.startDestinationRoute?.let { route ->
|
||||||
popUpTo(route) { saveState = false }
|
popUpTo(route) { saveState = false }
|
||||||
@@ -104,10 +105,13 @@ private fun MainNavBar(navController: NavController) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun MainNavGraph(navController: NavHostController) {
|
private fun MainNavGraph(navController: NavHostController) {
|
||||||
|
val radarRoute = "${Screen.Radar.route}?catNum={catNum}&aosTime={aosTime}"
|
||||||
|
val radarArgs = listOf(navArgument("catNum") { defaultValue = 0 },
|
||||||
|
navArgument("aosTime") { defaultValue = 0L })
|
||||||
NavHost(navController, startDestination = Screen.Passes.route) {
|
NavHost(navController, startDestination = Screen.Passes.route) {
|
||||||
composable(Screen.Entries.route) { EntriesScreen(navController) }
|
composable(Screen.Entries.route) { EntriesScreen(navController) }
|
||||||
composable(Screen.Passes.route) { PassesScreen(navController) }
|
composable(Screen.Passes.route) { PassesScreen(navController) }
|
||||||
composable(Screen.Radar.route) { RadarScreen() }
|
composable(radarRoute, radarArgs) { RadarScreen(navController) }
|
||||||
composable(Screen.Map.route) { MapScreen() }
|
composable(Screen.Map.route) { MapScreen() }
|
||||||
composable(Screen.Settings.route) { SettingsScreen(navController) }
|
composable(Screen.Settings.route) { SettingsScreen(navController) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,9 @@ private val sdf = SimpleDateFormat("HH:mm:ss", Locale.ENGLISH)
|
|||||||
@Composable
|
@Composable
|
||||||
fun PassesScreen(navController: NavController) {
|
fun PassesScreen(navController: NavController) {
|
||||||
val viewModel: PassesViewModel = hiltViewModel()
|
val viewModel: PassesViewModel = hiltViewModel()
|
||||||
val navToRadar = { navController.navigate(Screen.Radar.route) }
|
val navToRadar = { catNum: Int, aosTime: Long ->
|
||||||
|
navController.navigate("${Screen.Radar.route}?catNum=${catNum}&aosTime=${aosTime}")
|
||||||
|
}
|
||||||
val state = viewModel.passes.collectAsState(initial = null)
|
val state = viewModel.passes.collectAsState(initial = null)
|
||||||
val timerText = viewModel.timerText.collectAsState(initial = null)
|
val timerText = viewModel.timerText.collectAsState(initial = null)
|
||||||
val isRefreshing = state.value is DataState.Loading
|
val isRefreshing = state.value is DataState.Loading
|
||||||
@@ -105,15 +107,15 @@ private fun PassPreview() {
|
|||||||
)
|
)
|
||||||
val satellite = NearEarthSat(data)
|
val satellite = NearEarthSat(data)
|
||||||
val pass = SatPass(1L, 25.0, 10L, 75.0, 850, 45.0, satellite, 0.5f)
|
val pass = SatPass(1L, 25.0, 10L, 75.0, 850, 45.0, satellite, 0.5f)
|
||||||
MainTheme { Pass(pass = pass, {}) }
|
MainTheme { Pass(pass = pass, { _,_ -> }) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Pass(pass: SatPass, navToRadar: () -> Unit, modifier: Modifier = Modifier) {
|
private fun Pass(pass: SatPass, navToRadar: (Int, Long) -> Unit, modifier: Modifier = Modifier) {
|
||||||
Surface(color = MaterialTheme.colorScheme.background, modifier = modifier) {
|
Surface(color = MaterialTheme.colorScheme.background, modifier = modifier) {
|
||||||
Surface(modifier = Modifier
|
Surface(modifier = Modifier
|
||||||
.padding(bottom = 2.dp)
|
.padding(bottom = 2.dp)
|
||||||
.clickable { navToRadar() }) {
|
.clickable { navToRadar(pass.catNum, pass.aosTime) }) {
|
||||||
Column(
|
Column(
|
||||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -202,7 +204,7 @@ private fun PassesCard(
|
|||||||
refreshState: PullRefreshState,
|
refreshState: PullRefreshState,
|
||||||
isRefreshing: Boolean,
|
isRefreshing: Boolean,
|
||||||
passes: List<SatPass>,
|
passes: List<SatPass>,
|
||||||
navToRadar: () -> Unit
|
navToRadar: (Int, Long) -> Unit
|
||||||
) {
|
) {
|
||||||
ElevatedCard(modifier = Modifier.fillMaxSize()) {
|
ElevatedCard(modifier = Modifier.fillMaxSize()) {
|
||||||
Box(Modifier.pullRefresh(refreshState)) {
|
Box(Modifier.pullRefresh(refreshState)) {
|
||||||
|
|||||||
@@ -1,20 +1,35 @@
|
|||||||
package com.rtbishop.look4sat.presentation.radarScreen
|
package com.rtbishop.look4sat.presentation.radarScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
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.unit.sp
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
|
import com.rtbishop.look4sat.domain.model.SatRadio
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RadarScreen(viewModel: RadarViewModel = hiltViewModel()) {
|
fun RadarScreen(navController: NavController) {
|
||||||
|
val viewModel: RadarViewModel = hiltViewModel()
|
||||||
|
val currentPass = viewModel.getPass().collectAsState(null)
|
||||||
|
val radarData = viewModel.radarData.collectAsState()
|
||||||
|
val transmitters = viewModel.transmitters.collectAsState()
|
||||||
|
val orientation = viewModel.orientation.collectAsState()
|
||||||
|
|
||||||
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
ElevatedCard(modifier = Modifier.height(52.dp)) {
|
ElevatedCard(modifier = Modifier.height(52.dp)) {
|
||||||
@@ -47,11 +62,106 @@ fun RadarScreen(viewModel: RadarViewModel = hiltViewModel()) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ElevatedCard(modifier = Modifier.fillMaxSize().weight(1f)) {
|
ElevatedCard(modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.weight(1f)) {
|
||||||
|
// val context = LocalContext.current
|
||||||
|
// AndroidView({ RadarView(context) }, modifier = Modifier.fillMaxSize()) { radarView ->
|
||||||
|
// Timber.d("Radar view recomposition")
|
||||||
|
// radarView.setShowAim(true)
|
||||||
|
// radarView.setScanning(true)
|
||||||
|
// radarData.value?.let {
|
||||||
|
// radarView.setPosition(it.satPos)
|
||||||
|
// radarView.setPositions(it.satTrack)
|
||||||
|
// }
|
||||||
|
// orientation.value?.let {
|
||||||
|
// radarView.setOrientation(it.first, it.second, it.first)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
radarData.value?.let { data ->
|
||||||
|
orientation.value?.let { triple ->
|
||||||
|
RadarViewCompose(
|
||||||
|
item = data.satPos,
|
||||||
|
items = data.satTrack,
|
||||||
|
orientation = triple
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ElevatedCard(modifier = Modifier.fillMaxSize().weight(1f)) {
|
ElevatedCard(modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.weight(1f)) {
|
||||||
|
TransmittersList(transmitters = transmitters.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TransmittersList(transmitters: List<SatRadio>) {
|
||||||
|
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||||
|
items(items = transmitters, key = { item -> item.uuid }) { radio ->
|
||||||
|
TransmitterItem(radio)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TransmitterItem(radio: SatRadio) {
|
||||||
|
Surface(color = MaterialTheme.colorScheme.background) {
|
||||||
|
Surface(modifier = Modifier.padding(bottom = 2.dp)) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||||
|
modifier = Modifier
|
||||||
|
.background(MaterialTheme.colorScheme.surface)
|
||||||
|
.padding(6.dp)
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_prev),
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = radio.info,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_next),
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.radio_downlink, radio.downlink ?: 0L),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = 15.sp,
|
||||||
|
modifier = Modifier.weight(0.5f)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.radio_uplink, radio.uplink ?: 0L),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = 15.sp,
|
||||||
|
modifier = Modifier.weight(0.5f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = radio.mode ?: "",
|
||||||
|
fontSize = 15.sp
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = radio.isInverted.toString(),
|
||||||
|
fontSize = 15.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,29 +183,9 @@ fun RadarScreen(viewModel: RadarViewModel = hiltViewModel()) {
|
|||||||
// radarView?.setPositions(passData.satTrack)
|
// radarView?.setPositions(passData.satTrack)
|
||||||
// setPassText(pass, passData.satPos)
|
// setPassText(pass, passData.satPos)
|
||||||
// }
|
// }
|
||||||
// viewModel.transmitters.observe(viewLifecycleOwner) { list ->
|
|
||||||
// if (list.isNotEmpty()) {
|
|
||||||
// radioAdapter.submitList(list)
|
|
||||||
// radarProgress.visibility = View.INVISIBLE
|
|
||||||
// } else {
|
|
||||||
// radarProgress.visibility = View.INVISIBLE
|
|
||||||
// radarEmptyLayout.visibility = View.VISIBLE
|
|
||||||
// }
|
|
||||||
// radarView?.invalidate()
|
|
||||||
// }
|
|
||||||
// viewModel.orientation.observe(viewLifecycleOwner) { value ->
|
// viewModel.orientation.observe(viewLifecycleOwner) { value ->
|
||||||
// radarView?.setOrientation(value.first, value.second, value.third)
|
// radarView?.setOrientation(value.first, value.second, value.third)
|
||||||
// }
|
// }
|
||||||
// radarBtnBack.clickWithDebounce { findNavController().navigateUp() }
|
|
||||||
// radarBtnMap.clickWithDebounce {
|
|
||||||
// val direction = RadarFragmentDirections.globalToMap(pass.catNum)
|
|
||||||
// findNavController().navigate(direction)
|
|
||||||
// }
|
|
||||||
// radarBtnNotify.isEnabled = false
|
|
||||||
// radarBtnSettings.clickWithDebounce {
|
|
||||||
// val direction = RadarFragmentDirections.globalToSettings()
|
|
||||||
// findNavController().navigate(direction)
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|||||||
@@ -0,0 +1,155 @@
|
|||||||
|
@file:OptIn(ExperimentalTextApi::class)
|
||||||
|
|
||||||
|
package com.rtbishop.look4sat.presentation.radarScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Canvas
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.*
|
||||||
|
import androidx.compose.ui.graphics.drawscope.*
|
||||||
|
import androidx.compose.ui.text.*
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.rtbishop.look4sat.domain.predict.PI_2
|
||||||
|
import com.rtbishop.look4sat.domain.predict.SatPos
|
||||||
|
import com.rtbishop.look4sat.domain.predict.TWO_PI
|
||||||
|
import com.rtbishop.look4sat.utility.toRadians
|
||||||
|
import kotlin.math.cos
|
||||||
|
import kotlin.math.sin
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RadarViewCompose(item: SatPos, items: List<SatPos>, orientation: Triple<Float, Float, Float>) {
|
||||||
|
val measurer = rememberTextMeasurer()
|
||||||
|
val newTrackPath = remember { mutableStateOf(Path()) }
|
||||||
|
val newArrowPath = remember { mutableStateOf(Path()) }
|
||||||
|
var isTrackCreated = false
|
||||||
|
val yellowColor = Color(0xFFFFE082)
|
||||||
|
val whiteColor = Color(0xCCFFFFFF)
|
||||||
|
val redColor = Color(0xFFB71C1C)
|
||||||
|
val strokeWidth = 4f
|
||||||
|
Canvas(modifier = Modifier.fillMaxSize()) {
|
||||||
|
val radius = (size.minDimension / 2f) * 0.95f
|
||||||
|
if (items.isNotEmpty() && !isTrackCreated) {
|
||||||
|
newTrackPath.value = createPassTrajectory(items, radius)
|
||||||
|
newArrowPath.value = createPassTrajectoryArrow()
|
||||||
|
isTrackCreated = true
|
||||||
|
}
|
||||||
|
rotate(-orientation.first) {
|
||||||
|
drawRadarCirle(radius, whiteColor, strokeWidth)
|
||||||
|
drawRadarCross(radius, whiteColor, strokeWidth)
|
||||||
|
drawRadarText(radius, yellowColor, measurer)
|
||||||
|
translate(center.x, center.y) {
|
||||||
|
if (items.isNotEmpty()) {
|
||||||
|
val effect = createPathEffect(newTrackPath.value, newArrowPath.value)
|
||||||
|
drawPath(newTrackPath.value, redColor, style = Stroke(4f))
|
||||||
|
drawPath(newTrackPath.value, yellowColor, style = Stroke(pathEffect = effect))
|
||||||
|
}
|
||||||
|
drawSatellite(item, radius, yellowColor)
|
||||||
|
drawCrosshair(orientation.first, orientation.second, radius, strokeWidth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DrawScope.drawRadarCirle(radius: Float, color: Color, width: Float, circles: Int = 3) {
|
||||||
|
for (i in 0 until circles) {
|
||||||
|
val circleRadius = radius - radius / circles.toFloat() * i.toFloat()
|
||||||
|
drawCircle(color, circleRadius, style = Stroke(width))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DrawScope.drawRadarCross(radius: Float, color: Color, width: Float) {
|
||||||
|
drawLine(color, center, center.copy(x = center.x - radius), strokeWidth = width)
|
||||||
|
drawLine(color, center, center.copy(x = center.x + radius), strokeWidth = width)
|
||||||
|
drawLine(color, center, center.copy(y = center.y - radius), strokeWidth = width)
|
||||||
|
drawLine(color, center, center.copy(y = center.y + radius), strokeWidth = width)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DrawScope.drawRadarText(
|
||||||
|
radius: Float, color: Color, measurer: TextMeasurer, circles: Int = 3
|
||||||
|
) {
|
||||||
|
for (i in 0..circles) {
|
||||||
|
val textY = (radius - radius / circles * i) + 25f
|
||||||
|
val textDeg = " ${(90 / circles) * (circles - i)}°"
|
||||||
|
drawText(measurer, textDeg, center.copy(y = textY), style = TextStyle(color, 16.sp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DrawScope.drawSatellite(item: SatPos, radius: Float, color: Color) {
|
||||||
|
if (item.elevation > 0) {
|
||||||
|
val satX = sph2CartX(item.azimuth, item.elevation, radius.toDouble())
|
||||||
|
val satY = sph2CartY(item.azimuth, item.elevation, radius.toDouble())
|
||||||
|
drawCircle(color, 16f, center.copy(satX, -satY))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DrawScope.drawCrosshair(azimuth: Float, elevation: Float, radius: Float, width: Float) {
|
||||||
|
val redColor = Color(0xFFFF0000)
|
||||||
|
val size = 36f
|
||||||
|
val azimuthRad = azimuth.toDouble().toRadians()
|
||||||
|
val tmpElevation = elevation.toDouble().toRadians()
|
||||||
|
val elevationRad = if (tmpElevation > 0.0) 0.0 else tmpElevation
|
||||||
|
val crossX = sph2CartX(azimuthRad, -elevationRad, radius.toDouble())
|
||||||
|
val crossY = sph2CartY(azimuthRad, -elevationRad, radius.toDouble())
|
||||||
|
drawLine(
|
||||||
|
redColor,
|
||||||
|
center.copy(crossX - size, -crossY),
|
||||||
|
center.copy(crossX + size, -crossY),
|
||||||
|
strokeWidth = width
|
||||||
|
)
|
||||||
|
drawLine(
|
||||||
|
redColor,
|
||||||
|
center.copy(crossX, -crossY - size),
|
||||||
|
center.copy(crossX, -crossY + size),
|
||||||
|
strokeWidth = width
|
||||||
|
)
|
||||||
|
drawCircle(redColor, size / 2, center.copy(crossX, -crossY), style = Stroke(width))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createPassTrajectory(positions: List<SatPos>, radarRadius: Float): Path {
|
||||||
|
val trackPath = Path()
|
||||||
|
positions.forEachIndexed { index, satPos ->
|
||||||
|
val passX = sph2CartX(satPos.azimuth, satPos.elevation, radarRadius.toDouble())
|
||||||
|
val passY = sph2CartY(satPos.azimuth, satPos.elevation, radarRadius.toDouble())
|
||||||
|
if (index == 0) {
|
||||||
|
trackPath.moveTo(passX, -passY)
|
||||||
|
} else {
|
||||||
|
trackPath.lineTo(passX, -passY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trackPath
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createPassTrajectoryArrow(): Path {
|
||||||
|
val arrowPath = Path()
|
||||||
|
val radius = 24f
|
||||||
|
val sides = 3
|
||||||
|
val angle = TWO_PI / sides
|
||||||
|
arrowPath.moveTo((radius * cos(angle)).toFloat(), (radius * sin(angle)).toFloat())
|
||||||
|
for (i in 1 until sides) {
|
||||||
|
val x = (radius * cos(angle - angle * i)).toFloat()
|
||||||
|
val y = (radius * sin(angle - angle * i)).toFloat()
|
||||||
|
arrowPath.lineTo(x, y)
|
||||||
|
}
|
||||||
|
arrowPath.close()
|
||||||
|
return arrowPath
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createPathEffect(trackPath: Path, arrowPath: Path): PathEffect {
|
||||||
|
val trackLength = PathMeasure().apply { setPath(trackPath, false) }.length
|
||||||
|
val quarter = trackLength / 4f
|
||||||
|
val center = trackLength / 2f
|
||||||
|
return PathEffect.stampedPathEffect(arrowPath, center, quarter, StampedPathEffectStyle.Rotate)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sph2CartX(azimuth: Double, elevation: Double, r: Double): Float {
|
||||||
|
val radius = r * (PI_2 - elevation) / PI_2
|
||||||
|
return (radius * cos(PI_2 - azimuth)).toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sph2CartY(azimuth: Double, elevation: Double, r: Double): Float {
|
||||||
|
val radius = r * (PI_2 - elevation) / PI_2
|
||||||
|
return (radius * sin(PI_2 - azimuth)).toFloat()
|
||||||
|
}
|
||||||
+26
-12
@@ -19,8 +19,7 @@ package com.rtbishop.look4sat.presentation.radarScreen
|
|||||||
|
|
||||||
import android.hardware.GeomagneticField
|
import android.hardware.GeomagneticField
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.rtbishop.look4sat.domain.IDataRepository
|
import com.rtbishop.look4sat.domain.IDataRepository
|
||||||
@@ -37,6 +36,8 @@ import com.rtbishop.look4sat.utility.round
|
|||||||
import com.rtbishop.look4sat.utility.toDegrees
|
import com.rtbishop.look4sat.utility.toDegrees
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -44,6 +45,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class RadarViewModel @Inject constructor(
|
class RadarViewModel @Inject constructor(
|
||||||
|
private val savedStateHandle: SavedStateHandle,
|
||||||
private val orientationManager: OrientationManager,
|
private val orientationManager: OrientationManager,
|
||||||
private val reporter: DataReporter,
|
private val reporter: DataReporter,
|
||||||
private val btReporter: BTReporter,
|
private val btReporter: BTReporter,
|
||||||
@@ -53,17 +55,29 @@ class RadarViewModel @Inject constructor(
|
|||||||
) : ViewModel(), OrientationManager.OrientationListener {
|
) : ViewModel(), OrientationManager.OrientationListener {
|
||||||
|
|
||||||
private val stationPos = settings.loadStationPosition()
|
private val stationPos = settings.loadStationPosition()
|
||||||
private val _passData = MutableLiveData<RadarData>()
|
private val _passData = MutableStateFlow<RadarData?>(null)
|
||||||
private val _transmitters = MutableLiveData<List<SatRadio>>()
|
private val _transmitters = MutableStateFlow<List<SatRadio>>(emptyList())
|
||||||
private val _orientation = MutableLiveData<Triple<Float, Float, Float>>()
|
private val _orientation = MutableStateFlow<Triple<Float, Float, Float>?>(null)
|
||||||
val radarData: LiveData<RadarData> = _passData
|
val radarData: StateFlow<RadarData?> = _passData
|
||||||
val transmitters: LiveData<List<SatRadio>> = _transmitters
|
val transmitters: StateFlow<List<SatRadio>> = _transmitters
|
||||||
val orientation: LiveData<Triple<Float, Float, Float>> = _orientation
|
val orientation: StateFlow<Triple<Float, Float, Float>?> = _orientation
|
||||||
|
|
||||||
fun getPass(catNum: Int, aosTime: Long) = flow {
|
init {
|
||||||
|
enableSensor()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
disableSensor()
|
||||||
|
super.onCleared()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPass() = flow {
|
||||||
|
val catNum = savedStateHandle.get<Int>("catNum") ?: 0
|
||||||
|
val aosTime = savedStateHandle.get<Long>("aosTime") ?: 0L
|
||||||
satManager.calculatedPasses.collect { passes ->
|
satManager.calculatedPasses.collect { passes ->
|
||||||
val pass = passes.find { pass -> pass.catNum == catNum && pass.aosTime == aosTime }
|
val pass = passes.find { pass -> pass.catNum == catNum && pass.aosTime == aosTime }
|
||||||
pass?.let { satPass ->
|
val currentPass = pass ?: passes.firstOrNull()
|
||||||
|
currentPass?.let { satPass ->
|
||||||
emit(satPass)
|
emit(satPass)
|
||||||
val transmitters = repository.getRadiosWithId(satPass.catNum)
|
val transmitters = repository.getRadiosWithId(satPass.catNum)
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
@@ -115,7 +129,7 @@ class RadarViewModel @Inject constructor(
|
|||||||
val elevation = satPos.elevation.toDegrees().round(1)
|
val elevation = satPos.elevation.toDegrees().round(1)
|
||||||
reporter.reportRotation(server, port, azimuth, elevation)
|
reporter.reportRotation(server, port, azimuth, elevation)
|
||||||
}
|
}
|
||||||
_passData.postValue(RadarData(satPos, track))
|
_passData.value = RadarData(satPos, track)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +154,7 @@ class RadarViewModel @Inject constructor(
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
delay(125)
|
delay(125)
|
||||||
val list = satManager.processRadios(satellite, stationPos, radios, time)
|
val list = satManager.processRadios(satellite, stationPos, radios, time)
|
||||||
_transmitters.postValue(list)
|
_transmitters.value = list
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user