mirror of
https://github.com/rt-bishop/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Added MapViewModel.kt, cleaned up MapFragment.kt
This commit is contained in:
1 parent
19a0649cb3
commit
b850c7a41d
3 files changed
+200
-146
No files matched your search
@@ -1,28 +1,24 @@
|
||||
package com.rtbishop.look4sat.ui.mainScreen
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorMatrix
|
||||
import android.graphics.ColorMatrixColorFilter
|
||||
import android.graphics.Paint
|
||||
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.activityViewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.github.amsacode.predict4java.GroundStationPosition
|
||||
import com.github.amsacode.predict4java.Position
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.SharedViewModel
|
||||
import com.rtbishop.look4sat.data.Result
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.databinding.FragmentMapBinding
|
||||
import com.rtbishop.look4sat.utility.PrefsManager
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.osmdroid.config.Configuration
|
||||
import org.osmdroid.tileprovider.tilesource.ITileSource
|
||||
import org.osmdroid.tileprovider.tilesource.TileSourcePolicy
|
||||
@@ -33,53 +29,35 @@ import org.osmdroid.views.CustomZoomButtonsController
|
||||
import org.osmdroid.views.overlay.*
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MapFragment : Fragment(R.layout.fragment_map) {
|
||||
|
||||
@Inject
|
||||
lateinit var prefsManager: PrefsManager
|
||||
|
||||
private lateinit var binding: FragmentMapBinding
|
||||
lateinit var preferences: SharedPreferences
|
||||
private lateinit var trackPaint: Paint
|
||||
private lateinit var footprintPaint: Paint
|
||||
private lateinit var selectedPass: SatPass
|
||||
private lateinit var allPasses: List<SatPass>
|
||||
private lateinit var nameFormat: String
|
||||
private lateinit var altFormat: String
|
||||
private lateinit var distFormat: String
|
||||
private lateinit var velFormat: String
|
||||
private lateinit var latLonFormat: String
|
||||
private lateinit var selectedSat: SatPass
|
||||
private val dateNow = Date()
|
||||
private val viewModel: SharedViewModel by activityViewModels()
|
||||
private var iconPos: Drawable? = null
|
||||
private var iconSat: Drawable? = null
|
||||
private val viewModel: MapViewModel by viewModels()
|
||||
private val sharedViewModel: SharedViewModel by activityViewModels()
|
||||
private var binding: FragmentMapBinding? = null
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentMapBinding.bind(view)
|
||||
setupComponents(view)
|
||||
setupMapView()
|
||||
setupPosOverlay()
|
||||
setupObservers()
|
||||
}
|
||||
|
||||
private fun setupMapView() {
|
||||
Configuration.getInstance()
|
||||
.load(requireContext().applicationContext, prefsManager.preferences)
|
||||
val filter = getColorFilter(ContextCompat.getColor(requireContext(), R.color.satTrack))
|
||||
binding.mapView.apply {
|
||||
setMultiTouchControls(true)
|
||||
setTileSource(getWikimediaTileSource())
|
||||
minZoomLevel = 2.5
|
||||
maxZoomLevel = 6.0
|
||||
controller.setZoom(3.0)
|
||||
zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
|
||||
overlayManager.tilesOverlay.loadingBackgroundColor = Color.TRANSPARENT
|
||||
overlayManager.tilesOverlay.loadingLineColor = Color.TRANSPARENT
|
||||
overlayManager.tilesOverlay.setColorFilter(filter)
|
||||
setScrollableAreaLimitDouble(BoundingBox(85.05, 180.0, -85.05, -180.0))
|
||||
|
||||
// add overlays: 0 - GSP, 1 - SatTrack, 2 - SatFootprint, 3 - SatIcons
|
||||
val layers = listOf(FolderOverlay(), FolderOverlay(), FolderOverlay(), FolderOverlay())
|
||||
overlays.addAll(layers)
|
||||
}
|
||||
private fun setupComponents(view: View) {
|
||||
Configuration.getInstance().load(requireContext().applicationContext, preferences)
|
||||
binding = FragmentMapBinding.bind(view)
|
||||
trackPaint = Paint().apply {
|
||||
strokeWidth = 2f
|
||||
style = Paint.Style.STROKE
|
||||
@@ -93,119 +71,105 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||
color = ContextCompat.getColor(requireContext(), R.color.satFootprint)
|
||||
isAntiAlias = true
|
||||
}
|
||||
iconPos = ContextCompat.getDrawable(requireContext(), R.drawable.ic_map_pos)
|
||||
iconSat = ContextCompat.getDrawable(requireContext(), R.drawable.ic_map_sat)
|
||||
nameFormat = getString(R.string.pat_osm_idName)
|
||||
altFormat = getString(R.string.pat_altitude)
|
||||
distFormat = getString(R.string.pat_distance)
|
||||
velFormat = getString(R.string.pat_osm_vel)
|
||||
latLonFormat = getString(R.string.pat_osm_latLon)
|
||||
}
|
||||
|
||||
private fun getWikimediaTileSource(): ITileSource {
|
||||
val copyright = resources.getString(R.string.map_copyright)
|
||||
val sources = arrayOf("https://maps.wikimedia.org/osm-intl/")
|
||||
val policy = TileSourcePolicy(
|
||||
1, TileSourcePolicy.FLAG_NO_BULK and TileSourcePolicy.FLAG_NO_PREVENTIVE and
|
||||
TileSourcePolicy.FLAG_USER_AGENT_MEANINGFUL and TileSourcePolicy.FLAG_USER_AGENT_NORMALIZED
|
||||
)
|
||||
return XYTileSource("wikimedia", 2, 6, 256, ".png", sources, copyright, policy)
|
||||
}
|
||||
|
||||
private fun setupPosOverlay() {
|
||||
val gsp = prefsManager.getStationPosition()
|
||||
Marker(binding.mapView).apply {
|
||||
setInfoWindow(null)
|
||||
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
|
||||
icon = iconPos
|
||||
position = GeoPoint(gsp.latitude, gsp.longitude)
|
||||
binding.mapView.overlays[0] = this
|
||||
binding.mapView.invalidate()
|
||||
private fun setupMapView() {
|
||||
binding?.apply {
|
||||
mapView.apply {
|
||||
setMultiTouchControls(true)
|
||||
setTileSource(getTileSource())
|
||||
minZoomLevel = 2.5
|
||||
maxZoomLevel = 6.0
|
||||
controller.setZoom(3.0)
|
||||
zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
|
||||
overlayManager.tilesOverlay.loadingBackgroundColor = Color.TRANSPARENT
|
||||
overlayManager.tilesOverlay.loadingLineColor = Color.TRANSPARENT
|
||||
overlayManager.tilesOverlay.setColorFilter(getColorFilter())
|
||||
setScrollableAreaLimitDouble(BoundingBox(85.05, 180.0, -85.05, -180.0))
|
||||
// add overlays: 0 - GSP, 1 - SatTrack, 2 - SatFootprint, 3 - SatIcons
|
||||
overlays.addAll(Array(4) { FolderOverlay() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupObservers() {
|
||||
viewModel.getPasses().observe(viewLifecycleOwner, { satPasses ->
|
||||
if (satPasses is Result.Success) {
|
||||
if (satPasses.data.isNotEmpty()) {
|
||||
allPasses = satPasses.data.distinctBy { it.tle }
|
||||
selectedPass = allPasses[0]
|
||||
binding.fabPrev.setOnClickListener { changeSelection(true) }
|
||||
binding.fabNext.setOnClickListener { changeSelection(false) }
|
||||
setupSatOverlay(allPasses)
|
||||
}
|
||||
viewModel.getGSP().observe(viewLifecycleOwner, { setupPosOverlay(it) })
|
||||
sharedViewModel.getPasses().observe(viewLifecycleOwner, {
|
||||
if (it is Result.Success && it.data.isNotEmpty()) {
|
||||
viewModel.setPasses(it.data)
|
||||
binding?.fabPrev?.setOnClickListener { viewModel.changeSelection(true) }
|
||||
binding?.fabNext?.setOnClickListener { viewModel.changeSelection(false) }
|
||||
}
|
||||
})
|
||||
viewModel.getSelectedPass().observe(viewLifecycleOwner, { satPass ->
|
||||
satPass?.let {
|
||||
selectedSat = satPass
|
||||
setSelectedSatDetails(satPass)
|
||||
scrollToSat(satPass)
|
||||
}
|
||||
})
|
||||
viewModel.getSatMarkers().observe(viewLifecycleOwner, {
|
||||
setMarkers(it)
|
||||
setSelectedSatDetails(selectedSat)
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupSatOverlay(passList: List<SatPass>) {
|
||||
lifecycleScope.launch {
|
||||
while (true) {
|
||||
dateNow.time = System.currentTimeMillis()
|
||||
setSatDetails(selectedPass)
|
||||
binding.mapView.overlays[3] = getSatMarkers(passList)
|
||||
binding.mapView.invalidate()
|
||||
delay(2000)
|
||||
private fun setupPosOverlay(gsp: GroundStationPosition) {
|
||||
binding?.apply {
|
||||
Marker(mapView).apply {
|
||||
setInfoWindow(null)
|
||||
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
|
||||
icon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_map_pos)
|
||||
position = GeoPoint(gsp.latitude, gsp.longitude)
|
||||
mapView.overlays[0] = this
|
||||
mapView.invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun changeSelection(decrement: Boolean) {
|
||||
val index = allPasses.indexOf(selectedPass)
|
||||
selectedPass = if (decrement) {
|
||||
if (index > 0) allPasses[index - 1] else allPasses[allPasses.size - 1]
|
||||
} else {
|
||||
if (index < allPasses.size - 1) allPasses[index + 1] else allPasses[0]
|
||||
private fun setSelectedSatDetails(satPass: SatPass) {
|
||||
val satPos = satPass.predictor.getSatPos(dateNow)
|
||||
val osmPos = viewModel.getOsmPosition(satPos.latitude, satPos.longitude, true)
|
||||
binding?.apply {
|
||||
idName.text = String.format(nameFormat, satPass.tle.catnum, satPass.tle.name)
|
||||
altitude.text = String.format(altFormat, satPos.altitude)
|
||||
distance.text = String.format(distFormat, satPos.range)
|
||||
velocity.text = String.format(velFormat, viewModel.getSatVelocity(satPos.altitude))
|
||||
latLon.text = String.format(latLonFormat, osmPos.lat, osmPos.lon)
|
||||
mapView.overlays[1] = getSatTrack(satPass)
|
||||
mapView.overlays[2] = getSatFootprint(satPass)
|
||||
mapView.invalidate()
|
||||
}
|
||||
val satPos = selectedPass.predictor.getSatPos(dateNow)
|
||||
val osmPos = getOsmPosition(satPos.latitude, satPos.longitude, true)
|
||||
setSatDetails(selectedPass)
|
||||
binding.mapView.controller.animateTo(GeoPoint(osmPos.lat, osmPos.lon))
|
||||
}
|
||||
|
||||
private suspend fun getSatMarkers(passList: List<SatPass>): Overlay =
|
||||
withContext(Dispatchers.Default) {
|
||||
val items = FolderOverlay()
|
||||
passList.forEach { satPass ->
|
||||
val satPos = satPass.predictor.getSatPos(dateNow)
|
||||
val osmPos = getOsmPosition(satPos.latitude, satPos.longitude, true)
|
||||
Marker(binding.mapView).apply {
|
||||
private fun scrollToSat(satPass: SatPass) {
|
||||
val satPos = satPass.predictor.getSatPos(dateNow)
|
||||
val osmPos = viewModel.getOsmPosition(satPos.latitude, satPos.longitude, true)
|
||||
binding?.mapView?.controller?.animateTo(GeoPoint(osmPos.lat, osmPos.lon))
|
||||
}
|
||||
|
||||
private fun setMarkers(map: Map<SatPass, Position>) {
|
||||
dateNow.time = System.currentTimeMillis()
|
||||
binding?.apply {
|
||||
val markers = FolderOverlay()
|
||||
map.entries.forEach {
|
||||
Marker(mapView).apply {
|
||||
setInfoWindow(null)
|
||||
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
|
||||
icon = iconSat
|
||||
position = GeoPoint(osmPos.lat, osmPos.lon)
|
||||
setOnMarkerClickListener { _, _ ->
|
||||
selectedPass = satPass
|
||||
setSatDetails(satPass)
|
||||
true
|
||||
}
|
||||
items.add(this)
|
||||
icon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_map_sat)
|
||||
position = GeoPoint(it.value.lat, it.value.lon)
|
||||
setOnMarkerClickListener { _, _ -> viewModel.setSelectedSat(it.key) }
|
||||
markers.add(this)
|
||||
}
|
||||
}
|
||||
return@withContext items
|
||||
mapView.overlays[3] = markers
|
||||
mapView.invalidate()
|
||||
}
|
||||
|
||||
private fun setSatDetails(satPass: SatPass) {
|
||||
setSatInfo(satPass)
|
||||
binding.mapView.overlays[1] = getSatTrack(satPass)
|
||||
binding.mapView.overlays[2] = getSatFootprint(satPass)
|
||||
}
|
||||
|
||||
private fun setSatInfo(satPass: SatPass) {
|
||||
val satPos = satPass.predictor.getSatPos(dateNow)
|
||||
val osmPos = getOsmPosition(satPos.latitude, satPos.longitude, true)
|
||||
val catNum = satPass.tle.catnum
|
||||
val name = satPass.tle.name
|
||||
val satVelocity = getSatVelocity(satPos.altitude)
|
||||
binding.apply {
|
||||
idName.text = String.format(getString(R.string.pat_osm_idName), catNum, name)
|
||||
altitude.text = String.format(getString(R.string.pat_altitude), satPos.altitude)
|
||||
distance.text = String.format(getString(R.string.pat_distance), satPos.range)
|
||||
velocity.text = String.format(getString(R.string.pat_osm_vel), satVelocity)
|
||||
latLon.text = String.format(getString(R.string.pat_osm_latLon), osmPos.lat, osmPos.lon)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSatVelocity(satAlt: Double): Double {
|
||||
val earthG = 6.674 * 10.0.pow(-11)
|
||||
val earthM = 5.98 * 10.0.pow(24)
|
||||
val radius = 6.37 * 10.0.pow(6) + satAlt * 10.0.pow(3)
|
||||
return sqrt(earthG * earthM / radius) / 1000
|
||||
}
|
||||
|
||||
private fun getSatTrack(pass: SatPass): Overlay {
|
||||
@@ -216,7 +180,7 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||
var oldLon = 0.0
|
||||
|
||||
positions.forEach {
|
||||
val osmPos = getOsmPosition(it.latitude, it.longitude, true)
|
||||
val osmPos = viewModel.getOsmPosition(it.latitude, it.longitude, true)
|
||||
if (oldLon < -170.0 && osmPos.lon > 170.0 || oldLon > 170.0 && osmPos.lon < -170.0) {
|
||||
val currentPoints = mutableListOf<GeoPoint>()
|
||||
currentPoints.addAll(trackPoints)
|
||||
@@ -245,7 +209,7 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||
var zeroPoint = GeoPoint(0.0, 0.0)
|
||||
|
||||
rangeCircle.withIndex().forEach {
|
||||
val osmPos = getOsmPosition(it.value.lat, it.value.lon, false)
|
||||
val osmPos = viewModel.getOsmPosition(it.value.lat, it.value.lon, false)
|
||||
if (it.index == 0) zeroPoint = GeoPoint(osmPos.lat, osmPos.lon)
|
||||
rangePoints.add(GeoPoint(osmPos.lat, osmPos.lon))
|
||||
}
|
||||
@@ -258,7 +222,8 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getColorFilter(targetColor: Int): ColorMatrixColorFilter {
|
||||
private fun getColorFilter(): ColorMatrixColorFilter {
|
||||
val targetColor = ContextCompat.getColor(requireContext(), R.color.satTrack)
|
||||
val newR = Color.red(targetColor) / 255f
|
||||
val newG = Color.green(targetColor) / 255f
|
||||
val newB = Color.blue(targetColor) / 255f
|
||||
@@ -282,17 +247,18 @@ class MapFragment : Fragment(R.layout.fragment_map) {
|
||||
return ColorMatrixColorFilter(tintedMatrix)
|
||||
}
|
||||
|
||||
private fun getOsmPosition(lat: Double, lon: Double, inRadians: Boolean): Position {
|
||||
return if (inRadians) {
|
||||
var osmLat = Math.toDegrees(lat)
|
||||
var osmLon = Math.toDegrees(lon)
|
||||
if (osmLat > 85.05) osmLat = 85.05 else if (osmLat < -85.05) osmLat = -85.05
|
||||
if (osmLon > 180f) osmLon -= 360f
|
||||
Position(osmLat, osmLon)
|
||||
} else {
|
||||
val osmLat = if (lat > 85.05) 85.05 else if (lat < -85.05) -85.05 else lat
|
||||
val osmLon = if (lon > 180.0) lon - 360.0 else lon
|
||||
Position(osmLat, osmLon)
|
||||
}
|
||||
private fun getTileSource(): ITileSource {
|
||||
val copyright = resources.getString(R.string.map_copyright)
|
||||
val sources = arrayOf("https://maps.wikimedia.org/osm-intl/")
|
||||
val policy = TileSourcePolicy(
|
||||
1, TileSourcePolicy.FLAG_NO_BULK and TileSourcePolicy.FLAG_NO_PREVENTIVE and
|
||||
TileSourcePolicy.FLAG_USER_AGENT_MEANINGFUL and TileSourcePolicy.FLAG_USER_AGENT_NORMALIZED
|
||||
)
|
||||
return XYTileSource("wikimedia", 2, 6, 256, ".png", sources, copyright, policy)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.rtbishop.look4sat.ui.mainScreen
|
||||
|
||||
import androidx.hilt.lifecycle.ViewModelInject
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.github.amsacode.predict4java.GroundStationPosition
|
||||
import com.github.amsacode.predict4java.Position
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.utility.PrefsManager
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class MapViewModel @ViewModelInject constructor(prefsManager: PrefsManager) : ViewModel() {
|
||||
|
||||
private val dateNow = Date()
|
||||
private var filteredPasses = listOf<SatPass>()
|
||||
|
||||
private val _gsp = MutableLiveData(prefsManager.getStationPosition())
|
||||
fun getGSP(): LiveData<GroundStationPosition> = _gsp
|
||||
|
||||
private val _selectedPass = MutableLiveData<SatPass?>()
|
||||
fun getSelectedPass(): LiveData<SatPass?> = _selectedPass
|
||||
|
||||
private val _satMarkers = MutableLiveData<Map<SatPass, Position>>()
|
||||
fun getSatMarkers(): LiveData<Map<SatPass, Position>> = _satMarkers
|
||||
|
||||
fun setPasses(passesList: List<SatPass>) {
|
||||
filteredPasses = passesList.distinctBy { it.tle }
|
||||
_selectedPass.value = filteredPasses[0]
|
||||
calculateSatPos(filteredPasses)
|
||||
}
|
||||
|
||||
private fun calculateSatPos(passes: List<SatPass>) {
|
||||
viewModelScope.launch {
|
||||
while (true) {
|
||||
val passesMap = mutableMapOf<SatPass, Position>()
|
||||
dateNow.time = System.currentTimeMillis()
|
||||
passes.forEach {
|
||||
val satPos = it.predictor.getSatPos(dateNow)
|
||||
val osmPos = getOsmPosition(satPos.latitude, satPos.longitude, true)
|
||||
passesMap[it] = osmPos
|
||||
}
|
||||
_satMarkers.value = passesMap
|
||||
delay(2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setSelectedSat(satPass: SatPass): Boolean {
|
||||
_selectedPass.value = satPass
|
||||
return true
|
||||
}
|
||||
|
||||
fun changeSelection(decrement: Boolean) {
|
||||
val index = filteredPasses.indexOf(_selectedPass.value)
|
||||
_selectedPass.value = if (decrement) {
|
||||
if (index > 0) filteredPasses[index - 1] else filteredPasses[filteredPasses.size - 1]
|
||||
} else {
|
||||
if (index < filteredPasses.size - 1) filteredPasses[index + 1] else filteredPasses[0]
|
||||
}
|
||||
}
|
||||
|
||||
fun getSatVelocity(satAlt: Double): Double {
|
||||
val earthG = 6.674 * 10.0.pow(-11)
|
||||
val earthM = 5.98 * 10.0.pow(24)
|
||||
val radius = 6.37 * 10.0.pow(6) + satAlt * 10.0.pow(3)
|
||||
return sqrt(earthG * earthM / radius) / 1000
|
||||
}
|
||||
|
||||
fun getOsmPosition(lat: Double, lon: Double, inRadians: Boolean): Position {
|
||||
return if (inRadians) {
|
||||
var osmLat = Math.toDegrees(lat)
|
||||
var osmLon = Math.toDegrees(lon)
|
||||
if (osmLat > 85.05) osmLat = 85.05 else if (osmLat < -85.05) osmLat = -85.05
|
||||
if (osmLon > 180f) osmLon -= 360f
|
||||
Position(osmLat, osmLon)
|
||||
} else {
|
||||
val osmLat = if (lat > 85.05) 85.05 else if (lat < -85.05) -85.05 else lat
|
||||
val osmLon = if (lon > 180.0) lon - 360.0 else lon
|
||||
Position(osmLat, osmLon)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import com.github.amsacode.predict4java.GroundStationPosition
|
||||
import com.rtbishop.look4sat.data.PassPrefs
|
||||
import javax.inject.Inject
|
||||
|
||||
class PrefsManager @Inject constructor(val preferences: SharedPreferences) {
|
||||
class PrefsManager @Inject constructor(private val preferences: SharedPreferences) {
|
||||
companion object {
|
||||
const val keyLatitude = "latitude"
|
||||
const val keyLongitude = "longitude"
|
||||
|
||||
Reference in new issue
Block a user