Further refactoring. Restored the SatPass preferences dialog. Code cleanup.
This commit is contained in:
1 parent
bb8a060ef3
commit
807b5a0d67
12 files changed
+252
-161
No files matched your search
@@ -49,19 +49,33 @@ import javax.inject.Inject
|
||||
class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
private val defValueLoc = application.getString(R.string.def_gsp_loc)
|
||||
private val defValueHours = application.getString(R.string.def_hours_ahead)
|
||||
private val defValueMinEl = application.getString(R.string.def_min_el)
|
||||
private val defValueHours = application.getString(R.string.def_hours_ahead).toInt()
|
||||
private val defValueMinEl = application.getString(R.string.def_min_el).toDouble()
|
||||
private val defValueUpdateFreq = application.getString(R.string.def_update_freq)
|
||||
private val keyHours = application.getString(R.string.key_hours_ahead)
|
||||
private val keyMinEl = application.getString(R.string.key_min_el)
|
||||
private val keyLat = application.getString(R.string.key_lat)
|
||||
private val keyLon = application.getString(R.string.key_lon)
|
||||
private val keyAlt = application.getString(R.string.key_alt)
|
||||
private val keyHours = application.getString(R.string.key_hours_ahead)
|
||||
private val keyMinEl = application.getString(R.string.key_min_el)
|
||||
private val keyUpdateFreq = application.getString(R.string.key_update_freq)
|
||||
private val keyDelay = application.getString(R.string.key_delay)
|
||||
private val tleMainListFileName = application.getString(R.string.tle_main_list_file_name)
|
||||
private val tleSelectionFileName = application.getString(R.string.tle_selection_file_name)
|
||||
private val app = application
|
||||
|
||||
private val _debugMessage = MutableLiveData<String>()
|
||||
val debugMessage: LiveData<String> = _debugMessage
|
||||
|
||||
private val _satPassList = MutableLiveData<List<SatPass>>()
|
||||
val passSatList: LiveData<List<SatPass>> = _satPassList
|
||||
|
||||
private val _gsp = MutableLiveData<GroundStationPosition>()
|
||||
val gsp: LiveData<GroundStationPosition> = _gsp
|
||||
|
||||
private val urlList = listOf(
|
||||
"https://celestrak.com/NORAD/elements/amateur.txt",
|
||||
"https://celestrak.com/NORAD/elements/weather.txt"
|
||||
)
|
||||
|
||||
@Inject
|
||||
lateinit var locationClient: FusedLocationProviderClient
|
||||
@Inject
|
||||
@@ -69,34 +83,24 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
@Inject
|
||||
lateinit var repository: Repository
|
||||
|
||||
lateinit var tleMainList: List<TLE>
|
||||
lateinit var tleSelection: MutableList<Int>
|
||||
|
||||
init {
|
||||
(app as Look4SatApp).appComponent.inject(this)
|
||||
loadDataFromDisk()
|
||||
}
|
||||
|
||||
private val urlList = listOf(
|
||||
"https://celestrak.com/NORAD/elements/amateur.txt",
|
||||
"https://celestrak.com/NORAD/elements/weather.txt"
|
||||
)
|
||||
val delay: Long
|
||||
get() = preferences.getString(keyDelay, defValueUpdateFreq)!!.toLong()
|
||||
|
||||
private val _debugMessage = MutableLiveData<String>()
|
||||
val debugMessage: LiveData<String> = _debugMessage
|
||||
val hoursAhead: Int
|
||||
get() = preferences.getInt(keyHours, defValueHours)
|
||||
|
||||
private val _gsp = MutableLiveData<GroundStationPosition>(
|
||||
GroundStationPosition(
|
||||
preferences.getString(keyLat, defValueLoc)!!.toDouble(),
|
||||
preferences.getString(keyLon, defValueLoc)!!.toDouble(),
|
||||
preferences.getString(keyAlt, defValueLoc)!!.toDouble()
|
||||
)
|
||||
)
|
||||
val gsp: LiveData<GroundStationPosition> = _gsp
|
||||
val minEl: Double
|
||||
get() = preferences.getDouble(keyMinEl, defValueMinEl)
|
||||
|
||||
var satPassList = emptyList<SatPass>()
|
||||
var tleMainList = loadTwoLineElementFile()
|
||||
var selectionList = loadSelectionList()
|
||||
val updateFreq: Long
|
||||
get() = preferences.getString(keyUpdateFreq, defValueUpdateFreq)!!.toLong()
|
||||
|
||||
fun updateGsp() {
|
||||
fun setGroundStationPosition() {
|
||||
val lat = preferences.getString(keyLat, defValueLoc)!!.toDouble()
|
||||
val lon = preferences.getString(keyLon, defValueLoc)!!.toDouble()
|
||||
val alt = preferences.getString(keyAlt, defValueLoc)!!.toDouble()
|
||||
@@ -120,6 +124,14 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
}
|
||||
}
|
||||
|
||||
fun setPassPrefs(hoursAhead: Int, minEl: Double) {
|
||||
preferences.edit {
|
||||
putInt(keyHours, hoursAhead)
|
||||
putDouble(keyMinEl, minEl)
|
||||
apply()
|
||||
}
|
||||
}
|
||||
|
||||
fun updateAndSaveTleFile() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
@@ -132,7 +144,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
close()
|
||||
}
|
||||
tleMainList = tleList
|
||||
selectionList = mutableListOf()
|
||||
tleSelection = mutableListOf()
|
||||
_debugMessage.postValue("TLE file was updated")
|
||||
} catch (exception: IOException) {
|
||||
_debugMessage.postValue("Couldn't update TLE file")
|
||||
@@ -152,7 +164,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
}
|
||||
|
||||
fun updateAndSaveSelectionList(list: MutableList<Int>) {
|
||||
selectionList = list
|
||||
tleSelection = list
|
||||
try {
|
||||
val fileOutputStream = app.openFileOutput(tleSelectionFileName, Context.MODE_PRIVATE)
|
||||
ObjectOutputStream(fileOutputStream).apply {
|
||||
@@ -166,11 +178,9 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
}
|
||||
|
||||
suspend fun getPasses() {
|
||||
val hoursAhead = preferences.getString(keyHours, defValueHours)!!.toInt()
|
||||
val minEl = preferences.getString(keyMinEl, defValueMinEl)!!.toDouble()
|
||||
val passList = mutableListOf<SatPass>()
|
||||
withContext(Dispatchers.Default) {
|
||||
selectionList.forEach { indexOfSelection ->
|
||||
tleSelection.forEach { indexOfSelection ->
|
||||
val tle = tleMainList[indexOfSelection]
|
||||
try {
|
||||
val predictor = PassPredictor(tle, gsp.value)
|
||||
@@ -185,7 +195,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
passList.retainAll { it.pass.maxEl >= minEl }
|
||||
passList.sortBy { it.pass.startTime }
|
||||
}
|
||||
satPassList = passList
|
||||
_satPassList.postValue(passList)
|
||||
}
|
||||
|
||||
suspend fun getTransmittersForSat(id: Int): List<Transmitter> {
|
||||
@@ -193,30 +203,37 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun loadTwoLineElementFile(): List<TLE> {
|
||||
try {
|
||||
val fileInputStream = app.openFileInput(tleMainListFileName)
|
||||
val tleList = ObjectInputStream(fileInputStream).readObject()
|
||||
return tleList as List<TLE>
|
||||
private fun loadDataFromDisk() {
|
||||
tleMainList = try {
|
||||
val tleStream = app.openFileInput(tleMainListFileName)
|
||||
val tleList = ObjectInputStream(tleStream).readObject()
|
||||
tleList as List<TLE>
|
||||
} catch (exception: FileNotFoundException) {
|
||||
_debugMessage.postValue("TLE file wasn't found")
|
||||
emptyList()
|
||||
} catch (exception: IOException) {
|
||||
_debugMessage.postValue(exception.toString())
|
||||
emptyList()
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun loadSelectionList(): MutableList<Int> {
|
||||
try {
|
||||
val fileInputStream = app.openFileInput(tleSelectionFileName)
|
||||
val selectionList = ObjectInputStream(fileInputStream).readObject()
|
||||
return selectionList as MutableList<Int>
|
||||
tleSelection = try {
|
||||
val selectionStream = app.openFileInput(tleSelectionFileName)
|
||||
val selectionList = ObjectInputStream(selectionStream).readObject()
|
||||
selectionList as MutableList<Int>
|
||||
} catch (exception: FileNotFoundException) {
|
||||
_debugMessage.postValue("Selection file wasn't found")
|
||||
mutableListOf()
|
||||
} catch (exception: IOException) {
|
||||
_debugMessage.postValue(exception.toString())
|
||||
mutableListOf()
|
||||
}
|
||||
return 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()))
|
||||
}
|
||||
@@ -126,8 +126,8 @@ class MainActivity : AppCompatActivity() {
|
||||
})
|
||||
|
||||
viewModel.gsp.observe(this, Observer { gsp ->
|
||||
drawerLat.text = String.format(getString(R.string.pattern_lat), gsp.latitude)
|
||||
drawerLon.text = String.format(getString(R.string.pattern_lon), gsp.longitude)
|
||||
drawerLat.text = String.format(getString(R.string.pattern_location), gsp.latitude)
|
||||
drawerLon.text = String.format(getString(R.string.pattern_location), gsp.longitude)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ class RadarFragment : Fragment() {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val delay = viewModel.updateFreq
|
||||
val delay = viewModel.delay
|
||||
satPass = arguments?.get("satPass") as SatPass
|
||||
mainActivity.supportActionBar?.title = satPass.tle.name
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class SettingsFragment : PreferenceFragmentCompat(),
|
||||
if (key == context!!.getText(R.string.key_lat) ||
|
||||
key == context!!.getText(R.string.key_lon) ||
|
||||
key == context!!.getText(R.string.key_alt)
|
||||
) viewModel.updateGsp()
|
||||
) viewModel.setGroundStationPosition()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
||||
@@ -24,11 +24,13 @@ import android.os.CountDownTimer
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageButton
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@@ -46,22 +48,23 @@ import java.util.concurrent.TimeUnit
|
||||
class SkyFragment : Fragment() {
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var recViewFuture: RecyclerView
|
||||
private lateinit var recAdapterFuture: SatPassAdapter
|
||||
private lateinit var recyclerPasses: RecyclerView
|
||||
private lateinit var recyclerAdapter: SatPassAdapter
|
||||
private lateinit var timeToAos: TextView
|
||||
private lateinit var btnRefresh: ImageButton
|
||||
private lateinit var btnPassPrefs: ImageButton
|
||||
private lateinit var fab: FloatingActionButton
|
||||
private lateinit var aosTimer: CountDownTimer
|
||||
private lateinit var swipeLayout: SwipeRefreshLayout
|
||||
private lateinit var satPassList: List<SatPass>
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var satPassList: List<SatPass>
|
||||
private var isTimerSet: Boolean = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
mainActivity = activity as MainActivity
|
||||
viewModel = ViewModelProvider(mainActivity).get(MainViewModel::class.java)
|
||||
recAdapterFuture = SatPassAdapter()
|
||||
recyclerAdapter = SatPassAdapter()
|
||||
satPassList = emptyList()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
@@ -72,80 +75,114 @@ class SkyFragment : Fragment() {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupViews(view)
|
||||
findViews(view)
|
||||
setupComponents()
|
||||
setupObservers()
|
||||
}
|
||||
|
||||
private fun setupViews(view: View) {
|
||||
private fun findViews(view: View) {
|
||||
timeToAos = (mainActivity).findViewById(R.id.toolbar_time_to_aos)
|
||||
btnRefresh = (mainActivity).findViewById(R.id.toolbar_btn_refresh)
|
||||
btnPassPrefs = (mainActivity).findViewById(R.id.toolbar_btn_refresh)
|
||||
swipeLayout = view.findViewById(R.id.swipeRefreshLayout)
|
||||
recViewFuture = view.findViewById(R.id.sky_recycler_future)
|
||||
recyclerPasses = view.findViewById(R.id.sky_recycler_future)
|
||||
fab = view.findViewById(R.id.sky_fab)
|
||||
}
|
||||
|
||||
satPassList = viewModel.satPassList
|
||||
recViewFuture.apply {
|
||||
private fun setupComponents() {
|
||||
recyclerPasses.apply {
|
||||
layoutManager = LinearLayoutManager(mainActivity)
|
||||
adapter = recAdapterFuture
|
||||
}
|
||||
recAdapterFuture.setList(satPassList)
|
||||
recAdapterFuture.notifyDataSetChanged()
|
||||
if (satPassList.isEmpty()) {
|
||||
resetTimer()
|
||||
adapter = recyclerAdapter
|
||||
}
|
||||
recyclerAdapter.setList(satPassList)
|
||||
recyclerAdapter.notifyDataSetChanged()
|
||||
if (satPassList.isEmpty()) resetTimer()
|
||||
|
||||
swipeLayout.setProgressBackgroundColorSchemeResource(R.color.themeAccent)
|
||||
swipeLayout.setColorSchemeResources(R.color.darkOnLight)
|
||||
swipeLayout.setOnRefreshListener { calculatePasses() }
|
||||
btnRefresh.setOnClickListener { calculatePasses() }
|
||||
btnPassPrefs.setOnClickListener { showSatPassPrefsDialog() }
|
||||
fab.setOnClickListener {
|
||||
showSelectSatDialog(viewModel.tleMainList, viewModel.selectionList)
|
||||
showSelectSatDialog(viewModel.tleMainList, viewModel.tleSelection)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSelectSatDialog(tleMainList: List<TLE>, selectionList: MutableList<Int>) {
|
||||
val tleNameArray = arrayOfNulls<String>(tleMainList.size).apply {
|
||||
tleMainList.withIndex().forEach { (position, tle) -> this[position] = tle.name }
|
||||
}
|
||||
val tleCheckedArray = BooleanArray(tleMainList.size).apply {
|
||||
selectionList.forEach { this[it] = true }
|
||||
}
|
||||
val builder = AlertDialog.Builder(mainActivity)
|
||||
builder.setTitle(getString(R.string.dialog_select_sat))
|
||||
.setMultiChoiceItems(tleNameArray, tleCheckedArray) { _, which, isChecked ->
|
||||
if (isChecked) selectionList.add(which)
|
||||
else if (selectionList.contains(which)) selectionList.remove(which)
|
||||
}
|
||||
.setPositiveButton(getString(R.string.btn_ok)) { _, _ ->
|
||||
viewModel.updateAndSaveSelectionList(selectionList)
|
||||
calculatePasses()
|
||||
}
|
||||
.setNegativeButton(getString(R.string.btn_cancel)) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
.setNeutralButton(getString(R.string.btn_clear)) { _, _ ->
|
||||
selectionList.clear()
|
||||
viewModel.updateAndSaveSelectionList(selectionList)
|
||||
calculatePasses()
|
||||
}
|
||||
.create()
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun calculatePasses() {
|
||||
lifecycleScope.launch(Dispatchers.Main) {
|
||||
viewModel.getPasses()
|
||||
satPassList = viewModel.satPassList
|
||||
recAdapterFuture.setList(satPassList)
|
||||
recAdapterFuture.notifyDataSetChanged()
|
||||
private fun setupObservers() {
|
||||
viewModel.passSatList.observe(viewLifecycleOwner, Observer {
|
||||
satPassList = it
|
||||
recyclerAdapter.setList(satPassList)
|
||||
recyclerAdapter.notifyDataSetChanged()
|
||||
if (satPassList.isNotEmpty()) setTimer(satPassList.first().pass.startTime.time)
|
||||
else {
|
||||
resetTimer()
|
||||
timeToAos.text = String.format(getString(R.string.pattern_aos), 0, 0, 0)
|
||||
}
|
||||
swipeLayout.isRefreshing = false
|
||||
})
|
||||
}
|
||||
|
||||
private fun showSatPassPrefsDialog() {
|
||||
val satPassPrefView = View.inflate(mainActivity, R.layout.sat_pass_pref, null)
|
||||
val etHoursAhead = satPassPrefView.findViewById<EditText>(R.id.pref_hours_ahead_et)
|
||||
val etMinEl = satPassPrefView.findViewById<EditText>(R.id.pref_min_el_et)
|
||||
etHoursAhead.setText(viewModel.hoursAhead.toString())
|
||||
etMinEl.setText(viewModel.minEl.toString())
|
||||
|
||||
val builder = AlertDialog.Builder(mainActivity)
|
||||
builder.setTitle(getString(R.string.dialog_pass_prefs))
|
||||
.setPositiveButton(getString(R.string.btn_ok)) { _, _ ->
|
||||
val hoursAhead = etHoursAhead.text.toString().toInt()
|
||||
val minEl = etMinEl.text.toString().toDouble()
|
||||
viewModel.setPassPrefs(hoursAhead, minEl)
|
||||
calculatePasses()
|
||||
}
|
||||
.setNegativeButton(getString(R.string.btn_cancel)) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
.setView(satPassPrefView)
|
||||
.create()
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun showSelectSatDialog(tleMainList: List<TLE>, selectionList: MutableList<Int>) {
|
||||
if (tleMainList.isEmpty()) {
|
||||
Toast.makeText(mainActivity, "Please, update your TLE", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
val tleNameArray = arrayOfNulls<String>(tleMainList.size).apply {
|
||||
tleMainList.withIndex().forEach { (position, tle) -> this[position] = tle.name }
|
||||
}
|
||||
val tleCheckedArray = BooleanArray(tleMainList.size).apply {
|
||||
selectionList.forEach { this[it] = true }
|
||||
}
|
||||
val builder = AlertDialog.Builder(mainActivity)
|
||||
builder.setTitle(getString(R.string.dialog_select_sat))
|
||||
.setMultiChoiceItems(tleNameArray, tleCheckedArray) { _, which, isChecked ->
|
||||
if (isChecked) selectionList.add(which)
|
||||
else if (selectionList.contains(which)) selectionList.remove(which)
|
||||
}
|
||||
.setPositiveButton(getString(R.string.btn_ok)) { _, _ ->
|
||||
viewModel.updateAndSaveSelectionList(selectionList)
|
||||
calculatePasses()
|
||||
}
|
||||
.setNegativeButton(getString(R.string.btn_cancel)) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
.setNeutralButton(getString(R.string.btn_clear)) { _, _ ->
|
||||
selectionList.clear()
|
||||
viewModel.updateAndSaveSelectionList(selectionList)
|
||||
calculatePasses()
|
||||
}
|
||||
.create()
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculatePasses() {
|
||||
swipeLayout.isRefreshing = true
|
||||
lifecycleScope.launch(Dispatchers.Main) { viewModel.getPasses() }
|
||||
}
|
||||
|
||||
private fun setTimer(passTime: Long) {
|
||||
if (isTimerSet) resetTimer()
|
||||
resetTimer()
|
||||
val totalMillis = passTime.minus(System.currentTimeMillis())
|
||||
aosTimer = object : CountDownTimer(totalMillis, 1000) {
|
||||
override fun onFinish() {
|
||||
@@ -155,7 +192,7 @@ class SkyFragment : Fragment() {
|
||||
|
||||
override fun onTick(millisUntilFinished: Long) {
|
||||
timeToAos.text = String.format(
|
||||
getString(R.string.pattern_aos),
|
||||
mainActivity.getString(R.string.pattern_aos),
|
||||
TimeUnit.MILLISECONDS.toHours(millisUntilFinished) % 60,
|
||||
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) % 60,
|
||||
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) % 60
|
||||
|
||||
@@ -30,10 +30,7 @@ import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.github.amsacode.predict4java.PassPredictor
|
||||
import com.github.amsacode.predict4java.Position
|
||||
import com.github.amsacode.predict4java.SatPos
|
||||
import com.github.amsacode.predict4java.TLE
|
||||
import com.github.amsacode.predict4java.*
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.rtbishop.look4sat.MainViewModel
|
||||
import com.rtbishop.look4sat.R
|
||||
@@ -45,7 +42,6 @@ import kotlin.math.abs
|
||||
class WorldMapFragment : Fragment() {
|
||||
|
||||
private val service = Executors.newSingleThreadScheduledExecutor()
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var trackView: TrackView
|
||||
private lateinit var mapFrame: FrameLayout
|
||||
@@ -54,7 +50,8 @@ class WorldMapFragment : Fragment() {
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var selectedSat: TLE
|
||||
private lateinit var tleMainList: List<TLE>
|
||||
private lateinit var selectionList: MutableList<Int>
|
||||
private lateinit var tleSelection: MutableList<Int>
|
||||
private lateinit var gsp: GroundStationPosition
|
||||
private var checkedItem = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -73,15 +70,24 @@ class WorldMapFragment : Fragment() {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val delay = viewModel.updateFreq
|
||||
tleMainList = viewModel.tleMainList
|
||||
selectionList = viewModel.selectionList
|
||||
findViews(view)
|
||||
setupComponents()
|
||||
}
|
||||
|
||||
private fun findViews(view: View) {
|
||||
mapFrame = view.findViewById(R.id.worldmap_frame)
|
||||
fab = view.findViewById(R.id.worldmap_fab)
|
||||
}
|
||||
|
||||
if (tleMainList.isNotEmpty() && selectionList.isNotEmpty()) {
|
||||
fab.setOnClickListener { showSelectSatDialog(tleMainList, selectionList) }
|
||||
selectedSat = tleMainList[selectionList[0]]
|
||||
private fun setupComponents() {
|
||||
val delay = viewModel.delay
|
||||
tleMainList = viewModel.tleMainList
|
||||
tleSelection = viewModel.tleSelection
|
||||
gsp = viewModel.gsp.value!!
|
||||
|
||||
if (tleMainList.isNotEmpty() && tleSelection.isNotEmpty()) {
|
||||
fab.setOnClickListener { showSelectSatDialog(tleMainList, tleSelection) }
|
||||
selectedSat = tleMainList[tleSelection[0]]
|
||||
predictor = PassPredictor(selectedSat, viewModel.gsp.value)
|
||||
trackView = TrackView(mainActivity)
|
||||
mapFrame.addView(trackView)
|
||||
@@ -97,8 +103,7 @@ class WorldMapFragment : Fragment() {
|
||||
mainActivity,
|
||||
getString(R.string.no_selected_sat),
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
.show()
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +120,7 @@ class WorldMapFragment : Fragment() {
|
||||
.setSingleChoiceItems(tleNameArray, checkedItem) { dialog, which ->
|
||||
checkedItem = which
|
||||
selectedSat = tleMainList[selectionList[which]]
|
||||
predictor = PassPredictor(selectedSat, viewModel.gsp.value)
|
||||
predictor = PassPredictor(selectedSat, gsp)
|
||||
trackView.invalidate()
|
||||
dialog.dismiss()
|
||||
}
|
||||
@@ -124,7 +129,6 @@ class WorldMapFragment : Fragment() {
|
||||
}
|
||||
|
||||
inner class TrackView(context: Context) : View(context) {
|
||||
private val gsp = viewModel.gsp.value!!
|
||||
private val scale = resources.displayMetrics.density
|
||||
private val groundTrackPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
@@ -166,7 +170,7 @@ class WorldMapFragment : Fragment() {
|
||||
val satPosList = predictor.getPositions(currentTime, 60, 0, orbitalPeriod * 3)
|
||||
drawGroundTrack(canvas, degLon, degLat, satPosList)
|
||||
|
||||
selectionList.forEach {
|
||||
tleSelection.forEach {
|
||||
drawSat(it, currentTime, canvas, degLon, degLat)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#C0C0C0"
|
||||
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" />
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#C0C0C0"
|
||||
android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,49 @@
|
||||
<?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:id="@+id/pass_pref_root"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pref_hours_ahead_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/pref_hours_ahead_summary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/pref_hours_ahead_et"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/pref_hours_ahead_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="number"
|
||||
app:layout_constraintEnd_toEndOf="@+id/pref_hours_ahead_tv"
|
||||
app:layout_constraintStart_toStartOf="@+id/pref_hours_ahead_tv"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pref_hours_ahead_tv" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pref_min_el_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/pref_min_el_summary"
|
||||
app:layout_constraintEnd_toEndOf="@+id/pref_hours_ahead_et"
|
||||
app:layout_constraintStart_toStartOf="@+id/pref_hours_ahead_et"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pref_hours_ahead_et" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/pref_min_el_et"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/pref_min_el_hint"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="number"
|
||||
app:layout_constraintEnd_toEndOf="@+id/pref_min_el_tv"
|
||||
app:layout_constraintStart_toStartOf="@+id/pref_min_el_tv"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pref_min_el_tv" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -41,16 +41,17 @@
|
||||
|
||||
<string name="dialog_select_sat">Select satellites to track</string>
|
||||
<string name="dialog_show_track">Show ground track for…</string>
|
||||
<string name="dialog_pass_prefs">Satellite pass preferences</string>
|
||||
|
||||
<string name="pref_hours_ahead_summary">Show passes that occur within X hours</string>
|
||||
<string name="pref_hours_ahead_hint">Hours ahead</string>
|
||||
<string name="pref_min_el_summary">Show passes with max elevation above</string>
|
||||
<string name="pref_min_el_hint">Minimum elevation</string>
|
||||
|
||||
<string name="pref_gsp_title">Ground station position settings</string>
|
||||
<string name="pref_lat_title">Latitude</string>
|
||||
<string name="pref_lon_title">Longitude</string>
|
||||
<string name="pref_alt_title">Altitude</string>
|
||||
<string name="pref_sat_pass_title">Satellite pass settings</string>
|
||||
<string name="pref_hours_ahead_title">Hours ahead</string>
|
||||
<string name="pref_hours_ahead_summary">Show passes that occur within X hours</string>
|
||||
<string name="pref_min_el_title">Minimum elevation</string>
|
||||
<string name="pref_min_el_summary">Show passes with max elevation above</string>
|
||||
<string name="pref_other_title">Other settings</string>
|
||||
<string name="pref_update_freq_title">Update frequency</string>
|
||||
<string name="pref_update_freq_summary">Views update interval, ms</string>
|
||||
@@ -63,9 +64,9 @@
|
||||
<string name="key_lat">latitude</string>
|
||||
<string name="key_lon">longitude</string>
|
||||
<string name="key_alt">altitude</string>
|
||||
<string name="key_hours_ahead">hours_ahead</string>
|
||||
<string name="key_min_el">min_elevation</string>
|
||||
<string name="key_update_freq">update_freq</string>
|
||||
<string name="key_hours_ahead">hoursAhead</string>
|
||||
<string name="key_min_el">minEl</string>
|
||||
<string name="key_delay">delay</string>
|
||||
<string name="tle_main_list_file_name">tleFile.txt</string>
|
||||
<string name="tle_selection_file_name">tleSelection</string>
|
||||
|
||||
@@ -83,8 +84,7 @@
|
||||
<string name="trans_inverted">Inverted: Yes</string>
|
||||
<string name="trans_header">Transmitters:</string>
|
||||
|
||||
<string name="pattern_lat">%.4f</string>
|
||||
<string name="pattern_lon">%.4f</string>
|
||||
<string name="pattern_location">%.4f</string>
|
||||
<string name="pattern_aos">AOS -%02d:%02d:%02d</string>
|
||||
<string name="pattern_trans_mode">Mode: %s</string>
|
||||
<string name="pattern_trans_inverted">Inverted: %s</string>
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<style name="ToolbarButton">
|
||||
<item name="android:layout_width">48dp</item>
|
||||
<item name="android:layout_height">48dp</item>
|
||||
<item name="android:src">@drawable/ic_refresh</item>
|
||||
<item name="android:src">@drawable/ic_prefs</item>
|
||||
<item name="android:backgroundTint">@color/toolbarButton</item>
|
||||
</style>
|
||||
|
||||
|
||||
@@ -20,26 +20,10 @@
|
||||
android:singleLine="true"
|
||||
android:title="@string/pref_alt_title" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/pref_sat_pass_title">
|
||||
<EditTextPreference
|
||||
android:defaultValue="@string/def_hours_ahead"
|
||||
android:key="@string/key_hours_ahead"
|
||||
android:selectAllOnFocus="true"
|
||||
android:singleLine="true"
|
||||
android:summary="@string/pref_hours_ahead_summary"
|
||||
android:title="@string/pref_hours_ahead_title" />
|
||||
<EditTextPreference
|
||||
android:defaultValue="@string/def_min_el"
|
||||
android:key="@string/key_min_el"
|
||||
android:selectAllOnFocus="true"
|
||||
android:singleLine="true"
|
||||
android:summary="@string/pref_min_el_summary"
|
||||
android:title="@string/pref_min_el_title" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/pref_other_title">
|
||||
<EditTextPreference
|
||||
android:defaultValue="@string/def_update_freq"
|
||||
android:key="@string/key_update_freq"
|
||||
android:key="@string/key_delay"
|
||||
android:selectAllOnFocus="true"
|
||||
android:singleLine="true"
|
||||
android:summary="@string/pref_update_freq_summary"
|
||||
|
||||
Reference in new issue
Block a user