mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Fragments and adapters refactoring
This commit is contained in:
1 parent
f04e54d59b
commit
37c5ebbf2e
10 files changed
+141
-127
No files matched your search
@@ -18,11 +18,11 @@
|
|||||||
package com.rtbishop.look4sat.data.model
|
package com.rtbishop.look4sat.data.model
|
||||||
|
|
||||||
import com.github.amsacode.predict4java.SatPassTime
|
import com.github.amsacode.predict4java.SatPassTime
|
||||||
import com.github.amsacode.predict4java.TLE
|
import com.github.amsacode.predict4java.Satellite
|
||||||
import com.rtbishop.look4sat.utility.PassPredictor
|
import com.rtbishop.look4sat.utility.PassPredictor
|
||||||
|
|
||||||
class SatPass(
|
class SatPass(
|
||||||
val tle: TLE,
|
val satellite: Satellite,
|
||||||
val predictor: PassPredictor,
|
val predictor: PassPredictor,
|
||||||
val pass: SatPassTime,
|
val pass: SatPassTime,
|
||||||
var progress: Int = 0
|
var progress: Int = 0
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ class PassesRepo @Inject constructor(
|
|||||||
private val prefsRepo: PrefsRepo,
|
private val prefsRepo: PrefsRepo,
|
||||||
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher
|
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher
|
||||||
) {
|
) {
|
||||||
private val _passes = MutableStateFlow<Result<MutableList<SatPass>>>(Result.InProgress)
|
private val _passes =
|
||||||
|
MutableStateFlow<Result<MutableList<SatPass>>>(Result.Success(mutableListOf()))
|
||||||
val passes: StateFlow<Result<MutableList<SatPass>>> = _passes
|
val passes: StateFlow<Result<MutableList<SatPass>>> = _passes
|
||||||
|
|
||||||
private var selectedSatellites = emptyList<Satellite>()
|
private var selectedSatellites = emptyList<Satellite>()
|
||||||
@@ -61,7 +62,7 @@ class PassesRepo @Inject constructor(
|
|||||||
private fun getPasses(satellite: Satellite, refDate: Date): MutableList<SatPass> {
|
private fun getPasses(satellite: Satellite, refDate: Date): MutableList<SatPass> {
|
||||||
val predictor = satellite.getPredictor(prefsRepo.getStationPosition())
|
val predictor = satellite.getPredictor(prefsRepo.getStationPosition())
|
||||||
val passes = predictor.getPasses(refDate, prefsRepo.getHoursAhead(), true)
|
val passes = predictor.getPasses(refDate, prefsRepo.getHoursAhead(), true)
|
||||||
val passList = passes.map { SatPass(satellite.tle, predictor, it) }
|
val passList = passes.map { SatPass(satellite, predictor, it) }
|
||||||
return passList as MutableList<SatPass>
|
return passList as MutableList<SatPass>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,10 +46,8 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), EntriesAdapter.Entr
|
|||||||
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||||
uri?.let { viewModel.importSatDataFromFile(uri) }
|
uri?.let { viewModel.importSatDataFromFile(uri) }
|
||||||
}
|
}
|
||||||
private val entriesAdapter = EntriesAdapter().apply {
|
|
||||||
setEntriesClickListener(this@EntriesFragment)
|
|
||||||
}
|
|
||||||
private var binding: FragmentEntriesBinding? = null
|
private var binding: FragmentEntriesBinding? = null
|
||||||
|
private var entriesAdapter: EntriesAdapter? = null
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@@ -60,6 +58,9 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), EntriesAdapter.Entr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupComponents() {
|
private fun setupComponents() {
|
||||||
|
entriesAdapter = EntriesAdapter().apply {
|
||||||
|
setEntriesClickListener(this@EntriesFragment)
|
||||||
|
}
|
||||||
binding?.apply {
|
binding?.apply {
|
||||||
entriesRecycler.apply {
|
entriesRecycler.apply {
|
||||||
setHasFixedSize(true)
|
setHasFixedSize(true)
|
||||||
@@ -70,7 +71,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), EntriesAdapter.Entr
|
|||||||
}
|
}
|
||||||
importWeb.setOnClickListener { showImportFromWebDialog() }
|
importWeb.setOnClickListener { showImportFromWebDialog() }
|
||||||
importFile.setOnClickListener { filePicker.launch("*/*") }
|
importFile.setOnClickListener { filePicker.launch("*/*") }
|
||||||
selectAll.setOnClickListener { entriesAdapter.selectAllItems() }
|
selectAll.setOnClickListener { entriesAdapter?.selectAllItems() }
|
||||||
searchBar.addTextChangedListener { query -> filterByQuery(query) }
|
searchBar.addTextChangedListener { query -> filterByQuery(query) }
|
||||||
searchBar.clearFocus()
|
searchBar.clearFocus()
|
||||||
}
|
}
|
||||||
@@ -83,7 +84,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), EntriesAdapter.Entr
|
|||||||
if (result.data.isEmpty()) {
|
if (result.data.isEmpty()) {
|
||||||
setEmpty()
|
setEmpty()
|
||||||
} else {
|
} else {
|
||||||
entriesAdapter.submitAllItems(result.data)
|
entriesAdapter?.submitAllItems(result.data)
|
||||||
setLoaded()
|
setLoaded()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +135,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), EntriesAdapter.Entr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun filterByQuery(it: Editable?) {
|
private fun filterByQuery(it: Editable?) {
|
||||||
entriesAdapter.filterItems(it.toString())
|
entriesAdapter?.filterItems(it.toString())
|
||||||
binding?.entriesRecycler?.scrollToPosition(0)
|
binding?.entriesRecycler?.scrollToPosition(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +148,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries), EntriesAdapter.Entr
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
entriesAdapter = null
|
||||||
binding = null
|
binding = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.ui.passesScreen
|
package com.rtbishop.look4sat.ui.passesScreen
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
@@ -31,22 +30,9 @@ import com.rtbishop.look4sat.utility.navigateSafe
|
|||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PassesAdapter(context: Context, private val shouldUseUTC: Boolean = false) :
|
class PassesAdapter(private val shouldUseUTC: Boolean = false) :
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
private val currentDate = Date()
|
|
||||||
private val satIdFormat = context.getString(R.string.pass_satId)
|
|
||||||
private val azFormat = context.getString(R.string.pat_azimuth)
|
|
||||||
private val altFormat = context.getString(R.string.pat_altitude)
|
|
||||||
private val elevFormat = context.getString(R.string.pat_elevation)
|
|
||||||
private val aosAzFormat = context.getString(R.string.pass_aosAz)
|
|
||||||
private val maxElFormat = context.getString(R.string.pass_maxEl)
|
|
||||||
private val losAzFormat = context.getString(R.string.pass_losAz)
|
|
||||||
private val startTimeFormat = context.getString(R.string.pass_startTime)
|
|
||||||
private val endTimeFormat = context.getString(R.string.pass_endTime)
|
|
||||||
private val timeZoneUTC = TimeZone.getTimeZone("UTC")
|
|
||||||
private val startFormat = SimpleDateFormat(startTimeFormat, Locale.getDefault())
|
|
||||||
private val endFormat = SimpleDateFormat(endTimeFormat, Locale.getDefault())
|
|
||||||
private var satPassList: MutableList<SatPass> = mutableListOf()
|
private var satPassList: MutableList<SatPass> = mutableListOf()
|
||||||
|
|
||||||
fun setList(list: MutableList<SatPass>) {
|
fun setList(list: MutableList<SatPass>) {
|
||||||
@@ -55,11 +41,10 @@ class PassesAdapter(context: Context, private val shouldUseUTC: Boolean = false)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun tickPasses(timeNow: Long) {
|
fun tickPasses(timeNow: Long) {
|
||||||
currentDate.time = timeNow
|
|
||||||
val iterator = satPassList.listIterator()
|
val iterator = satPassList.listIterator()
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
val satPass = iterator.next()
|
val satPass = iterator.next()
|
||||||
if (!satPass.tle.isDeepspace) {
|
if (!satPass.satellite.tle.isDeepspace) {
|
||||||
if (satPass.progress < 100) {
|
if (satPass.progress < 100) {
|
||||||
val timeStart = satPass.pass.startTime.time
|
val timeStart = satPass.pass.startTime.time
|
||||||
if (timeNow > timeStart) {
|
if (timeNow > timeStart) {
|
||||||
@@ -84,42 +69,49 @@ class PassesAdapter(context: Context, private val shouldUseUTC: Boolean = false)
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
return if (satPassList[position].tle.isDeepspace) 1
|
return if (satPassList[position].satellite.tle.isDeepspace) 1
|
||||||
else 0
|
else 0
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
return if (viewType == 0) {
|
return if (viewType == 0) {
|
||||||
val bindingLeo = ItemPassLeoBinding
|
SatPassLeoHolder.from(parent)
|
||||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
|
||||||
SatPassLeoHolder(bindingLeo)
|
|
||||||
} else {
|
} else {
|
||||||
val bindingGeo = ItemPassGeoBinding
|
SatPassGeoHolder.from(parent)
|
||||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
|
||||||
SatPassGeoHolder(bindingGeo)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
if (holder.itemViewType == 0) {
|
if (holder.itemViewType == 0) {
|
||||||
(holder as SatPassLeoHolder).bind(satPassList[position])
|
(holder as SatPassLeoHolder).bind(satPassList[position], position, shouldUseUTC)
|
||||||
} else {
|
} else {
|
||||||
(holder as SatPassGeoHolder).bind(satPassList[position])
|
(holder as SatPassGeoHolder).bind(satPassList[position], position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class SatPassLeoHolder(private val binding: ItemPassLeoBinding) :
|
class SatPassLeoHolder private constructor(private val binding: ItemPassLeoBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
fun bind(satPass: SatPass) {
|
private val satIdFormat = itemView.context.getString(R.string.pass_satId)
|
||||||
val satPos = satPass.predictor.getSatPos(currentDate)
|
private val altFormat = itemView.context.getString(R.string.pat_altitude)
|
||||||
|
private val aosAzFormat = itemView.context.getString(R.string.pass_aosAz)
|
||||||
|
private val maxElFormat = itemView.context.getString(R.string.pass_maxEl)
|
||||||
|
private val losAzFormat = itemView.context.getString(R.string.pass_losAz)
|
||||||
|
private val startTimeFormat = itemView.context.getString(R.string.pass_startTime)
|
||||||
|
private val endTimeFormat = itemView.context.getString(R.string.pass_endTime)
|
||||||
|
private val timeZoneUTC = TimeZone.getTimeZone("UTC")
|
||||||
|
private val startFormat = SimpleDateFormat(startTimeFormat, Locale.getDefault())
|
||||||
|
private val endFormat = SimpleDateFormat(endTimeFormat, Locale.getDefault())
|
||||||
|
|
||||||
|
fun bind(satPass: SatPass, position: Int, shouldUseUTC: Boolean) {
|
||||||
|
val satPos = satPass.predictor.getSatPos(Date())
|
||||||
binding.apply {
|
binding.apply {
|
||||||
if (shouldUseUTC) {
|
if (shouldUseUTC) {
|
||||||
startFormat.timeZone = timeZoneUTC
|
startFormat.timeZone = timeZoneUTC
|
||||||
endFormat.timeZone = timeZoneUTC
|
endFormat.timeZone = timeZoneUTC
|
||||||
}
|
}
|
||||||
passLeoSatName.text = satPass.tle.name
|
passLeoSatName.text = satPass.satellite.tle.name
|
||||||
passLeoSatId.text = String.format(satIdFormat, satPass.tle.catnum)
|
passLeoSatId.text = String.format(satIdFormat, satPass.satellite.tle.catnum)
|
||||||
passLeoAosAz.text = String.format(aosAzFormat, satPass.pass.aosAzimuth)
|
passLeoAosAz.text = String.format(aosAzFormat, satPass.pass.aosAzimuth)
|
||||||
passLeoMaxEl.text = String.format(maxElFormat, satPass.pass.maxEl)
|
passLeoMaxEl.text = String.format(maxElFormat, satPass.pass.maxEl)
|
||||||
passLeoLosAz.text = String.format(losAzFormat, satPass.pass.losAzimuth)
|
passLeoLosAz.text = String.format(losAzFormat, satPass.pass.losAzimuth)
|
||||||
@@ -131,30 +123,49 @@ class PassesAdapter(context: Context, private val shouldUseUTC: Boolean = false)
|
|||||||
|
|
||||||
itemView.setOnClickListener {
|
itemView.setOnClickListener {
|
||||||
if (satPass.progress < 100) {
|
if (satPass.progress < 100) {
|
||||||
val bundle = bundleOf("index" to satPassList.indexOf(satPass))
|
val bundle = bundleOf("index" to position)
|
||||||
itemView.findNavController().navigateSafe(R.id.action_passes_to_polar, bundle)
|
itemView.findNavController().navigateSafe(R.id.action_passes_to_polar, bundle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun from(parent: ViewGroup): SatPassLeoHolder {
|
||||||
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
|
return SatPassLeoHolder(ItemPassLeoBinding.inflate(inflater, parent, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class SatPassGeoHolder(private val binding: ItemPassGeoBinding) :
|
class SatPassGeoHolder private constructor(private val binding: ItemPassGeoBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
fun bind(satPass: SatPass) {
|
private val satIdFormat = itemView.context.getString(R.string.pass_satId)
|
||||||
val satPos = satPass.predictor.getSatPos(currentDate)
|
private val azFormat = itemView.context.getString(R.string.pat_azimuth)
|
||||||
|
private val altFormat = itemView.context.getString(R.string.pat_altitude)
|
||||||
|
private val elevFormat = itemView.context.getString(R.string.pat_elevation)
|
||||||
|
|
||||||
|
fun bind(satPass: SatPass, position: Int) {
|
||||||
|
val satPos = satPass.predictor.getSatPos(Date())
|
||||||
binding.apply {
|
binding.apply {
|
||||||
passGeoSatName.text = satPass.tle.name
|
passGeoSatName.text = satPass.satellite.tle.name
|
||||||
passGeoSatId.text = String.format(satIdFormat, satPass.tle.catnum)
|
passGeoSatId.text = String.format(satIdFormat, satPass.satellite.tle.catnum)
|
||||||
passGeoAz.text = String.format(azFormat, Math.toDegrees(satPos.azimuth))
|
passGeoAz.text = String.format(azFormat, Math.toDegrees(satPos.azimuth))
|
||||||
passGeoAlt.text = String.format(altFormat, satPos.altitude)
|
passGeoAlt.text = String.format(altFormat, satPos.altitude)
|
||||||
passGeoEl.text = String.format(elevFormat, Math.toDegrees(satPos.elevation))
|
passGeoEl.text = String.format(elevFormat, Math.toDegrees(satPos.elevation))
|
||||||
}
|
}
|
||||||
|
|
||||||
itemView.setOnClickListener {
|
itemView.setOnClickListener {
|
||||||
val bundle = bundleOf("index" to satPassList.indexOf(satPass))
|
val bundle = bundleOf("index" to position)
|
||||||
itemView.findNavController().navigateSafe(R.id.action_passes_to_polar, bundle)
|
itemView.findNavController().navigateSafe(R.id.action_passes_to_polar, bundle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun from(parent: ViewGroup): SatPassGeoHolder {
|
||||||
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
|
return SatPassGeoHolder(ItemPassGeoBinding.inflate(inflater, parent, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,10 +37,10 @@ import java.util.*
|
|||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PassesFragment : Fragment(R.layout.fragment_passes) {
|
class PassesFragment : Fragment(R.layout.fragment_passes) {
|
||||||
|
|
||||||
private var binding: FragmentPassesBinding? = null
|
|
||||||
private var passesAdapter: PassesAdapter? = null
|
|
||||||
private val viewModel: PassesViewModel by viewModels()
|
private val viewModel: PassesViewModel by viewModels()
|
||||||
private var passes = mutableListOf<SatPass>()
|
private var passes = mutableListOf<SatPass>()
|
||||||
|
private var binding: FragmentPassesBinding? = null
|
||||||
|
private var passesAdapter: PassesAdapter? = null
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@@ -84,7 +84,7 @@ class PassesFragment : Fragment(R.layout.fragment_passes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupComponents() {
|
private fun setupComponents() {
|
||||||
passesAdapter = PassesAdapter(requireContext(), viewModel.shouldUseUTC())
|
passesAdapter = PassesAdapter(viewModel.shouldUseUTC())
|
||||||
binding?.apply {
|
binding?.apply {
|
||||||
passesRecycler.apply {
|
passesRecycler.apply {
|
||||||
setHasFixedSize(true)
|
setHasFixedSize(true)
|
||||||
|
|||||||
@@ -32,23 +32,18 @@ import androidx.recyclerview.widget.SimpleItemAnimator
|
|||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.data.model.Result
|
import com.rtbishop.look4sat.data.model.Result
|
||||||
import com.rtbishop.look4sat.data.model.SatPass
|
import com.rtbishop.look4sat.data.model.SatPass
|
||||||
import com.rtbishop.look4sat.data.repository.PrefsRepo
|
|
||||||
import com.rtbishop.look4sat.databinding.FragmentPolarBinding
|
import com.rtbishop.look4sat.databinding.FragmentPolarBinding
|
||||||
import com.rtbishop.look4sat.utility.RecyclerDivider
|
import com.rtbishop.look4sat.utility.RecyclerDivider
|
||||||
import com.rtbishop.look4sat.utility.formatForTimer
|
import com.rtbishop.look4sat.utility.formatForTimer
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.FlowPreview
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlin.math.round
|
import kotlin.math.round
|
||||||
|
|
||||||
@FlowPreview
|
@FlowPreview
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var prefsRepo: PrefsRepo
|
|
||||||
|
|
||||||
private lateinit var transmitterAdapter: TransAdapter
|
private lateinit var transmitterAdapter: TransAdapter
|
||||||
private lateinit var binding: FragmentPolarBinding
|
private lateinit var binding: FragmentPolarBinding
|
||||||
private lateinit var satPass: SatPass
|
private lateinit var satPass: SatPass
|
||||||
@@ -61,13 +56,13 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding = FragmentPolarBinding.bind(view)
|
binding = FragmentPolarBinding.bind(view)
|
||||||
sensorManager = requireContext().getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
sensorManager = requireContext().getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
||||||
magneticDeclination = prefsRepo.getMagDeclination()
|
magneticDeclination = viewModel.getMagDeclination()
|
||||||
observePasses()
|
observePasses()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
if (prefsRepo.shouldUseCompass()) {
|
if (viewModel.shouldUseCompass()) {
|
||||||
sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR).also { sensor ->
|
sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR).also { sensor ->
|
||||||
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI)
|
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI)
|
||||||
}
|
}
|
||||||
@@ -76,7 +71,7 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
|||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
if (prefsRepo.shouldUseCompass()) {
|
if (viewModel.shouldUseCompass()) {
|
||||||
sensorManager.unregisterListener(this)
|
sensorManager.unregisterListener(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,7 +93,7 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun observePasses() {
|
private fun observePasses() {
|
||||||
viewModel.passes.observe(viewLifecycleOwner, { result ->
|
viewModel.getPasses().observe(viewLifecycleOwner, { result ->
|
||||||
if (result is Result.Success) {
|
if (result is Result.Success) {
|
||||||
satPass = result.data[requireArguments().getInt("index")]
|
satPass = result.data[requireArguments().getInt("index")]
|
||||||
polarView = PolarView(requireContext()).apply { setPass(satPass) }
|
polarView = PolarView(requireContext()).apply { setPass(satPass) }
|
||||||
@@ -109,26 +104,27 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun observeTransmitters() {
|
private fun observeTransmitters() {
|
||||||
viewModel.getTransmittersForSat(satPass.tle.catnum).observe(viewLifecycleOwner, { list ->
|
viewModel.getTransmittersForSat(satPass.satellite.tle.catnum)
|
||||||
transmitterAdapter = TransAdapter(requireContext(), satPass)
|
.observe(viewLifecycleOwner, { list ->
|
||||||
if (list.isNotEmpty()) {
|
transmitterAdapter = TransAdapter(satPass)
|
||||||
transmitterAdapter.setData(list)
|
if (list.isNotEmpty()) {
|
||||||
binding.recycler.apply {
|
transmitterAdapter.setData(list)
|
||||||
setHasFixedSize(true)
|
binding.recycler.apply {
|
||||||
adapter = transmitterAdapter
|
setHasFixedSize(true)
|
||||||
isVerticalScrollBarEnabled = false
|
adapter = transmitterAdapter
|
||||||
layoutManager = LinearLayoutManager(context)
|
isVerticalScrollBarEnabled = false
|
||||||
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
layoutManager = LinearLayoutManager(context)
|
||||||
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_dark))
|
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
||||||
visibility = View.VISIBLE
|
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_dark))
|
||||||
|
visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
binding.noTransMsg.visibility = View.INVISIBLE
|
||||||
|
} else {
|
||||||
|
binding.recycler.visibility = View.INVISIBLE
|
||||||
|
binding.noTransMsg.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
binding.noTransMsg.visibility = View.INVISIBLE
|
observeTimer()
|
||||||
} else {
|
})
|
||||||
binding.recycler.visibility = View.INVISIBLE
|
|
||||||
binding.noTransMsg.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
observeTimer()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeTimer() {
|
private fun observeTimer() {
|
||||||
@@ -151,7 +147,7 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
|||||||
binding.distance.text = String.format(polarRng, satPos.range)
|
binding.distance.text = String.format(polarRng, satPos.range)
|
||||||
binding.altitude.text = String.format(polarAlt, satPos.altitude)
|
binding.altitude.text = String.format(polarAlt, satPos.altitude)
|
||||||
|
|
||||||
if (!satPass.tle.isDeepspace) {
|
if (!satPass.satellite.tle.isDeepspace) {
|
||||||
if (dateNow.before(satPass.pass.startTime)) {
|
if (dateNow.before(satPass.pass.startTime)) {
|
||||||
val millisBeforeStart = satPass.pass.startTime.time.minus(timeNow)
|
val millisBeforeStart = satPass.pass.startTime.time.minus(timeNow)
|
||||||
binding.polarTimer.text = millisBeforeStart.formatForTimer()
|
binding.polarTimer.text = millisBeforeStart.formatForTimer()
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class PolarView(context: Context) : View(context) {
|
|||||||
canvas.translate(polarCenter, polarCenter)
|
canvas.translate(polarCenter, polarCenter)
|
||||||
drawRadarView(canvas)
|
drawRadarView(canvas)
|
||||||
drawRadarText(canvas)
|
drawRadarText(canvas)
|
||||||
if (!satPass.tle.isDeepspace) drawPassTrajectory(canvas, satPass)
|
if (!satPass.satellite.tle.isDeepspace) drawPassTrajectory(canvas, satPass)
|
||||||
drawSatellite(canvas, satPass)
|
drawSatellite(canvas, satPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,12 +30,10 @@ import javax.inject.Inject
|
|||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class PolarViewModel @Inject constructor(
|
class PolarViewModel @Inject constructor(
|
||||||
private val prefsRepo: PrefsRepo,
|
private val prefsRepo: PrefsRepo,
|
||||||
passesRepo: PassesRepo,
|
private val passesRepo: PassesRepo,
|
||||||
private val satelliteRepo: SatelliteRepo
|
private val satelliteRepo: SatelliteRepo
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
val passes = passesRepo.passes.asLiveData()
|
|
||||||
|
|
||||||
fun getAppTimer() = liveData {
|
fun getAppTimer() = liveData {
|
||||||
while (true) {
|
while (true) {
|
||||||
emit(System.currentTimeMillis())
|
emit(System.currentTimeMillis())
|
||||||
@@ -43,5 +41,15 @@ class PolarViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getPasses() = passesRepo.passes.asLiveData()
|
||||||
|
|
||||||
|
fun shouldUseCompass(): Boolean {
|
||||||
|
return prefsRepo.shouldUseCompass()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMagDeclination(): Float {
|
||||||
|
return prefsRepo.getMagDeclination()
|
||||||
|
}
|
||||||
|
|
||||||
fun getTransmittersForSat(satId: Int) = satelliteRepo.getSatTransmitters(satId).asLiveData()
|
fun getTransmittersForSat(satId: Int) = satelliteRepo.getSatTransmitters(satId).asLiveData()
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.ui.polarScreen
|
package com.rtbishop.look4sat.ui.polarScreen
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@@ -25,19 +24,12 @@ import com.rtbishop.look4sat.R
|
|||||||
import com.rtbishop.look4sat.data.model.SatPass
|
import com.rtbishop.look4sat.data.model.SatPass
|
||||||
import com.rtbishop.look4sat.data.model.SatTrans
|
import com.rtbishop.look4sat.data.model.SatTrans
|
||||||
import com.rtbishop.look4sat.databinding.ItemTransBinding
|
import com.rtbishop.look4sat.databinding.ItemTransBinding
|
||||||
|
import com.rtbishop.look4sat.utility.PassPredictor
|
||||||
|
import com.rtbishop.look4sat.utility.getDopplerFreq
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class TransAdapter(context: Context, private val satPass: SatPass) :
|
class TransAdapter(private val pass: SatPass) : RecyclerView.Adapter<TransAdapter.TransHolder>() {
|
||||||
RecyclerView.Adapter<TransAdapter.TransHolder>() {
|
|
||||||
|
|
||||||
private val divider = 1000000f
|
|
||||||
private val strNo = context.getString(R.string.btn_no)
|
|
||||||
private val strYes = context.getString(R.string.btn_yes)
|
|
||||||
private val mode = context.getString(R.string.trans_mode)
|
|
||||||
private val formatLink = context.getString(R.string.trans_link_low)
|
|
||||||
private val formatLinkNull = context.getString(R.string.trans_no_link)
|
|
||||||
private val isInverted = context.getString(R.string.trans_inverted)
|
|
||||||
private val predictor = satPass.predictor
|
|
||||||
private var transmittersList = emptyList<SatTrans>()
|
private var transmittersList = emptyList<SatTrans>()
|
||||||
|
|
||||||
fun setData(list: List<SatTrans>) {
|
fun setData(list: List<SatTrans>) {
|
||||||
@@ -46,7 +38,7 @@ class TransAdapter(context: Context, private val satPass: SatPass) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun tickTransmitters() {
|
fun tickTransmitters() {
|
||||||
if (!satPass.tle.isDeepspace) {
|
if (!pass.satellite.tle.isDeepspace) {
|
||||||
val iterator = transmittersList.listIterator()
|
val iterator = transmittersList.listIterator()
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
val trans = iterator.next()
|
val trans = iterator.next()
|
||||||
@@ -61,23 +53,29 @@ class TransAdapter(context: Context, private val satPass: SatPass) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransHolder {
|
||||||
val binding = ItemTransBinding
|
return TransHolder.from(parent)
|
||||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
|
||||||
return TransHolder(binding)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: TransHolder, position: Int) {
|
override fun onBindViewHolder(holder: TransHolder, position: Int) {
|
||||||
holder.bind(transmittersList[position])
|
holder.bind(transmittersList[position], pass)
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class TransHolder(private val binding: ItemTransBinding) :
|
class TransHolder private constructor(private val binding: ItemTransBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
fun bind(satTrans: SatTrans) {
|
private val divider = 1000000f
|
||||||
|
private val strNo = itemView.context.getString(R.string.btn_no)
|
||||||
|
private val strYes = itemView.context.getString(R.string.btn_yes)
|
||||||
|
private val mode = itemView.context.getString(R.string.trans_mode)
|
||||||
|
private val formatLink = itemView.context.getString(R.string.trans_link_low)
|
||||||
|
private val formatLinkNull = itemView.context.getString(R.string.trans_no_link)
|
||||||
|
private val isInverted = itemView.context.getString(R.string.trans_inverted)
|
||||||
|
|
||||||
|
fun bind(satTrans: SatTrans, satPass: SatPass) {
|
||||||
binding.description.text = satTrans.description
|
binding.description.text = satTrans.description
|
||||||
|
|
||||||
if (satPass.tle.isDeepspace) setRegularFreq(satTrans)
|
if (satPass.satellite.tle.isDeepspace) setRegularFreq(satTrans)
|
||||||
else setDopplerFreq(satTrans)
|
else setDopplerFreq(satTrans, satPass.predictor)
|
||||||
|
|
||||||
if (satTrans.mode != null) binding.mode.text = String.format(mode, satTrans.mode)
|
if (satTrans.mode != null) binding.mode.text = String.format(mode, satTrans.mode)
|
||||||
else binding.mode.text = String.format(mode, strNo)
|
else binding.mode.text = String.format(mode, strNo)
|
||||||
@@ -98,18 +96,27 @@ class TransAdapter(context: Context, private val satPass: SatPass) :
|
|||||||
} else binding.uplink.text = formatLinkNull
|
} else binding.uplink.text = formatLinkNull
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setDopplerFreq(satTrans: SatTrans) {
|
private fun setDopplerFreq(satTrans: SatTrans, predictor: PassPredictor) {
|
||||||
val dateNow = Date()
|
val dateNow = Date()
|
||||||
|
|
||||||
if (satTrans.downlinkLow != null) {
|
if (satTrans.downlinkLow != null) {
|
||||||
val downFreq = predictor.getDownlinkFreq(satTrans.downlinkLow, dateNow) / divider
|
val rangeRate = predictor.getSatPos(dateNow).rangeRate
|
||||||
binding.downlink.text = String.format(Locale.ENGLISH, formatLink, downFreq)
|
val freq = satTrans.downlinkLow.getDopplerFreq(rangeRate, true) / divider
|
||||||
|
binding.downlink.text = String.format(Locale.ENGLISH, formatLink, freq)
|
||||||
} else binding.downlink.text = formatLinkNull
|
} else binding.downlink.text = formatLinkNull
|
||||||
|
|
||||||
if (satTrans.uplinkLow != null) {
|
if (satTrans.uplinkLow != null) {
|
||||||
val upFreq = predictor.getUplinkFreq(satTrans.uplinkLow, dateNow) / divider
|
val rangeRate = predictor.getSatPos(dateNow).rangeRate
|
||||||
binding.uplink.text = String.format(Locale.ENGLISH, formatLink, upFreq)
|
val freq = satTrans.uplinkLow.getDopplerFreq(rangeRate, false) / divider
|
||||||
|
binding.uplink.text = String.format(Locale.ENGLISH, formatLink, freq)
|
||||||
} else binding.uplink.text = formatLinkNull
|
} else binding.uplink.text = formatLinkNull
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun from(parent: ViewGroup): TransHolder {
|
||||||
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
|
return TransHolder(ItemTransBinding.inflate(inflater, parent, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,18 +24,8 @@ import com.github.amsacode.predict4java.Satellite
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PassPredictor(private val satellite: Satellite, private val qth: GroundStationPosition) {
|
class PassPredictor(private val satellite: Satellite, private val qth: GroundStationPosition) {
|
||||||
|
|
||||||
private val oneQuarterOrbitMin = (24.0 * 60.0 / satellite.tle.meanmo / 4.0).toInt()
|
private val oneQuarterOrbitMin = (24.0 * 60.0 / satellite.tle.meanmo / 4.0).toInt()
|
||||||
private val speedOfLight = 2.99792458E8
|
|
||||||
|
|
||||||
fun getDownlinkFreq(freq: Long, date: Date): Long {
|
|
||||||
val rangeRate = getSatPos(date).rangeRate
|
|
||||||
return (freq.toDouble() * (speedOfLight - rangeRate * 1000.0) / speedOfLight).toLong()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getUplinkFreq(freq: Long, date: Date): Long {
|
|
||||||
val rangeRate = getSatPos(date).rangeRate
|
|
||||||
return (freq.toDouble() * (speedOfLight + rangeRate * 1000.0) / speedOfLight).toLong()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getSatPos(date: Date): SatPos {
|
fun getSatPos(date: Date): SatPos {
|
||||||
return satellite.getPosition(qth, date)
|
return satellite.getPosition(qth, date)
|
||||||
@@ -81,10 +71,9 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta
|
|||||||
val satPos = getSatPos(refDate)
|
val satPos = getSatPos(refDate)
|
||||||
val startDate = Date(refDate.time - 24 * 60L * 60L * 1000L)
|
val startDate = Date(refDate.time - 24 * 60L * 60L * 1000L)
|
||||||
val endDate = Date(refDate.time + 24 * 60L * 60L * 1000L)
|
val endDate = Date(refDate.time + 24 * 60L * 60L * 1000L)
|
||||||
val aosAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt()
|
val azimuth = Math.toDegrees(satPos.azimuth).toInt()
|
||||||
val losAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt()
|
val maxEl = Math.toDegrees(satPos.elevation)
|
||||||
val maxEl = satPos.elevation / (2.0 * Math.PI) * 360.0
|
return SatPassTime(startDate, endDate, "pole", azimuth, azimuth, maxEl)
|
||||||
return SatPassTime(startDate, endDate, "pole", aosAzimuth, losAzimuth, maxEl)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nextNearEarthPass(refDate: Date, windBack: Boolean = false): SatPassTime {
|
private fun nextNearEarthPass(refDate: Date, windBack: Boolean = false): SatPassTime {
|
||||||
@@ -127,7 +116,7 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta
|
|||||||
} while (satPos.elevation < 0.0)
|
} while (satPos.elevation < 0.0)
|
||||||
|
|
||||||
val startDate = satPos.time
|
val startDate = satPos.time
|
||||||
val aosAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt()
|
val aosAzimuth = Math.toDegrees(satPos.azimuth).toInt()
|
||||||
|
|
||||||
// find when sat goes below
|
// find when sat goes below
|
||||||
do {
|
do {
|
||||||
@@ -147,8 +136,8 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta
|
|||||||
} while (satPos.elevation > 0.0)
|
} while (satPos.elevation > 0.0)
|
||||||
|
|
||||||
val endDate = satPos.time
|
val endDate = satPos.time
|
||||||
val losAzimuth = (satPos.azimuth / (2.0 * Math.PI) * 360.0).toInt()
|
val losAzimuth = Math.toDegrees(satPos.azimuth).toInt()
|
||||||
val maxEl = maxElevation / (2.0 * Math.PI) * 360.0
|
val maxEl = Math.toDegrees(maxElevation)
|
||||||
return SatPassTime(startDate, endDate, "pole", aosAzimuth, losAzimuth, maxEl)
|
return SatPassTime(startDate, endDate, "pole", aosAzimuth, losAzimuth, maxEl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user