mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-05 12:07:25 +00:00
Code separation and cleanup for future testing
This commit is contained in:
1 parent
38b9feb829
commit
b5fa5c0673
10 files changed
+311
-152
No files matched your search
@@ -20,11 +20,6 @@
|
|||||||
package com.rtbishop.look4sat
|
package com.rtbishop.look4sat
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.location.LocationManager
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.content.edit
|
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
@@ -36,103 +31,58 @@ import com.rtbishop.look4sat.predict4kotlin.PassPredictor
|
|||||||
import com.rtbishop.look4sat.repo.Repository
|
import com.rtbishop.look4sat.repo.Repository
|
||||||
import com.rtbishop.look4sat.repo.SatPass
|
import com.rtbishop.look4sat.repo.SatPass
|
||||||
import com.rtbishop.look4sat.repo.Transmitter
|
import com.rtbishop.look4sat.repo.Transmitter
|
||||||
|
import com.rtbishop.look4sat.utility.DataManager
|
||||||
|
import com.rtbishop.look4sat.utility.PrefsManager
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.FileNotFoundException
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.ObjectInputStream
|
|
||||||
import java.io.ObjectOutputStream
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class MainViewModel(application: Application) : AndroidViewModel(application) {
|
class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
|
||||||
private val tag = "MainViewModel"
|
|
||||||
|
|
||||||
private val app = application
|
private val app = application
|
||||||
private val keyHours = application.getString(R.string.pref_hours_ahead_key)
|
|
||||||
private val keyMinEl = application.getString(R.string.pref_min_el_key)
|
|
||||||
private val keyLat = application.getString(R.string.pref_lat_key)
|
|
||||||
private val keyLon = application.getString(R.string.pref_lon_key)
|
|
||||||
private val keyAlt = application.getString(R.string.pref_alt_key)
|
|
||||||
private val keyDelay = application.getString(R.string.pref_refresh_rate_key)
|
|
||||||
private val tleMainListFileName = "tleFile.txt"
|
|
||||||
private val tleSelectionFileName = "tleSelection"
|
|
||||||
|
|
||||||
private val _debugMessage = MutableLiveData<String>()
|
|
||||||
val debugMessage: LiveData<String> = _debugMessage
|
|
||||||
|
|
||||||
private val _satPassList = MutableLiveData<MutableList<SatPass>>()
|
|
||||||
val satPassList: LiveData<MutableList<SatPass>> = _satPassList
|
|
||||||
|
|
||||||
private val _gsp = MutableLiveData<GroundStationPosition>()
|
|
||||||
val gsp: LiveData<GroundStationPosition> = _gsp
|
|
||||||
|
|
||||||
private val urlList = listOf("https://celestrak.com/NORAD/elements/active.txt")
|
private val urlList = listOf("https://celestrak.com/NORAD/elements/active.txt")
|
||||||
|
private val _satPassList = MutableLiveData<MutableList<SatPass>>()
|
||||||
|
private val _debugMessage = MutableLiveData<String>()
|
||||||
|
private val _gsp = MutableLiveData<GroundStationPosition>()
|
||||||
private var calculationJob: Job? = null
|
private var calculationJob: Job? = null
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var locationManager: LocationManager
|
|
||||||
@Inject
|
|
||||||
lateinit var preferences: SharedPreferences
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var repository: Repository
|
lateinit var repository: Repository
|
||||||
|
@Inject
|
||||||
lateinit var tleMainList: List<TLE>
|
lateinit var dataManager: DataManager
|
||||||
lateinit var tleSelection: MutableList<Int>
|
@Inject
|
||||||
|
lateinit var prefsManager: PrefsManager
|
||||||
|
|
||||||
init {
|
init {
|
||||||
(app as Look4SatApp).appComponent.inject(this)
|
(app as Look4SatApp).appComponent.inject(this)
|
||||||
loadDataFromDisk()
|
setGroundStationPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
val delay: Long
|
var tleMainList = dataManager.loadTleList()
|
||||||
get() = preferences.getString(keyDelay, "3000")!!.toLong()
|
var tleSelection = dataManager.loadSelectionList()
|
||||||
|
|
||||||
val hoursAhead: Int
|
fun getGSP(): LiveData<GroundStationPosition> = _gsp
|
||||||
get() = preferences.getInt(keyHours, 8)
|
fun getDebugMessage(): LiveData<String> = _debugMessage
|
||||||
|
fun getSatPassList(): LiveData<MutableList<SatPass>> = _satPassList
|
||||||
val minEl: Double
|
fun getRefreshRate() = prefsManager.getRefreshRate()
|
||||||
get() = preferences.getDouble(keyMinEl, 16.0)
|
fun getHoursAhead() = prefsManager.getHoursAhead()
|
||||||
|
fun getMinElevation() = prefsManager.getMinElevation()
|
||||||
fun setGroundStationPosition() {
|
fun setGroundStationPosition() = _gsp.postValue(prefsManager.getGroundStationPosition())
|
||||||
val lat = preferences.getString(keyLat, "0.0")!!.toDouble()
|
|
||||||
val lon = preferences.getString(keyLon, "0.0")!!.toDouble()
|
|
||||||
val alt = preferences.getString(keyAlt, "0.0")!!.toDouble()
|
|
||||||
_gsp.postValue(GroundStationPosition(lat, lon, alt))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateLocation() {
|
fun updateLocation() {
|
||||||
val passiveProvider = LocationManager.PASSIVE_PROVIDER
|
dataManager.getLastKnownLocation()?.let {
|
||||||
try {
|
prefsManager.setGroundStationPosition(it)
|
||||||
val location = locationManager.getLastKnownLocation(passiveProvider)
|
_gsp.postValue(it)
|
||||||
|
|
||||||
val lat = location?.latitude ?: 0.0
|
|
||||||
val lon = location?.longitude ?: 0.0
|
|
||||||
val alt = location?.altitude ?: 0.0
|
|
||||||
|
|
||||||
preferences.edit {
|
|
||||||
putString(keyLat, lat.toString())
|
|
||||||
putString(keyLon, lon.toString())
|
|
||||||
putString(keyAlt, alt.toString())
|
|
||||||
apply()
|
|
||||||
}
|
|
||||||
_gsp.postValue(GroundStationPosition(lat, lon, alt))
|
|
||||||
_debugMessage.postValue(app.getString(R.string.update_loc_success))
|
|
||||||
} catch (e: SecurityException) {
|
|
||||||
_debugMessage.postValue(app.getString(R.string.err_no_permissions))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setPassPrefs(hoursAhead: Int, minEl: Double) {
|
fun setPassPrefs(hoursAhead: Int, minEl: Double) {
|
||||||
preferences.edit {
|
prefsManager.setHoursAhead(hoursAhead)
|
||||||
putInt(keyHours, hoursAhead)
|
prefsManager.setMinElevation(minEl)
|
||||||
putDouble(keyMinEl, minEl)
|
|
||||||
apply()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateAndSaveTleFile() {
|
fun updateAndSaveTleFile() {
|
||||||
@@ -140,12 +90,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
try {
|
try {
|
||||||
val inputStream = repository.getStreamForUrl(urlList)
|
val inputStream = repository.getStreamForUrl(urlList)
|
||||||
val tleList = TLE.importSat(inputStream).apply { sortBy { it.name } }
|
val tleList = TLE.importSat(inputStream).apply { sortBy { it.name } }
|
||||||
val fileOutStream = app.openFileOutput(tleMainListFileName, Context.MODE_PRIVATE)
|
dataManager.saveTleList(tleList)
|
||||||
ObjectOutputStream(fileOutStream).apply {
|
|
||||||
writeObject(tleList)
|
|
||||||
flush()
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
tleMainList = tleList
|
tleMainList = tleList
|
||||||
tleSelection = mutableListOf()
|
tleSelection = mutableListOf()
|
||||||
_debugMessage.postValue(app.getString(R.string.update_tle_success))
|
_debugMessage.postValue(app.getString(R.string.update_tle_success))
|
||||||
@@ -168,35 +113,21 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
|
|
||||||
fun updateAndSaveSelectionList(list: MutableList<Int>) {
|
fun updateAndSaveSelectionList(list: MutableList<Int>) {
|
||||||
tleSelection = list
|
tleSelection = list
|
||||||
try {
|
dataManager.saveSelectionList(list)
|
||||||
val fileOutputStream = app.openFileOutput(tleSelectionFileName, Context.MODE_PRIVATE)
|
|
||||||
ObjectOutputStream(fileOutputStream).apply {
|
|
||||||
writeObject(list)
|
|
||||||
flush()
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
} catch (exception: IOException) {
|
|
||||||
_debugMessage.postValue(exception.toString())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPasses() {
|
fun getPasses() {
|
||||||
calculationJob?.cancel()
|
calculationJob?.cancel()
|
||||||
val passList = mutableListOf<SatPass>()
|
var passList = mutableListOf<SatPass>()
|
||||||
val dateNow = Date()
|
|
||||||
val dateFuture = Calendar.getInstance().let {
|
|
||||||
it.time = dateNow
|
|
||||||
it.add(Calendar.HOUR, hoursAhead)
|
|
||||||
it.time
|
|
||||||
}
|
|
||||||
calculationJob = viewModelScope.launch {
|
calculationJob = viewModelScope.launch {
|
||||||
if (tleMainList.isNotEmpty() && tleSelection.isNotEmpty()) {
|
if (tleMainList.isNotEmpty() && tleSelection.isNotEmpty()) {
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
|
val dateNow = Date()
|
||||||
tleSelection.forEach { indexOfSelection ->
|
tleSelection.forEach { indexOfSelection ->
|
||||||
val tle = tleMainList[indexOfSelection]
|
val tle = tleMainList[indexOfSelection]
|
||||||
try {
|
try {
|
||||||
val predictor = PassPredictor(tle, gsp.value!!)
|
val predictor = PassPredictor(tle, getGSP().value!!)
|
||||||
val passes = predictor.getPasses(dateNow, hoursAhead, true)
|
val passes = predictor.getPasses(dateNow, getHoursAhead(), true)
|
||||||
passes.forEach {
|
passes.forEach {
|
||||||
passList.add(SatPass(tle, predictor, it))
|
passList.add(SatPass(tle, predictor, it))
|
||||||
}
|
}
|
||||||
@@ -206,10 +137,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
_debugMessage.postValue(app.getString(R.string.err_sat_wont_pass))
|
_debugMessage.postValue(app.getString(R.string.err_sat_wont_pass))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
passList.removeAll { it.pass.startTime.after(dateFuture) }
|
passList = filterAndSortList(passList, getHoursAhead())
|
||||||
passList.removeAll { it.pass.endTime.before(dateNow) }
|
|
||||||
passList.removeAll { it.pass.maxEl < minEl }
|
|
||||||
passList.sortBy { it.pass.startTime }
|
|
||||||
}
|
}
|
||||||
_satPassList.postValue(passList)
|
_satPassList.postValue(passList)
|
||||||
} else {
|
} else {
|
||||||
@@ -219,42 +147,24 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun filterAndSortList(
|
||||||
|
list: MutableList<SatPass>,
|
||||||
|
hoursAhead: Int
|
||||||
|
): MutableList<SatPass> {
|
||||||
|
val dateNow = Date()
|
||||||
|
val dateFuture = Calendar.getInstance().let {
|
||||||
|
it.time = dateNow
|
||||||
|
it.add(Calendar.HOUR, hoursAhead)
|
||||||
|
it.time
|
||||||
|
}
|
||||||
|
list.removeAll { it.pass.startTime.after(dateFuture) }
|
||||||
|
list.removeAll { it.pass.endTime.before(dateNow) }
|
||||||
|
list.removeAll { it.pass.maxEl < getMinElevation() }
|
||||||
|
list.sortBy { it.pass.startTime }
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun getTransmittersForSat(id: Int): List<Transmitter> {
|
suspend fun getTransmittersForSat(id: Int): List<Transmitter> {
|
||||||
return repository.getTransmittersForSat(id)
|
return repository.getTransmittersForSat(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
private fun loadDataFromDisk() {
|
|
||||||
tleMainList = try {
|
|
||||||
val tleStream = app.openFileInput(tleMainListFileName)
|
|
||||||
val tleList = ObjectInputStream(tleStream).readObject()
|
|
||||||
tleList as List<TLE>
|
|
||||||
} catch (exception: FileNotFoundException) {
|
|
||||||
Log.w(tag, app.getString(R.string.err_no_tle_file))
|
|
||||||
emptyList()
|
|
||||||
} catch (exception: IOException) {
|
|
||||||
Log.w(tag, exception.toString())
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
tleSelection = try {
|
|
||||||
val selectionStream = app.openFileInput(tleSelectionFileName)
|
|
||||||
val selectionList = ObjectInputStream(selectionStream).readObject()
|
|
||||||
selectionList as MutableList<Int>
|
|
||||||
} catch (exception: FileNotFoundException) {
|
|
||||||
Log.w(tag, app.getString(R.string.err_no_selection_file))
|
|
||||||
mutableListOf()
|
|
||||||
} catch (exception: IOException) {
|
|
||||||
Log.w(tag, exception.toString())
|
|
||||||
mutableListOf()
|
|
||||||
}
|
|
||||||
setGroundStationPosition()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun SharedPreferences.Editor.putDouble(key: String, double: Double) {
|
|
||||||
putLong(key, double.toRawBits())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun SharedPreferences.getDouble(key: String, default: Double): Double {
|
|
||||||
return Double.fromBits(getLong(key, default.toRawBits()))
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||||
|
* Copyright (C) 2019, 2020 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.rtbishop.look4sat.di
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.location.LocationManager
|
||||||
|
import com.rtbishop.look4sat.utility.DataManager
|
||||||
|
import com.rtbishop.look4sat.utility.PrefsManager
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
class UtilityModule {
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun providePrefsManager(preferences: SharedPreferences): PrefsManager {
|
||||||
|
return PrefsManager(preferences)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideDataManager(locationManager: LocationManager, context: Context): DataManager {
|
||||||
|
return DataManager(locationManager, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -103,7 +103,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupObservers() {
|
private fun setupObservers() {
|
||||||
viewModel.debugMessage.observe(this, Observer { message ->
|
viewModel.getDebugMessage().observe(this, Observer { message ->
|
||||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||||
when (message) {
|
when (message) {
|
||||||
getString(R.string.update_loc_success) -> drawerBinding.drawerBtnLoc.isEnabled =
|
getString(R.string.update_loc_success) -> drawerBinding.drawerBtnLoc.isEnabled =
|
||||||
@@ -119,7 +119,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.gsp.observe(this, Observer { gsp ->
|
viewModel.getGSP().observe(this, Observer { gsp ->
|
||||||
drawerBinding.drawerLatValue.text =
|
drawerBinding.drawerLatValue.text =
|
||||||
String.format(getString(R.string.pat_location), gsp.latitude)
|
String.format(getString(R.string.pat_location), gsp.latitude)
|
||||||
drawerBinding.drawerLonValue.text =
|
drawerBinding.drawerLonValue.text =
|
||||||
|
|||||||
@@ -82,9 +82,9 @@ class MapViewFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupComponents() {
|
private fun setupComponents() {
|
||||||
val delay = viewModel.delay
|
val refreshRate = viewModel.getRefreshRate()
|
||||||
gsp = viewModel.gsp.value ?: GroundStationPosition(0.0, 0.0, 0.0)
|
gsp = viewModel.getGSP().value ?: GroundStationPosition(0.0, 0.0, 0.0)
|
||||||
satPassList = viewModel.satPassList.value ?: emptyList()
|
satPassList = viewModel.getSatPassList().value ?: emptyList()
|
||||||
|
|
||||||
if (satPassList.isNotEmpty()) {
|
if (satPassList.isNotEmpty()) {
|
||||||
satPassList = satPassList.distinctBy { it.tle }
|
satPassList = satPassList.distinctBy { it.tle }
|
||||||
@@ -96,8 +96,8 @@ class MapViewFragment : Fragment() {
|
|||||||
binding.frameMap.addView(mapView)
|
binding.frameMap.addView(mapView)
|
||||||
service.scheduleAtFixedRate(
|
service.scheduleAtFixedRate(
|
||||||
{ mapView.invalidate() },
|
{ mapView.invalidate() },
|
||||||
delay,
|
refreshRate,
|
||||||
delay,
|
refreshRate,
|
||||||
TimeUnit.MILLISECONDS
|
TimeUnit.MILLISECONDS
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class PassListFragment : Fragment() {
|
|||||||
binding.refLayoutPassList.setColorSchemeResources(R.color.backgroundDark)
|
binding.refLayoutPassList.setColorSchemeResources(R.color.backgroundDark)
|
||||||
binding.refLayoutPassList.setOnRefreshListener { calculatePasses() }
|
binding.refLayoutPassList.setOnRefreshListener { calculatePasses() }
|
||||||
btnPassPrefs.setOnClickListener {
|
btnPassPrefs.setOnClickListener {
|
||||||
showSatPassPrefsDialog(viewModel.hoursAhead, viewModel.minEl)
|
showSatPassPrefsDialog(viewModel.getHoursAhead(), viewModel.getMinElevation())
|
||||||
}
|
}
|
||||||
binding.fabSatSelect.setOnClickListener {
|
binding.fabSatSelect.setOnClickListener {
|
||||||
showSelectSatDialog(viewModel.tleMainList, viewModel.tleSelection)
|
showSelectSatDialog(viewModel.tleMainList, viewModel.tleSelection)
|
||||||
@@ -105,7 +105,7 @@ class PassListFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupObservers() {
|
private fun setupObservers() {
|
||||||
viewModel.satPassList.observe(viewLifecycleOwner, Observer {
|
viewModel.getSatPassList().observe(viewLifecycleOwner, Observer {
|
||||||
satPassList = it
|
satPassList = it
|
||||||
satPassAdapter.setList(satPassList)
|
satPassAdapter.setList(satPassList)
|
||||||
if (satPassList.isNotEmpty()) {
|
if (satPassList.isNotEmpty()) {
|
||||||
|
|||||||
@@ -78,8 +78,8 @@ class PolarViewFragment : Fragment() {
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
viewModel.satPassList.value?.let {
|
viewModel.getSatPassList().value?.let {
|
||||||
val refreshRate = viewModel.delay
|
val refreshRate = viewModel.getRefreshRate()
|
||||||
satPass = it[args.satPassIndex]
|
satPass = it[args.satPassIndex]
|
||||||
mainActivity.supportActionBar?.title = satPass.tle.name
|
mainActivity.supportActionBar?.title = satPass.tle.name
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ class SatPassAdapter(val viewModel: MainViewModel) :
|
|||||||
binding.passLeoProgress.progress = satPass.progress
|
binding.passLeoProgress.progress = satPass.progress
|
||||||
|
|
||||||
itemView.setOnClickListener {
|
itemView.setOnClickListener {
|
||||||
viewModel.satPassList.value?.let {
|
viewModel.getSatPassList().value?.let {
|
||||||
val satPassIndex = it.indexOf(satPass)
|
val satPassIndex = it.indexOf(satPass)
|
||||||
val action = PassListFragmentDirections.actionPassToPolar(satPassIndex)
|
val action = PassListFragmentDirections.actionPassToPolar(satPassIndex)
|
||||||
itemView.findNavController().navigate(action)
|
itemView.findNavController().navigate(action)
|
||||||
@@ -148,7 +148,7 @@ class SatPassAdapter(val viewModel: MainViewModel) :
|
|||||||
String.format(context.getString(R.string.pat_elevation), satPass.pass.maxEl)
|
String.format(context.getString(R.string.pat_elevation), satPass.pass.maxEl)
|
||||||
|
|
||||||
itemView.setOnClickListener {
|
itemView.setOnClickListener {
|
||||||
viewModel.satPassList.value?.let {
|
viewModel.getSatPassList().value?.let {
|
||||||
val satPassIndex = it.indexOf(satPass)
|
val satPassIndex = it.indexOf(satPass)
|
||||||
val action = PassListFragmentDirections.actionPassToPolar(satPassIndex)
|
val action = PassListFragmentDirections.actionPassToPolar(satPassIndex)
|
||||||
itemView.findNavController().navigate(action)
|
itemView.findNavController().navigate(action)
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||||
|
* Copyright (C) 2019, 2020 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.rtbishop.look4sat.utility
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.location.LocationManager
|
||||||
|
import android.util.Log
|
||||||
|
import com.github.amsacode.predict4java.GroundStationPosition
|
||||||
|
import com.github.amsacode.predict4java.TLE
|
||||||
|
import com.rtbishop.look4sat.R
|
||||||
|
import java.io.FileNotFoundException
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.ObjectInputStream
|
||||||
|
import java.io.ObjectOutputStream
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class DataManager @Inject constructor(
|
||||||
|
private val locationManager: LocationManager,
|
||||||
|
private val context: Context
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val tag = "DataManager"
|
||||||
|
private val tleMainListFileName = "tleFile.txt"
|
||||||
|
private val tleSelectionFileName = "tleSelection"
|
||||||
|
|
||||||
|
fun getLastKnownLocation(): GroundStationPosition? {
|
||||||
|
val passiveProvider = LocationManager.PASSIVE_PROVIDER
|
||||||
|
var groundStationPosition: GroundStationPosition? = null
|
||||||
|
return try {
|
||||||
|
val location = locationManager.getLastKnownLocation(passiveProvider)
|
||||||
|
location?.let {
|
||||||
|
groundStationPosition =
|
||||||
|
GroundStationPosition(it.latitude, it.longitude, it.altitude)
|
||||||
|
}
|
||||||
|
groundStationPosition
|
||||||
|
} catch (e: SecurityException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveSelectionList(selectionList: MutableList<Int>) {
|
||||||
|
try {
|
||||||
|
val fileOutputStream =
|
||||||
|
context.openFileOutput(tleSelectionFileName, Context.MODE_PRIVATE)
|
||||||
|
ObjectOutputStream(fileOutputStream).apply {
|
||||||
|
writeObject(selectionList)
|
||||||
|
flush()
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
} catch (exception: IOException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveTleList(tleList: MutableList<TLE>) {
|
||||||
|
try {
|
||||||
|
val fileOutStream = context.openFileOutput(tleMainListFileName, Context.MODE_PRIVATE)
|
||||||
|
ObjectOutputStream(fileOutStream).apply {
|
||||||
|
writeObject(tleList)
|
||||||
|
flush()
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
} catch (exception: IOException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun loadTleList(): List<TLE> {
|
||||||
|
return try {
|
||||||
|
val tleStream = context.openFileInput(tleMainListFileName)
|
||||||
|
val tleList = ObjectInputStream(tleStream).readObject()
|
||||||
|
tleList as List<TLE>
|
||||||
|
} catch (exception: FileNotFoundException) {
|
||||||
|
Log.w(tag, context.getString(R.string.err_no_tle_file))
|
||||||
|
emptyList()
|
||||||
|
} catch (exception: IOException) {
|
||||||
|
Log.w(tag, exception.toString())
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun loadSelectionList(): MutableList<Int> {
|
||||||
|
return try {
|
||||||
|
val selectionStream = context.openFileInput(tleSelectionFileName)
|
||||||
|
val selectionList = ObjectInputStream(selectionStream).readObject()
|
||||||
|
selectionList as MutableList<Int>
|
||||||
|
} catch (exception: FileNotFoundException) {
|
||||||
|
Log.w(tag, context.getString(R.string.err_no_selection_file))
|
||||||
|
mutableListOf()
|
||||||
|
} catch (exception: IOException) {
|
||||||
|
Log.w(tag, exception.toString())
|
||||||
|
mutableListOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Look4Sat. Amateur radio and weather satellite tracker and passes predictor for Android.
|
||||||
|
* Copyright (C) 2019, 2020 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.rtbishop.look4sat.utility
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import com.github.amsacode.predict4java.GroundStationPosition
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class PrefsManager @Inject constructor(private val preferences: SharedPreferences) {
|
||||||
|
|
||||||
|
private val keyHoursAhead = "hoursAhead"
|
||||||
|
private val keyMinElevation = "minEl"
|
||||||
|
private val keyLatitude = "latitude"
|
||||||
|
private val keyLongitude = "longitude"
|
||||||
|
private val keyAltitude = "altitude"
|
||||||
|
private val keyRefreshRate = "rate"
|
||||||
|
|
||||||
|
fun getHoursAhead(): Int {
|
||||||
|
return preferences.getInt(keyHoursAhead, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMinElevation(): Double {
|
||||||
|
return preferences.getDouble(keyMinElevation, 16.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRefreshRate(): Long {
|
||||||
|
return preferences.getString(keyRefreshRate, "3000")!!.toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getGroundStationPosition(): GroundStationPosition {
|
||||||
|
val lat = preferences.getString(keyLatitude, "0.0")!!.toDouble()
|
||||||
|
val lon = preferences.getString(keyLongitude, "0.0")!!.toDouble()
|
||||||
|
val alt = preferences.getString(keyAltitude, "0.0")!!.toDouble()
|
||||||
|
return GroundStationPosition(lat, lon, alt)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setHoursAhead(hours: Int) {
|
||||||
|
preferences.edit {
|
||||||
|
putInt(keyHoursAhead, hours)
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMinElevation(minEl: Double) {
|
||||||
|
preferences.edit {
|
||||||
|
putDouble(keyMinElevation, minEl)
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setRefreshRate(rate: Long) {
|
||||||
|
preferences.edit {
|
||||||
|
putLong(keyRefreshRate, rate)
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setGroundStationPosition(gsp: GroundStationPosition) {
|
||||||
|
preferences.edit {
|
||||||
|
putString(keyLatitude, gsp.latitude.toString())
|
||||||
|
putString(keyLongitude, gsp.longitude.toString())
|
||||||
|
putString(keyAltitude, gsp.heightAMSL.toString())
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SharedPreferences.Editor.putDouble(key: String, double: Double) {
|
||||||
|
putLong(key, double.toRawBits())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SharedPreferences.getDouble(key: String, default: Double): Double {
|
||||||
|
return Double.fromBits(getLong(key, default.toRawBits()))
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -26,7 +26,7 @@ buildscript {
|
|||||||
|
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.6.0'
|
classpath 'com.android.tools.build:gradle:3.6.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61"
|
||||||
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.2.1"
|
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.2.1"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user