Further refactoring. Restored the SatPass preferences dialog. Code cleanup.

This commit is contained in:
Arty Bishop committed 2019-12-29 21:42:37 +00:00
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)
}
}
+9
View File
@@ -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>
-9
View File
@@ -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>
+49
View File
@@ -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>
+10 -10
View File
@@ -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>
+1 -1
View File
@@ -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>
+1 -17
View File
@@ -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"