kopia lustrzana https://github.com/rt-bishop/Look4Sat
Further refactoring, showing passes now after the radarFragment onBack pressed. Trying to decide on the way it all should work.
rodzic
d7a094a1e2
commit
89299d1c3b
|
|
@ -4,10 +4,8 @@ import android.app.Application
|
|||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.location.Location
|
||||
import android.util.Log
|
||||
import androidx.core.content.edit
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.preference.PreferenceManager
|
||||
|
|
@ -29,95 +27,86 @@ import javax.inject.Inject
|
|||
|
||||
class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
private val keyLat = "LATITUDE"
|
||||
private val keyLon = "LONGITUDE"
|
||||
private val keyHeight = "HEIGHT"
|
||||
private val tleFile = "tles.txt"
|
||||
private val tag = "myTag"
|
||||
private val keyLat = "latitude"
|
||||
private val keyLon = "longitude"
|
||||
private val keyHeight = "height"
|
||||
private val keyHours = "hoursAhead"
|
||||
private val keyMaxEl = "maxElevation"
|
||||
private val tleFileName = "tleFile.txt"
|
||||
private val preferences = PreferenceManager.getDefaultSharedPreferences(application)
|
||||
private val locationClient = LocationServices.getFusedLocationProviderClient(application)
|
||||
|
||||
val debugMessage = MutableLiveData("")
|
||||
|
||||
@Inject
|
||||
lateinit var repository: Repository
|
||||
|
||||
private val preferences = PreferenceManager.getDefaultSharedPreferences(application)
|
||||
private val fusedLocationClient = LocationServices.getFusedLocationProviderClient(application)
|
||||
|
||||
init {
|
||||
(application as LookingSatApp).appComponent.inject(this)
|
||||
}
|
||||
|
||||
private val _debugMessage = MutableLiveData("")
|
||||
val debugMessage: LiveData<String> = _debugMessage
|
||||
|
||||
private val _tleMainList = MutableLiveData<List<TLE>>(loadTwoLineElementFile())
|
||||
val tleMainList: LiveData<List<TLE>> = _tleMainList
|
||||
|
||||
private val _tleSelectedMap = MutableLiveData<MutableMap<TLE, Boolean>>(mutableMapOf())
|
||||
val tleSelectedMap: LiveData<MutableMap<TLE, Boolean>> = _tleSelectedMap
|
||||
|
||||
private val _satPassPrefs = MutableLiveData<SatPassPrefs>(
|
||||
SatPassPrefs(
|
||||
preferences.getInt("hoursAhead", 8),
|
||||
preferences.getDouble("maxEl", 20.0)
|
||||
)
|
||||
)
|
||||
val satPassPrefs: LiveData<SatPassPrefs> = _satPassPrefs
|
||||
|
||||
private val _gsp = MutableLiveData<GroundStationPosition>(
|
||||
val gsp = MutableLiveData<GroundStationPosition>(
|
||||
GroundStationPosition(
|
||||
preferences.getDouble(keyLat, 0.0),
|
||||
preferences.getDouble(keyLon, 0.0),
|
||||
preferences.getDouble(keyHeight, 0.0)
|
||||
)
|
||||
)
|
||||
val gsp: LiveData<GroundStationPosition> = _gsp
|
||||
|
||||
var tleMainList = loadTwoLineElementFile()
|
||||
var tleSelectedMap = mutableMapOf<TLE, Boolean>()
|
||||
var passPrefs = SatPassPrefs(
|
||||
preferences.getInt(keyHours, 8),
|
||||
preferences.getDouble(keyMaxEl, 16.0)
|
||||
)
|
||||
|
||||
private fun loadTwoLineElementFile(): List<TLE> {
|
||||
return try {
|
||||
TLE.importSat(getApplication<Application>().openFileInput(tleFile))
|
||||
TLE.importSat(getApplication<Application>().openFileInput(tleFileName))
|
||||
.sortedWith(compareBy { it.name })
|
||||
} catch (exception: FileNotFoundException) {
|
||||
_debugMessage.postValue("TLE file wasn't found")
|
||||
debugMessage.postValue("TLE file wasn't found")
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getPasses(satMap: Map<TLE, Boolean>, hours: Int, maxEl: Double): List<SatPass> {
|
||||
suspend fun getPasses(): List<SatPass> {
|
||||
val satPassList = mutableListOf<SatPass>()
|
||||
withContext(Dispatchers.Default) {
|
||||
satMap.forEach { (tle, value) ->
|
||||
tleSelectedMap.forEach { (tle, value) ->
|
||||
if (value) {
|
||||
try {
|
||||
val passPredictor = PassPredictor(tle, gsp.value)
|
||||
val passes = passPredictor.getPasses(Date(), hours, false)
|
||||
passes.forEach { satPassList.add(SatPass(tle, passPredictor, it)) }
|
||||
val predictor = PassPredictor(tle, gsp.value)
|
||||
val passes = predictor.getPasses(Date(), passPrefs.hoursAhead, false)
|
||||
passes.forEach { satPassList.add(SatPass(tle, predictor, it)) }
|
||||
} catch (exception: IllegalArgumentException) {
|
||||
Log.d(tag, "There was a problem with TLE")
|
||||
debugMessage.postValue("There was a problem with TLE")
|
||||
} catch (exception: SatNotFoundException) {
|
||||
Log.d(tag, "Certain satellites shall not pass")
|
||||
debugMessage.postValue("Certain satellites shall not pass")
|
||||
}
|
||||
}
|
||||
}
|
||||
satPassList.retainAll { it.pass.maxEl >= maxEl }
|
||||
satPassList.retainAll { it.pass.maxEl >= passPrefs.maxEl }
|
||||
satPassList.sortBy { it.pass.startTime }
|
||||
}
|
||||
return satPassList
|
||||
}
|
||||
|
||||
fun updateSelectedSatMap(mutableMap: MutableMap<TLE, Boolean>) {
|
||||
_tleSelectedMap.postValue(mutableMap)
|
||||
tleSelectedMap = mutableMap
|
||||
}
|
||||
|
||||
fun updatePassPrefs(hoursAhead: Int, maxEl: Double) {
|
||||
_satPassPrefs.postValue(SatPassPrefs(hoursAhead, maxEl))
|
||||
passPrefs = SatPassPrefs(hoursAhead, maxEl)
|
||||
preferences.edit {
|
||||
putInt("hoursAhead", hoursAhead)
|
||||
putDouble("maxEl", maxEl)
|
||||
putInt(keyHours, hoursAhead)
|
||||
putDouble(keyMaxEl, maxEl)
|
||||
apply()
|
||||
}
|
||||
}
|
||||
|
||||
fun updateLocation() {
|
||||
fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? ->
|
||||
locationClient.lastLocation.addOnSuccessListener { location: Location? ->
|
||||
val lat = location?.latitude ?: 0.0
|
||||
val lon = location?.longitude ?: 0.0
|
||||
val height = location?.altitude ?: 0.0
|
||||
|
|
@ -128,8 +117,8 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||
putDouble(keyHeight, height)
|
||||
apply()
|
||||
}
|
||||
_gsp.postValue(GroundStationPosition(lat, lon, height))
|
||||
_debugMessage.postValue("Location was updated")
|
||||
gsp.postValue(GroundStationPosition(lat, lon, height))
|
||||
debugMessage.postValue("Location was updated")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -137,13 +126,14 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val stream = repository.fetchTleStream()
|
||||
getApplication<Application>().openFileOutput(tleFile, Context.MODE_PRIVATE).use {
|
||||
it.write(stream.readBytes())
|
||||
}
|
||||
_tleMainList.postValue(loadTwoLineElementFile())
|
||||
_debugMessage.postValue("TLE file was updated")
|
||||
getApplication<Application>().openFileOutput(tleFileName, Context.MODE_PRIVATE)
|
||||
.use {
|
||||
it.write(stream.readBytes())
|
||||
}
|
||||
tleMainList = loadTwoLineElementFile()
|
||||
debugMessage.postValue("TLE file was updated")
|
||||
} catch (exception: IOException) {
|
||||
_debugMessage.postValue("Couldn't update TLE file")
|
||||
debugMessage.postValue("Couldn't update TLE file")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -152,9 +142,9 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
repository.updateTransmittersDatabase()
|
||||
_debugMessage.postValue("Transmitters were updated")
|
||||
debugMessage.postValue("Transmitters were updated")
|
||||
} catch (exception: IOException) {
|
||||
_debugMessage.postValue("Couldn't update transmitters")
|
||||
debugMessage.postValue("Couldn't update transmitters")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ import com.github.amsacode.predict4java.TLE
|
|||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.rtbishop.lookingsat.MainViewModel
|
||||
import com.rtbishop.lookingsat.R
|
||||
import com.rtbishop.lookingsat.repo.SatPass
|
||||
import com.rtbishop.lookingsat.repo.SatPassPrefs
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
|
@ -34,12 +32,14 @@ class SkyFragment : Fragment() {
|
|||
private lateinit var btnPassPrefs: ImageButton
|
||||
private lateinit var progressBar: ProgressBar
|
||||
private lateinit var fab: FloatingActionButton
|
||||
private lateinit var tleMainList: List<TLE>
|
||||
private var selectedSatMap: MutableMap<TLE, Boolean> = mutableMapOf()
|
||||
private lateinit var satPassPrefs: SatPassPrefs
|
||||
private lateinit var aosTimer: CountDownTimer
|
||||
private var isTimerSet: Boolean = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View? {
|
||||
|
|
@ -49,12 +49,9 @@ class SkyFragment : Fragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupViews(view)
|
||||
setupObservers()
|
||||
resetTimer()
|
||||
}
|
||||
|
||||
private fun setupViews(view: View) {
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
timeToAos = (activity as MainActivity).findViewById(R.id.toolbar_time_to_aos)
|
||||
btnPassPrefs = (activity as MainActivity).findViewById(R.id.toolbar_btn_refresh)
|
||||
progressBar = view.findViewById(R.id.sky_progressbar)
|
||||
|
|
@ -66,29 +63,7 @@ class SkyFragment : Fragment() {
|
|||
btnPassPrefs.setOnClickListener { showSatPassPrefsDialog() }
|
||||
fab.setOnClickListener { showSelectSatDialog() }
|
||||
|
||||
satPassPrefs = viewModel.satPassPrefs.value ?: SatPassPrefs(8, 20.0)
|
||||
}
|
||||
|
||||
private fun setupObservers() {
|
||||
viewModel.tleMainList.observe(this, Observer {
|
||||
tleMainList = it
|
||||
selectedSatMap.clear()
|
||||
viewModel.updateSelectedSatMap(selectedSatMap)
|
||||
})
|
||||
|
||||
viewModel.tleSelectedMap.observe(this, Observer {
|
||||
selectedSatMap = it
|
||||
calculatePasses()
|
||||
})
|
||||
|
||||
viewModel.satPassPrefs.observe(this, Observer {
|
||||
satPassPrefs = it
|
||||
calculatePasses()
|
||||
})
|
||||
|
||||
viewModel.gsp.observe(this, Observer {
|
||||
calculatePasses()
|
||||
})
|
||||
viewModel.gsp.observe(this, Observer { calculatePasses() })
|
||||
}
|
||||
|
||||
private fun showSatPassPrefsDialog() {
|
||||
|
|
@ -96,8 +71,8 @@ class SkyFragment : Fragment() {
|
|||
val satPassPrefView = View.inflate(context, R.layout.sat_pass_pref, null)
|
||||
val etHours = satPassPrefView.findViewById<EditText>(R.id.pass_pref_et_hours)
|
||||
val etMaxEl = satPassPrefView.findViewById<EditText>(R.id.pass_pref_et_maxEl)
|
||||
etHours.setText(viewModel.satPassPrefs.value?.hoursAhead.toString())
|
||||
etMaxEl.setText(viewModel.satPassPrefs.value?.maxEl.toString())
|
||||
etHours.setText(viewModel.passPrefs.hoursAhead.toString())
|
||||
etMaxEl.setText(viewModel.passPrefs.maxEl.toString())
|
||||
|
||||
val builder = AlertDialog.Builder(context)
|
||||
builder.setTitle(getString(R.string.title_pass_pref))
|
||||
|
|
@ -105,6 +80,7 @@ class SkyFragment : Fragment() {
|
|||
val hoursAhead = etHours.text.toString().toInt()
|
||||
val maxEl = etMaxEl.text.toString().toDouble()
|
||||
viewModel.updatePassPrefs(hoursAhead, maxEl)
|
||||
calculatePasses()
|
||||
}
|
||||
.setNegativeButton(getString(R.string.btn_cancel)) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
|
|
@ -115,10 +91,11 @@ class SkyFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun showSelectSatDialog() {
|
||||
val tleMainList: List<TLE> = viewModel.tleMainList
|
||||
val tleNameArray = arrayOfNulls<String>(tleMainList.size)
|
||||
val tleCheckedArray = BooleanArray(tleMainList.size)
|
||||
val builder = AlertDialog.Builder(activity as MainActivity)
|
||||
val selectionMap = mutableMapOf<TLE, Boolean>()
|
||||
val selectedSatMap = viewModel.tleSelectedMap
|
||||
val currentSelectionMap = mutableMapOf<TLE, Boolean>()
|
||||
|
||||
if (selectedSatMap.isEmpty()) {
|
||||
tleMainList.withIndex().forEach { (position, tle) ->
|
||||
|
|
@ -132,14 +109,16 @@ class SkyFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
val builder = AlertDialog.Builder(activity as MainActivity)
|
||||
builder.setTitle(getString(R.string.title_select_sat))
|
||||
.setMultiChoiceItems(tleNameArray, tleCheckedArray) { _, which, isChecked ->
|
||||
selectionMap[tleMainList[which]] = isChecked
|
||||
currentSelectionMap[tleMainList[which]] = isChecked
|
||||
}
|
||||
.setPositiveButton(getString(R.string.btn_ok)) { _, _ ->
|
||||
for ((tle, value) in selectionMap) {
|
||||
for ((tle, value) in currentSelectionMap) {
|
||||
selectedSatMap[tle] = value
|
||||
viewModel.updateSelectedSatMap(selectedSatMap)
|
||||
calculatePasses()
|
||||
}
|
||||
}
|
||||
.setNegativeButton(getString(R.string.btn_cancel)) { dialog, _ ->
|
||||
|
|
@ -148,20 +127,18 @@ class SkyFragment : Fragment() {
|
|||
.setNeutralButton(getString(R.string.btn_clear)) { _, _ ->
|
||||
selectedSatMap.clear()
|
||||
viewModel.updateSelectedSatMap(selectedSatMap)
|
||||
calculatePasses()
|
||||
}
|
||||
.create()
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun calculatePasses() {
|
||||
val hoursAhead = satPassPrefs.hoursAhead
|
||||
val maxEl = satPassPrefs.maxEl
|
||||
var satPassList: List<SatPass>
|
||||
lifecycleScope.launch(Dispatchers.Main) {
|
||||
recViewFuture.visibility = View.INVISIBLE
|
||||
progressBar.visibility = View.VISIBLE
|
||||
progressBar.isIndeterminate = true
|
||||
satPassList = viewModel.getPasses(selectedSatMap, hoursAhead, maxEl)
|
||||
val satPassList = viewModel.getPasses()
|
||||
recAdapterFuture = SatPassAdapter(satPassList)
|
||||
recViewFuture.adapter = recAdapterFuture
|
||||
progressBar.isIndeterminate = false
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue