Further refactoring, showing passes now after the radarFragment onBack pressed. Trying to decide on the way it all should work.

pull/30/head
Arty Bishop 2019-11-29 11:01:51 +00:00
rodzic d7a094a1e2
commit 89299d1c3b
2 zmienionych plików z 62 dodań i 95 usunięć

Wyświetl plik

@ -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")
}
}
}

Wyświetl plik

@ -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