Added map in compose, removed MapFragment

This commit is contained in:
Arty Bishop committed 2025-12-27 15:01:32 +00:00
1 parent acb851d4f6
commit c592b8d3ce
23 files changed
+333 -737

No files matched your search

-1
View File
@@ -3,7 +3,6 @@ plugins {
id "org.jetbrains.kotlin.android"
id "org.jetbrains.kotlin.kapt"
id "dagger.hilt.android.plugin"
id "androidx.navigation.safeargs.kotlin"
}
android {
@@ -26,12 +26,7 @@ import android.os.SystemClock
import android.view.View
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.IdRes
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.navigation.fragment.findNavController
import com.rtbishop.look4sat.presentation.bottomNav.MainScreenView
import dagger.hilt.android.AndroidEntryPoint
@@ -54,24 +49,6 @@ class MainActivity : ComponentActivity() {
}
}
fun <T> Fragment.getNavResult(@IdRes id: Int, key: String, onResult: (result: T) -> Unit) {
val backStackEntry = findNavController().getBackStackEntry(id)
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME && backStackEntry.savedStateHandle.contains(key)) {
backStackEntry.savedStateHandle.get<T>(key)?.let(onResult)
backStackEntry.savedStateHandle.remove<T>(key)
}
}
backStackEntry.lifecycle.addObserver(observer)
viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_DESTROY) backStackEntry.lifecycle.removeObserver(observer)
})
}
fun <T> Fragment.setNavResult(key: String, value: T) {
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, value)
}
fun View.clickWithDebounce(debounceTime: Long = 875L, action: () -> Unit) {
this.setOnClickListener(object : View.OnClickListener {
private var lastClickTime: Long = 0
@@ -20,6 +20,7 @@ import androidx.navigation.compose.rememberNavController
import com.rtbishop.look4sat.presentation.MainTheme
import com.rtbishop.look4sat.presentation.aboutScreen.AboutScreen
import com.rtbishop.look4sat.presentation.entriesScreen.EntriesScreen
import com.rtbishop.look4sat.presentation.mapScreen.MapScreen
import com.rtbishop.look4sat.presentation.passesScreen.PassesScreen
import com.rtbishop.look4sat.presentation.passesScreen.PassesViewModel
@@ -58,7 +59,7 @@ fun NavigationGraph(navController: NavHostController) {
EntriesScreen(navToPasses, passesViewModel = passesViewModel)
}
composable(BottomNavItem.Passes.screen_route) { PassesScreen(viewModel = passesViewModel) }
composable(BottomNavItem.WorldMap.screen_route) {}
composable(BottomNavItem.WorldMap.screen_route) { MapScreen() }
composable(BottomNavItem.Settings.screen_route) {}
composable(BottomNavItem.About.screen_route) { AboutScreen() }
}
@@ -28,7 +28,6 @@ import androidx.recyclerview.widget.SimpleItemAnimator
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.DialogModesBinding
import com.rtbishop.look4sat.domain.ISettingsManager
import com.rtbishop.look4sat.presentation.setNavResult
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@@ -74,7 +73,7 @@ class ModesDialog : AppCompatDialogFragment(), ModesAdapter.ModesClickListener {
}
modesBtnNeg.setOnClickListener { dismiss() }
modesBtnPos.setOnClickListener {
setNavResult("modes", selectedModes.toList())
// setNavResult("modes", selectedModes.toList())
dismiss()
}
}
@@ -1,240 +0,0 @@
/*
* Look4Sat. Amateur radio satellite tracker and pass predictor.
* Copyright (C) 2019-2022 Arty Bishop (bishop.arty@gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.presentation.mapScreen
import android.content.Context
import android.graphics.*
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.view.View
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentMapBinding
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.domain.predict.SatPos
import com.rtbishop.look4sat.domain.predict.Satellite
import com.rtbishop.look4sat.presentation.clickWithDebounce
import dagger.hilt.android.AndroidEntryPoint
import org.osmdroid.config.Configuration
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.CustomZoomButtonsController
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.FolderOverlay
import org.osmdroid.views.overlay.Marker
import org.osmdroid.views.overlay.Polyline
@AndroidEntryPoint
class MapFragment : Fragment(R.layout.fragment_map) {
private val viewModel: MapViewModel by viewModels()
private val navArgs: MapFragmentArgs by navArgs()
private val minLat = MapView.getTileSystem().minLatitude
private val maxLat = MapView.getTileSystem().maxLatitude
private val trackPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
strokeWidth = 3f
style = Paint.Style.STROKE
color = Color.RED
strokeCap = Paint.Cap.ROUND
strokeJoin = Paint.Join.ROUND
}
private val footprintPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
strokeWidth = 3f
style = Paint.Style.FILL_AND_STROKE
color = Color.parseColor("#FFE082")
}
private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
textSize = 36f
style = Paint.Style.FILL
color = Color.parseColor("#CCFFFFFF")
setShadowLayer(3f, 3f, 3f, Color.BLACK)
}
private val labelRect = Rect()
private lateinit var binding: FragmentMapBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentMapBinding.bind(view)
setupComponents()
setupObservers()
}
private fun setupComponents() {
val context = requireContext()
val preferences = context.getSharedPreferences("default", Context.MODE_PRIVATE)
Configuration.getInstance().load(context, preferences)
binding.run {
mapView.apply {
setMultiTouchControls(true)
setTileSource(TileSourceFactory.WIKIMEDIA)
minZoomLevel = getMinZoom(resources.displayMetrics.heightPixels) + 0.25
maxZoomLevel = 5.75
controller.setZoom(minZoomLevel + 0.25)
zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
overlayManager.tilesOverlay.loadingBackgroundColor = Color.TRANSPARENT
overlayManager.tilesOverlay.loadingLineColor = Color.TRANSPARENT
overlayManager.tilesOverlay.setColorFilter(getColorFilter())
setScrollableAreaLimitLatitude(maxLat, minLat, 0)
// add overlays: 0 - GSP, 1 - SatTrack, 2 - SatFootprint, 3 - SatIcons
overlays.addAll(Array(4) { FolderOverlay() })
}
mapBtnBack.clickWithDebounce { findNavController().navigateUp() }
mapBtnPrev.setOnClickListener { viewModel.scrollSelection(true) }
mapBtnNext.setOnClickListener { viewModel.scrollSelection(false) }
}
}
private fun setupObservers() {
viewModel.selectDefaultSatellite(navArgs.catNum)
viewModel.stationPos.observe(viewLifecycleOwner) { handleStationPos(it) }
viewModel.positions.observe(viewLifecycleOwner) { handlePositions(it) }
viewModel.track.observe(viewLifecycleOwner) { handleTrack(it) }
viewModel.footprint.observe(viewLifecycleOwner) { handleFootprint(it) }
viewModel.mapData.observe(viewLifecycleOwner) { handleMapData(it) }
}
private fun handleStationPos(stationPos: GeoPos) {
binding.apply {
Marker(mapView).apply {
setInfoWindow(null)
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
icon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_position)
position = GeoPoint(stationPos.lat, stationPos.lon)
mapView.overlays[0] = this
mapView.invalidate()
}
}
}
private fun handlePositions(posMap: Map<Satellite, GeoPos>) {
binding.apply {
val markers = FolderOverlay()
posMap.entries.forEach {
Marker(mapView).apply {
setInfoWindow(null)
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
icon = getCustomTextIcon(it.key.data.name)
try {
position = GeoPoint(it.value.lat, it.value.lon)
} catch (exception: IllegalArgumentException) {
println(exception.stackTraceToString())
}
setOnMarkerClickListener { _, _ ->
viewModel.selectSatellite(it.key)
return@setOnMarkerClickListener true
}
markers.add(this)
}
}
mapView.overlays[3] = markers
mapView.invalidate()
}
}
private fun getCustomTextIcon(textLabel: String): Drawable {
textPaint.getTextBounds(textLabel, 0, textLabel.length, labelRect)
val iconSize = 8f
val width = labelRect.width() + iconSize * 2f
val height = textPaint.textSize * 3f + iconSize * 2f
val bitmap = Bitmap.createBitmap(width.toInt(), height.toInt(), Bitmap.Config.ARGB_8888)
Canvas(bitmap).run {
drawCircle(width / 2f, height / 2f, iconSize, textPaint)
drawText(textLabel, iconSize / 2f, height - iconSize, textPaint)
}
return BitmapDrawable(binding.mapView.context.resources, bitmap)
}
private fun handleTrack(satTrack: List<List<GeoPos>>) {
val center = GeoPoint(satTrack[0][0].lat, satTrack[0][0].lon)
val trackOverlay = FolderOverlay()
satTrack.forEach { track ->
val trackPoints = track.map { GeoPoint(it.lat, it.lon) }
Polyline().apply {
try {
setPoints(trackPoints)
outlinePaint.set(trackPaint)
trackOverlay.add(this)
} catch (exception: IllegalArgumentException) {
println(exception.stackTraceToString())
}
}
}
binding.mapView.overlays[1] = trackOverlay
binding.mapView.controller.animateTo(center)
}
private fun handleFootprint(satPos: SatPos) {
val footprintPoints = satPos.getRangeCircle().map { GeoPoint(it.lat, it.lon) }
val footprintOverlay = Polyline().apply {
outlinePaint.set(footprintPaint)
try {
setPoints(footprintPoints)
} catch (exception: IllegalArgumentException) {
println(exception.stackTraceToString())
}
}
binding.mapView.overlays[2] = footprintOverlay
}
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()
}
private fun getColorFilter(): ColorMatrixColorFilter {
val grayScaleMatrix = ColorMatrix().apply { setSaturation(0f) }
val negativeMatrix = ColorMatrix(
floatArrayOf(
-1f, 0f, 0f, 0f, 255f,
0f, -1f, 0f, 0f, 255f,
0f, 0f, -1f, 0f, 255f,
0f, 0f, 0f, 1f, 0f
)
)
negativeMatrix.preConcat(grayScaleMatrix)
return ColorMatrixColorFilter(negativeMatrix)
}
private fun getMinZoom(screenHeight: Int): Double {
return MapView.getTileSystem().getLatitudeZoom(maxLat, minLat, screenHeight)
}
}
@@ -0,0 +1,247 @@
package com.rtbishop.look4sat.presentation.mapScreen
import android.content.Context
import android.graphics.*
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ElevatedCard
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.domain.predict.SatPos
import com.rtbishop.look4sat.domain.predict.Satellite
import org.osmdroid.config.Configuration
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.CustomZoomButtonsController
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.FolderOverlay
import org.osmdroid.views.overlay.Marker
import org.osmdroid.views.overlay.Polyline
import timber.log.Timber
private val minLat = MapView.getTileSystem().minLatitude
private val maxLat = MapView.getTileSystem().maxLatitude
private val trackPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
strokeWidth = 3f
style = Paint.Style.STROKE
color = Color.RED
strokeCap = Paint.Cap.ROUND
strokeJoin = Paint.Join.ROUND
}
private val footprintPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
strokeWidth = 3f
style = Paint.Style.FILL_AND_STROKE
color = Color.parseColor("#FFE082")
}
private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
textSize = 36f
style = Paint.Style.FILL
color = Color.parseColor("#CCFFFFFF")
setShadowLayer(3f, 3f, 3f, Color.BLACK)
}
private val labelRect = Rect()
@Composable
fun MapScreen(viewModel: MapViewModel = hiltViewModel()) {
val context = LocalContext.current
Configuration.getInstance().load(context, viewModel.getPreferences())
viewModel.selectDefaultSatellite(-1)
val stationPos = viewModel.stationPos.observeAsState()
val positions = viewModel.positions.observeAsState()
val satTrack = viewModel.track.observeAsState()
val footprint = viewModel.footprint.observeAsState()
val positionClick = { satellite: Satellite -> viewModel.selectSatellite(satellite) }
Timber.d("MapScreen recomposition")
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
ElevatedCard(modifier = Modifier.fillMaxSize()) {
MapView(modifier = Modifier.fillMaxSize()) { mapView ->
Timber.d("MapView recomposition")
stationPos.value?.let { setStationPosition(it, mapView) }
positions.value?.let { setPositions(it, mapView, positionClick) }
satTrack.value?.let { setSatelliteTrack(it, mapView) }
footprint.value?.let { setFootprint(it, mapView) }
}
}
}
}
private fun setStationPosition(stationPos: GeoPos, mapView: MapView) {
Marker(mapView).apply {
setInfoWindow(null)
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
icon = ContextCompat.getDrawable(mapView.context, R.drawable.ic_position)
position = GeoPoint(stationPos.lat, stationPos.lon)
mapView.overlays[0] = this
mapView.invalidate()
}
}
private fun setPositions(
posMap: Map<Satellite, GeoPos>, mapView: MapView, action: (Satellite) -> Unit
) {
val markers = FolderOverlay()
posMap.entries.forEach {
Marker(mapView).apply {
setInfoWindow(null)
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
icon = getCustomTextIcon(it.key.data.name, mapView)
try {
position = GeoPoint(it.value.lat, it.value.lon)
} catch (exception: IllegalArgumentException) {
println(exception.stackTraceToString())
}
setOnMarkerClickListener { _, _ ->
action(it.key)
return@setOnMarkerClickListener true
}
markers.add(this)
}
}
mapView.overlays[3] = markers
mapView.invalidate()
}
private fun getCustomTextIcon(textLabel: String, mapView: MapView): Drawable {
textPaint.getTextBounds(textLabel, 0, textLabel.length, labelRect)
val iconSize = 8f
val width = labelRect.width() + iconSize * 2f
val height = textPaint.textSize * 3f + iconSize * 2f
val bitmap = Bitmap.createBitmap(width.toInt(), height.toInt(), Bitmap.Config.ARGB_8888)
Canvas(bitmap).run {
drawCircle(width / 2f, height / 2f, iconSize, textPaint)
drawText(textLabel, iconSize / 2f, height - iconSize, textPaint)
}
return BitmapDrawable(mapView.context.resources, bitmap)
}
private fun setSatelliteTrack(satTrack: List<List<GeoPos>>, mapView: MapView) {
// val center = GeoPoint(satTrack[0][0].lat, satTrack[0][0].lon)
val trackOverlay = FolderOverlay()
satTrack.forEach { track ->
val trackPoints = track.map { GeoPoint(it.lat, it.lon) }
Polyline().apply {
try {
setPoints(trackPoints)
outlinePaint.set(trackPaint)
trackOverlay.add(this)
} catch (exception: IllegalArgumentException) {
println(exception.stackTraceToString())
}
}
}
mapView.overlays[1] = trackOverlay
// mapView.controller.animateTo(center)
}
private fun setFootprint(satPos: SatPos, mapView: MapView) {
val footprintPoints = satPos.getRangeCircle().map { GeoPoint(it.lat, it.lon) }
val footprintOverlay = Polyline().apply {
outlinePaint.set(footprintPaint)
try {
setPoints(footprintPoints)
} catch (exception: IllegalArgumentException) {
println(exception.stackTraceToString())
}
}
mapView.overlays[2] = footprintOverlay
}
//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, update: ((map: MapView) -> Unit)? = null) {
val mapView = rememberMapViewWithLifecycle()
AndroidView({ mapView }, modifier) { update?.invoke(it) }
}
@Composable
private fun rememberMapViewWithLifecycle(context: Context = LocalContext.current): MapView {
// add clipToOutline = true if needed
val mapView = remember { MapView(context).apply { id = R.id.osm_map_view } }.apply {
setMultiTouchControls(true)
setTileSource(TileSourceFactory.WIKIMEDIA)
minZoomLevel = getMinZoom(resources.displayMetrics.heightPixels) + 0.25
maxZoomLevel = 5.75
controller.setZoom(minZoomLevel + 0.25)
zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
overlayManager.tilesOverlay.loadingBackgroundColor = Color.TRANSPARENT
overlayManager.tilesOverlay.loadingLineColor = Color.TRANSPARENT
overlayManager.tilesOverlay.setColorFilter(getColorFilter())
setScrollableAreaLimitLatitude(maxLat, minLat, 0)
// add overlays: 0 - GSP, 1 - SatTrack, 2 - SatFootprint, 3 - SatIcons
overlays.addAll(Array(4) { FolderOverlay() })
}
// Makes MapView follow the lifecycle of this composable
val lifecycleObserver = rememberMapViewLifecycleObserver(mapView)
val lifecycle = LocalLifecycleOwner.current.lifecycle
DisposableEffect(lifecycle) {
lifecycle.addObserver(lifecycleObserver)
onDispose { lifecycle.removeObserver(lifecycleObserver) }
}
return mapView
}
@Composable
private fun rememberMapViewLifecycleObserver(mapView: MapView) = remember(mapView) {
LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_RESUME -> mapView.onResume()
Lifecycle.Event.ON_PAUSE -> mapView.onPause()
else -> {}
}
}
}
private fun getColorFilter(): ColorMatrixColorFilter {
val grayScaleMatrix = ColorMatrix().apply { setSaturation(0f) }
val negativeMatrix = ColorMatrix(
floatArrayOf(
-1f, 0f, 0f, 0f, 255f, 0f, -1f, 0f, 0f, 255f, 0f, 0f, -1f, 0f, 255f, 0f, 0f, 0f, 1f, 0f
)
)
negativeMatrix.preConcat(grayScaleMatrix)
return ColorMatrixColorFilter(negativeMatrix)
}
private fun getMinZoom(screenHeight: Int): Double {
return MapView.getTileSystem().getLatitudeZoom(maxLat, minLat, screenHeight)
}
@@ -17,6 +17,7 @@
*/
package com.rtbishop.look4sat.presentation.mapScreen
import android.content.SharedPreferences
import androidx.lifecycle.*
import com.rtbishop.look4sat.domain.IDataRepository
import com.rtbishop.look4sat.domain.ISatelliteManager
@@ -36,9 +37,10 @@ import kotlin.math.min
@HiltViewModel
class MapViewModel @Inject constructor(
private val satelliteManager: ISatelliteManager,
private val preferences: SharedPreferences,
private val repository: IDataRepository,
private val settings: ISettingsManager,
private val satelliteManager: ISatelliteManager,
private val settings: ISettingsManager
) : ViewModel() {
private val stationPosition = settings.loadStationPosition()
@@ -66,6 +68,8 @@ class MapViewModel @Inject constructor(
private val _positions = MutableLiveData<Map<Satellite, GeoPos>>()
val positions: LiveData<Map<Satellite, GeoPos>> = _positions
fun getPreferences() = preferences
fun scrollSelection(decrement: Boolean) {
if (allSatellites.isNotEmpty()) {
val index = allSatellites.indexOf(selectedSatellite)
@@ -184,8 +188,19 @@ class MapViewModel @Inject constructor(
val phase = satPos.phase.toDegrees()
val visibility = satPos.eclipsed
val satData = MapData(
sat.data.catnum, sat.data.name, aosTime, azimuth, elevation, satPos.distance,
satPos.altitude, velocity, qthLoc, osmPos, sat.data.orbitalPeriod, phase, visibility
sat.data.catnum,
sat.data.name,
aosTime,
azimuth,
elevation,
satPos.distance,
satPos.altitude,
velocity,
qthLoc,
osmPos,
sat.data.orbitalPeriod,
phase,
visibility
)
_mapData.postValue(satData)
}
@@ -17,14 +17,10 @@
*/
package com.rtbishop.look4sat.presentation.radarScreen
import android.content.Intent
import android.os.Bundle
import android.provider.CalendarContract
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator
@@ -32,7 +28,6 @@ import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentRadarBinding
import com.rtbishop.look4sat.domain.predict.SatPass
import com.rtbishop.look4sat.domain.predict.SatPos
import com.rtbishop.look4sat.presentation.clickWithDebounce
import com.rtbishop.look4sat.utility.toDegrees
import com.rtbishop.look4sat.utility.toTimerString
import dagger.hilt.android.AndroidEntryPoint
@@ -41,7 +36,6 @@ import dagger.hilt.android.AndroidEntryPoint
class RadarFragment : Fragment(R.layout.fragment_radar) {
private val viewModel: RadarViewModel by viewModels()
private val navArgs: RadarFragmentArgs by navArgs()
private val radioAdapter = RadioAdapter()
private var binding: FragmentRadarBinding? = null
private var radarView: RadarView? = null
@@ -78,7 +72,7 @@ class RadarFragment : Fragment(R.layout.fragment_radar) {
}
private fun setupObservers() {
viewModel.getPass(navArgs.catNum, navArgs.aosTime).observe(viewLifecycleOwner) { pass ->
viewModel.getPass(45000, System.currentTimeMillis()).observe(viewLifecycleOwner) { pass ->
binding?.run {
radarView = RadarView(requireContext()).apply {
setShowAim(viewModel.getUseCompass())
@@ -103,24 +97,16 @@ class RadarFragment : Fragment(R.layout.fragment_radar) {
viewModel.orientation.observe(viewLifecycleOwner) { value ->
radarView?.setOrientation(value.first, value.second, value.third)
}
radarBtnBack.clickWithDebounce { findNavController().navigateUp() }
radarBtnMap.clickWithDebounce {
val direction = RadarFragmentDirections.globalToMap(pass.catNum)
findNavController().navigate(direction)
}
radarBtnNotify.clickWithDebounce {
val intent = Intent(Intent.ACTION_INSERT)
.setData(CalendarContract.Events.CONTENT_URI)
.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, pass.aosTime)
.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, pass.losTime)
.putExtra(CalendarContract.Events.TITLE, pass.name)
.putExtra(CalendarContract.Events.DESCRIPTION, "Look4Sat")
startActivity(intent)
}
radarBtnSettings.clickWithDebounce {
val direction = RadarFragmentDirections.globalToSettings()
findNavController().navigate(direction)
}
// 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)
// }
}
}
}
@@ -150,7 +136,7 @@ class RadarFragment : Fragment(R.layout.fragment_radar) {
radarTimer.text = millisBeforeEnd.toTimerString()
if (timeNow > satPass.losTime) {
radarTimer.text = 0L.toTimerString()
findNavController().navigateUp()
// findNavController().navigateUp()
}
}
} else radarTimer.text = 0L.toTimerString()
@@ -26,7 +26,6 @@ import androidx.appcompat.app.AppCompatDialogFragment
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.DialogLocatorBinding
import com.rtbishop.look4sat.domain.ISettingsManager
import com.rtbishop.look4sat.presentation.setNavResult
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@@ -50,7 +49,7 @@ class LocatorDialog : AppCompatDialogFragment() {
)
locatorEdit.setText(preferences.loadStationLocator())
locatorBtnPos.setOnClickListener {
setNavResult("locator", locatorEdit.text.toString())
// setNavResult("locator", locatorEdit.text.toString())
dismiss()
}
locatorBtnNeg.setOnClickListener { dismiss() }
@@ -26,7 +26,6 @@ import androidx.appcompat.app.AppCompatDialogFragment
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.DialogPositionBinding
import com.rtbishop.look4sat.domain.ISettingsManager
import com.rtbishop.look4sat.presentation.setNavResult
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@@ -52,17 +51,17 @@ class PositionDialog : AppCompatDialogFragment() {
positionLatEdit.setText(location.lat.toString())
positionLonEdit.setText(location.lon.toString())
positionBtnPos.setOnClickListener {
val latitude = try {
positionLatEdit.text.toString().toDouble()
} catch (exception: Exception) {
180.0
}
val longitude = try {
positionLonEdit.text.toString().toDouble()
} catch (exception: Exception) {
400.0
}
setNavResult("position", Pair(latitude, longitude))
// val latitude = try {
// positionLatEdit.text.toString().toDouble()
// } catch (exception: Exception) {
// 180.0
// }
// val longitude = try {
// positionLonEdit.text.toString().toDouble()
// } catch (exception: Exception) {
// 400.0
// }
// setNavResult("position", Pair(latitude, longitude))
dismiss()
}
positionBtnNeg.setOnClickListener { dismiss() }
@@ -31,14 +31,12 @@ import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.asLiveData
import androidx.navigation.fragment.findNavController
import com.rtbishop.look4sat.BuildConfig
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.databinding.FragmentSettingsBinding
import com.rtbishop.look4sat.domain.model.DataState
import com.rtbishop.look4sat.domain.predict.GeoPos
import com.rtbishop.look4sat.presentation.clickWithDebounce
import com.rtbishop.look4sat.presentation.getNavResult
import com.rtbishop.look4sat.utility.isValidIPv4
import com.rtbishop.look4sat.utility.isValidPort
import dagger.hilt.android.AndroidEntryPoint
@@ -79,7 +77,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentSettingsBinding.bind(view).apply {
settingsBtnBack.clickWithDebounce { findNavController().navigateUp() }
// settingsBtnBack.clickWithDebounce { findNavController().navigateUp() }
settingsScroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, y, _, newY ->
if (y > newY) settingsFab.hide() else settingsFab.show()
})
@@ -115,20 +113,20 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
settingsLocation.locationBtnGps.clickWithDebounce {
locationRequest.launch(arrayOf(locationFine, locationCoarse))
}
settingsLocation.locationBtnManual.clickWithDebounce {
val action = SettingsFragmentDirections.globalToPosition()
findNavController().navigate(action)
}
settingsLocation.locationBtnQth.clickWithDebounce {
val action = SettingsFragmentDirections.globalToLocator()
findNavController().navigate(action)
}
getNavResult<Pair<Double, Double>>(R.id.nav_settings, "position") { position ->
viewModel.setStationPosition(position.first, position.second)
}
getNavResult<String>(R.id.nav_settings, "locator") { locator ->
viewModel.setPositionFromQth(locator)
}
// settingsLocation.locationBtnManual.clickWithDebounce {
// val action = SettingsFragmentDirections.globalToPosition()
// findNavController().navigate(action)
// }
// settingsLocation.locationBtnQth.clickWithDebounce {
// val action = SettingsFragmentDirections.globalToLocator()
// findNavController().navigate(action)
// }
// getNavResult<Pair<Double, Double>>(R.id.nav_settings, "position") { position ->
// viewModel.setStationPosition(position.first, position.second)
// }
// getNavResult<String>(R.id.nav_settings, "locator") { locator ->
// viewModel.setPositionFromQth(locator)
// }
}
}
@@ -146,9 +144,9 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
val radiosFormat = getString(R.string.data_radios)
settingsData.dataRadios.text = String.format(radiosFormat, number)
}
getNavResult<List<String>>(R.id.nav_settings, "sources") {
viewModel.updateFromWeb()
}
// getNavResult<List<String>>(R.id.nav_settings, "sources") {
// viewModel.updateFromWeb()
// }
}
}
@@ -1,7 +1,8 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:autoMirrored="true"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
+2 -1
View File
@@ -1,7 +1,8 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:autoMirrored="true"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
+10 -3
View File
@@ -1,4 +1,11 @@
<vector android:height="24dp" android:viewportHeight="512"
android:viewportWidth="512" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M495.3,425.74H255.18c-3.58,-52 -23.78,-100.69 -58.12,-140.07L401.37,81.37c6.52,-6.52 6.52,-17.09 0,-23.61c-6.52,-6.52 -17.09,-6.52 -23.61,0L162.23,273.29L4.89,430.63c-4.77,4.77 -6.21,11.96 -3.62,18.2s8.67,10.3 15.42,10.3h222.61h256c9.22,0 16.7,-7.47 16.7,-16.7C512,433.21 504.52,425.74 495.3,425.74z"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:tint="?attr/colorControlNormal"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#000000"
android:pathData="M495.3,425.74H255.18c-3.58,-52 -23.78,-100.69 -58.12,-140.07L401.37,81.37c6.52,-6.52 6.52,-17.09 0,-23.61c-6.52,-6.52 -17.09,-6.52 -23.61,0L162.23,273.29L4.89,430.63c-4.77,4.77 -6.21,11.96 -3.62,18.2s8.67,10.3 15.42,10.3h222.61h256c9.22,0 16.7,-7.47 16.7,-16.7C512,433.21 504.52,425.74 495.3,425.74z" />
</vector>
+2 -1
View File
@@ -1,7 +1,8 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:autoMirrored="true"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z" />
</vector>
@@ -1,13 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#000000"
android:pathData="M437.02,74.98C388.67,26.63 324.38,0 256,0S123.33,26.63 74.98,74.98C26.63,123.33 0,187.62 0,256S26.63,388.67 74.98,437.02C123.33,485.37 187.62,512 256,512c68.38,0 132.67,-26.63 181.02,-74.98C485.37,388.67 512,324.38 512,256S485.37,123.33 437.02,74.98zM415.51,415.51c-42.61,42.61 -99.26,66.07 -159.51,66.07c-60.26,0 -116.9,-23.47 -159.51,-66.07C53.88,372.9 30.42,316.26 30.42,256S53.88,139.1 96.49,96.49C139.1,53.88 195.74,30.42 256,30.42c55.16,0 107.29,19.67 148.39,55.68l-41.21,41.21C333.14,102.2 295.63,88.52 256,88.52c-92.35,0 -167.48,75.13 -167.48,167.48S163.65,423.48 256,423.48s167.48,-75.13 167.48,-167.48h-30.42c0,75.57 -61.49,137.06 -137.06,137.06S118.94,331.58 118.94,256S180.43,118.94 256,118.94c31.49,0 61.35,10.56 85.57,29.98l-41.53,41.53c-12.91,-8.72 -28.12,-13.4 -44.04,-13.4c-43.53,0 -78.95,35.42 -78.95,78.95c0,43.53 35.42,78.95 78.95,78.95s78.95,-35.42 78.95,-78.95h-30.42c0,26.76 -21.77,48.54 -48.54,48.54S207.46,282.76 207.46,256c0,-26.76 21.77,-48.54 48.54,-48.54c7.72,0 15.15,1.8 21.84,5.18l-32.6,32.6l21.51,21.51l159.15,-159.15c36.01,41.11 55.68,93.24 55.68,148.39C481.58,316.26 458.12,372.9 415.51,415.51z" />
<path
android:fillColor="#000000"
android:pathData="M396.71,197.71m-18.42,0a18.42,18.42 0,1 1,36.85 0a18.42,18.42 0,1 1,-36.85 0" />
</vector>
@@ -1,6 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:tint="?attr/colorControlNormal"
android:viewportWidth="287.97"
android:viewportHeight="287.97">
@@ -1,22 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="503.61"
android:viewportHeight="503.61">
<path
android:fillColor="#000000"
android:pathData="M251.8,0C113.31,0 0,112.47 0,251.8s113.31,251.8 251.8,251.8s251.8,-113.31 251.8,-251.8S390.3,0 251.8,0zM251.8,486.82c-129.26,0 -235.02,-105.76 -235.02,-235.02S122.54,16.79 251.8,16.79S486.82,122.54 486.82,251.8S381.06,486.82 251.8,486.82z" />
<path
android:fillColor="#000000"
android:pathData="M251.8,83.93c-92.33,0 -167.87,75.54 -167.87,167.87c0,9.23 0.84,18.47 2.52,26.86c0,4.2 5.04,7.55 9.23,6.72c4.2,0 7.55,-5.04 6.72,-9.23c-0.84,-7.55 -1.68,-15.95 -1.68,-24.34c0,-83.1 67.99,-151.08 151.08,-151.08s151.08,67.99 151.08,151.08s-67.99,151.08 -151.08,151.08c-37.55,0 -72.9,-13.13 -100.64,-38.69l47.21,-47.21c15.02,12.31 33.58,18.75 53.43,18.75c46.16,0 83.93,-37.77 83.93,-83.93s-37.77,-83.93 -83.93,-83.93s-83.93,37.77 -83.93,83.93c0,5.04 0,9.23 1.68,13.43c0,4.2 5.04,7.55 9.23,6.72c4.2,0 7.55,-5.04 6.72,-9.23c-0.84,-3.36 -0.84,-7.55 -0.84,-10.91c0,-36.93 30.22,-67.15 67.15,-67.15s67.15,30.22 67.15,67.15c0,36.93 -30.22,67.15 -67.15,67.15c-15.56,0 -29.91,-4.78 -41.58,-13.81l24.48,-24.48c5.02,2.99 10.87,4.72 17.1,4.72c18.47,0 33.57,-15.11 33.57,-33.57s-15.11,-33.57 -33.57,-33.57s-33.57,15.11 -33.57,33.57c0,6.24 1.73,12.09 4.72,17.1l-30.74,30.74c0,0 0,0 0,0s0,0 0,0l-58.75,58.75c0,0 0,0 0,0s0,0 0,0l-30.22,30.22c-3.36,3.36 -3.36,8.39 0,11.75c1.68,1.68 3.36,2.52 5.88,2.52c2.52,0 4.2,-0.84 5.88,-2.52l24.41,-24.41c30.46,28.22 70.69,43.72 112.4,43.72c92.33,0 167.87,-74.7 167.87,-167.87C419.67,159.48 344.13,83.93 251.8,83.93zM251.8,235.02c9.23,0 16.79,7.55 16.79,16.79c0,9.23 -7.55,16.79 -16.79,16.79c-4.18,0 -8.01,-1.56 -10.95,-4.11c-0.24,-0.32 -0.5,-0.63 -0.8,-0.93s-0.61,-0.56 -0.93,-0.8c-2.55,-2.95 -4.11,-6.77 -4.11,-10.95C235.02,242.57 242.57,235.02 251.8,235.02z" />
<path
android:fillColor="#000000"
android:pathData="M92.33,159.48c0,-9.23 -7.55,-16.79 -16.79,-16.79s-16.79,7.55 -16.79,16.79s7.55,16.79 16.79,16.79S92.33,168.71 92.33,159.48z" />
<path
android:fillColor="#000000"
android:pathData="M318.95,327.34c0,9.23 7.55,16.79 16.79,16.79c9.23,0 16.79,-7.55 16.79,-16.79c0,-9.23 -7.55,-16.79 -16.79,-16.79C326.51,310.56 318.95,318.11 318.95,327.34z" />
<path
android:fillColor="#000000"
android:pathData="M360.92,109.11c9.23,0 16.79,-7.55 16.79,-16.79s-7.55,-16.79 -16.79,-16.79s-16.79,7.55 -16.79,16.79S351.68,109.11 360.92,109.11z" />
</vector>
-242
View File
@@ -1,242 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:transitionGroup="true"
android:keepScreenOn="true">
<androidx.cardview.widget.CardView
android:id="@+id/map_toolbar"
style="@style/Toolbar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageButton
android:id="@+id/map_btn_back"
style="@style/ToolbarButton"
android:layout_gravity="start|center_vertical"
android:contentDescription="@string/btn_back"
android:src="@drawable/ic_back" />
<TextView
android:id="@+id/map_timer"
style="@style/ToolbarTimer" />
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/map_card"
style="@style/SurfaceCard"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="@dimen/view_default_margin"
android:layout_marginTop="@dimen/view_default_margin"
android:layout_marginEnd="@dimen/view_default_margin"
android:layout_marginBottom="@dimen/view_default_margin"
app:layout_constraintBottom_toTopOf="@+id/map_card_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/map_toolbar">
<org.osmdroid.views.MapView
android:id="@+id/map_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/map_copyright"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="2dp"
android:ellipsize="end"
android:gravity="center"
android:includeFontPadding="false"
android:maxLines="1"
android:text="@string/map_copyright"
android:textColor="@color/textMain"
android:textSize="@dimen/text_size_copyright"
app:layout_constraintEnd_toEndOf="@+id/map_card"
app:layout_constraintStart_toStartOf="@+id/map_card"
app:layout_constraintTop_toTopOf="@+id/map_card" />
<androidx.cardview.widget.CardView
android:id="@+id/map_card_info"
style="@style/SurfaceCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/view_default_margin"
android:layout_marginEnd="@dimen/view_default_margin"
android:layout_marginBottom="@dimen/view_default_margin"
app:layout_constraintBottom_toTopOf="@+id/map_coordinator"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/map_azimuth"
style="@style/WorldMapText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/map_azimuth"
app:layout_constraintBottom_toTopOf="@+id/map_data_alt"
app:layout_constraintStart_toStartOf="@+id/map_data_period"
app:layout_constraintTop_toBottomOf="@+id/map_data_period" />
<TextView
android:id="@+id/map_data_lat"
style="@style/WorldMapText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/map_latitude"
app:layout_constraintBottom_toTopOf="@+id/map_data_qth"
app:layout_constraintStart_toStartOf="@+id/map_data_alt"
app:layout_constraintTop_toBottomOf="@+id/map_data_alt" />
<TextView
android:id="@+id/map_data_lon"
style="@style/WorldMapText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/map_longitude"
app:layout_constraintBaseline_toBaselineOf="@+id/map_data_lat"
app:layout_constraintEnd_toEndOf="@+id/map_data_dst" />
<TextView
android:id="@+id/map_data_alt"
style="@style/WorldMapText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/map_altitude"
app:layout_constraintBottom_toTopOf="@+id/map_data_lat"
app:layout_constraintStart_toStartOf="@+id/map_azimuth"
app:layout_constraintTop_toBottomOf="@+id/map_azimuth" />
<TextView
android:id="@+id/map_data_dst"
style="@style/WorldMapText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/map_distance"
app:layout_constraintBaseline_toBaselineOf="@+id/map_data_alt"
app:layout_constraintEnd_toEndOf="@+id/map_elevation" />
<TextView
android:id="@+id/map_elevation"
style="@style/WorldMapText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/map_elevation"
app:layout_constraintBaseline_toBaselineOf="@+id/map_azimuth"
app:layout_constraintEnd_toEndOf="@+id/map_data_phase" />
<TextView
android:id="@+id/map_data_period"
style="@style/WorldMapText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="6dp"
android:text="@string/map_period"
app:layout_constraintBottom_toTopOf="@+id/map_azimuth"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/map_data_phase"
style="@style/WorldMapText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:text="@string/map_phase"
app:layout_constraintBaseline_toBaselineOf="@+id/map_data_period"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/map_data_qth"
style="@style/WorldMapText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="8dp"
android:text="@string/map_qth"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/map_data_lat"
app:layout_constraintTop_toBottomOf="@+id/map_data_lat" />
<TextView
android:id="@+id/map_data_vel"
style="@style/WorldMapText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/map_velocity"
app:layout_constraintBaseline_toBaselineOf="@+id/map_data_qth"
app:layout_constraintEnd_toEndOf="@+id/map_data_lon" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/map_coordinator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/map_bottom_bar"
style="@style/BottomBar" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<Button
android:id="@+id/map_btn_prev"
style="@style/NormalButton"
android:layout_width="@dimen/button_width_max"
android:layout_marginStart="@dimen/button_margin_side"
android:text="@string/btn_prev"
app:icon="@drawable/ic_prev"
app:layout_constraintBottom_toBottomOf="@+id/map_coordinator"
app:layout_constraintStart_toStartOf="@+id/map_coordinator"
app:layout_constraintTop_toTopOf="@+id/map_coordinator" />
<TextView
android:id="@+id/map_data_visibility"
style="@style/WorldMapText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:ellipsize="end"
android:gravity="center_horizontal"
android:maxLines="1"
android:text="@string/map_visible"
app:layout_constraintBaseline_toBaselineOf="@+id/map_btn_prev"
app:layout_constraintEnd_toStartOf="@+id/map_btn_next"
app:layout_constraintStart_toEndOf="@+id/map_btn_prev" />
<Button
android:id="@+id/map_btn_next"
style="@style/NormalButton"
android:layout_width="@dimen/button_width_max"
android:layout_marginEnd="@dimen/button_margin_side"
android:text="@string/btn_next"
app:icon="@drawable/ic_next"
app:iconGravity="end"
app:layout_constraintBaseline_toBaselineOf="@+id/map_btn_prev"
app:layout_constraintEnd_toEndOf="@+id/map_coordinator" />
</androidx.constraintlayout.widget.ConstraintLayout>
+5
View File
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<org.osmdroid.views.MapView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/osm_map_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
-19
View File
@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/nav_entries"
android:icon="@drawable/ic_satellite"
android:title="@string/menu_satellites" />
<item
android:id="@+id/nav_passes"
android:icon="@drawable/ic_list"
android:title="@string/menu_passes" />
<item
android:id="@+id/nav_map"
android:icon="@drawable/ic_map"
android:title="@string/menu_map" />
<item
android:id="@+id/nav_settings"
android:icon="@drawable/ic_settings"
android:title="@string/menu_settings" />
</menu>
-94
View File
@@ -1,94 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_root"
app:startDestination="@id/nav_radar">
<fragment
android:id="@+id/nav_radar"
android:name="com.rtbishop.look4sat.presentation.radarScreen.RadarFragment"
tools:layout="@layout/fragment_radar">
<argument
android:name="catNum"
android:defaultValue="-1"
app:argType="integer" />
<argument
android:name="aosTime"
android:defaultValue="0L"
app:argType="long" />
</fragment>
<fragment
android:id="@+id/nav_map"
android:name="com.rtbishop.look4sat.presentation.mapScreen.MapFragment"
tools:layout="@layout/fragment_map">
<argument
android:name="catNum"
android:defaultValue="-1"
app:argType="integer" />
</fragment>
<fragment
android:id="@+id/nav_settings"
android:name="com.rtbishop.look4sat.presentation.settingsScreen.SettingsFragment"
tools:layout="@layout/fragment_settings" />
<dialog
android:id="@+id/nav_modes"
android:name="com.rtbishop.look4sat.presentation.entriesScreen.ModesDialog"
tools:layout="@layout/dialog_modes" />
<dialog
android:id="@+id/nav_position"
android:name="com.rtbishop.look4sat.presentation.settingsScreen.PositionDialog"
tools:layout="@layout/dialog_position" />
<dialog
android:id="@+id/nav_locator"
android:name="com.rtbishop.look4sat.presentation.settingsScreen.LocatorDialog"
tools:layout="@layout/dialog_locator" />
<action
android:id="@+id/global_to_entries"
app:destination="@id/nav_entries"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
<action
android:id="@+id/global_to_passes"
app:destination="@id/nav_passes"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
<action
android:id="@+id/global_to_radar"
app:destination="@id/nav_radar"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
<action
android:id="@+id/global_to_map"
app:destination="@id/nav_map"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
<action
android:id="@+id/global_to_settings"
app:destination="@id/nav_settings"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
<action
android:id="@+id/global_to_position"
app:destination="@id/nav_position"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
<action
android:id="@+id/global_to_locator"
app:destination="@id/nav_locator"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
</navigation>