mirror of
https://github.com/rt-bishop/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Fixed transmitters doppler frequency update logic
This commit is contained in:
1 parent
555c2fe626
commit
db710c55c4
7 files changed
+108
-90
No files matched your search
+2
-2
@@ -13,8 +13,8 @@ android {
|
|||||||
applicationId "com.rtbishop.look4sat"
|
applicationId "com.rtbishop.look4sat"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 231
|
versionCode 232
|
||||||
versionName "2.3.1"
|
versionName "2.3.2"
|
||||||
kapt {
|
kapt {
|
||||||
arguments {
|
arguments {
|
||||||
arg("room.schemaLocation", "$projectDir/schemas")
|
arg("room.schemaLocation", "$projectDir/schemas")
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ data class SatTrans(
|
|||||||
@PrimaryKey @field:Json(name = "uuid") val uuid: String,
|
@PrimaryKey @field:Json(name = "uuid") val uuid: String,
|
||||||
@field:Json(name = "description") val info: String,
|
@field:Json(name = "description") val info: String,
|
||||||
@field:Json(name = "alive") val isAlive: Boolean,
|
@field:Json(name = "alive") val isAlive: Boolean,
|
||||||
@field:Json(name = "downlink_low") val downlink: Long?,
|
@field:Json(name = "downlink_low") var downlink: Long?,
|
||||||
@field:Json(name = "uplink_low") val uplink: Long?,
|
@field:Json(name = "uplink_low") var uplink: Long?,
|
||||||
@field:Json(name = "mode") val mode: String?,
|
@field:Json(name = "mode") val mode: String?,
|
||||||
@field:Json(name = "invert") val isInverted: Boolean,
|
@field:Json(name = "invert") val isInverted: Boolean,
|
||||||
@field:Json(name = "norad_cat_id") val catNum: Int
|
@field:Json(name = "norad_cat_id") val catNum: Int
|
||||||
|
|||||||
@@ -40,17 +40,18 @@ class PolarFragment : Fragment(R.layout.fragment_polar) {
|
|||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val binding = FragmentPolarBinding.bind(view)
|
FragmentPolarBinding.bind(view).apply {
|
||||||
val catNum = requireArguments().getInt("catNum")
|
val transAdapter = TransAdapter()
|
||||||
val aosTime = requireArguments().getLong("aosTime")
|
recycler.apply {
|
||||||
viewModel.getPass(catNum, aosTime).observe(viewLifecycleOwner) { pass ->
|
setHasFixedSize(true)
|
||||||
polarView = PolarView(requireContext()).apply { setPass(pass) }
|
adapter = transAdapter
|
||||||
binding.frame.addView(polarView)
|
isVerticalScrollBarEnabled = false
|
||||||
observeTransmitters(pass, binding)
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
||||||
|
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_dark))
|
||||||
|
}
|
||||||
|
setupObservers(transAdapter, this)
|
||||||
}
|
}
|
||||||
viewModel.azimuth.observe(viewLifecycleOwner, { trueNorthAzimuth ->
|
|
||||||
polarView?.rotation = -trueNorthAzimuth
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@@ -63,35 +64,41 @@ class PolarFragment : Fragment(R.layout.fragment_polar) {
|
|||||||
viewModel.disableSensor()
|
viewModel.disableSensor()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeTransmitters(satPass: SatPass, binding: FragmentPolarBinding) {
|
private fun setupObservers(transAdapter: TransAdapter, binding: FragmentPolarBinding) {
|
||||||
viewModel.getSatTransmitters(satPass.catNum).observe(viewLifecycleOwner, { list ->
|
val catNum = requireArguments().getInt("catNum")
|
||||||
val transmitterAdapter = TransAdapter(satPass)
|
val aosTime = requireArguments().getLong("aosTime")
|
||||||
|
viewModel.getPass(catNum, aosTime).observe(viewLifecycleOwner) { pass ->
|
||||||
|
polarView = PolarView(requireContext()).apply { setPass(pass) }
|
||||||
|
binding.frame.addView(polarView)
|
||||||
|
observeTransmitters(pass, transAdapter, binding)
|
||||||
|
}
|
||||||
|
viewModel.azimuth.observe(viewLifecycleOwner, { trueNorthAzimuth ->
|
||||||
|
polarView?.rotation = -trueNorthAzimuth
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeTransmitters(
|
||||||
|
satPass: SatPass,
|
||||||
|
transAdapter: TransAdapter,
|
||||||
|
binding: FragmentPolarBinding
|
||||||
|
) {
|
||||||
|
viewModel.transmitters.observe(viewLifecycleOwner, { list ->
|
||||||
if (list.isNotEmpty()) {
|
if (list.isNotEmpty()) {
|
||||||
transmitterAdapter.setData(list)
|
transAdapter.submitList(list)
|
||||||
binding.recycler.apply {
|
binding.recycler.visibility = View.VISIBLE
|
||||||
setHasFixedSize(true)
|
|
||||||
adapter = transmitterAdapter
|
|
||||||
isVerticalScrollBarEnabled = false
|
|
||||||
layoutManager = LinearLayoutManager(context)
|
|
||||||
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
|
||||||
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_dark))
|
|
||||||
visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
binding.noTransMsg.visibility = View.INVISIBLE
|
binding.noTransMsg.visibility = View.INVISIBLE
|
||||||
} else {
|
} else {
|
||||||
binding.recycler.visibility = View.INVISIBLE
|
binding.recycler.visibility = View.INVISIBLE
|
||||||
binding.noTransMsg.visibility = View.VISIBLE
|
binding.noTransMsg.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
viewModel.getAppTimer().observe(viewLifecycleOwner, {
|
setPassText(satPass, binding)
|
||||||
setPassText(it, satPass, binding)
|
polarView?.invalidate()
|
||||||
polarView?.invalidate()
|
|
||||||
transmitterAdapter.tickTransmitters()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setPassText(timeNow: Long, satPass: SatPass, binding: FragmentPolarBinding) {
|
private fun setPassText(satPass: SatPass, binding: FragmentPolarBinding) {
|
||||||
val dateNow = Date(timeNow)
|
val dateNow = Date()
|
||||||
|
val timeNow = System.currentTimeMillis()
|
||||||
val satPos = satPass.predictor.getSatPos(dateNow)
|
val satPos = satPass.predictor.getSatPos(dateNow)
|
||||||
val polarAz = getString(R.string.pat_azimuth)
|
val polarAz = getString(R.string.pat_azimuth)
|
||||||
val polarEl = getString(R.string.pat_elevation)
|
val polarEl = getString(R.string.pat_elevation)
|
||||||
|
|||||||
@@ -18,12 +18,18 @@
|
|||||||
package com.rtbishop.look4sat.ui.polarScreen
|
package com.rtbishop.look4sat.ui.polarScreen
|
||||||
|
|
||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.*
|
||||||
|
import com.rtbishop.look4sat.data.model.SatPass
|
||||||
|
import com.rtbishop.look4sat.data.model.SatTrans
|
||||||
import com.rtbishop.look4sat.data.repository.PassesRepo
|
import com.rtbishop.look4sat.data.repository.PassesRepo
|
||||||
import com.rtbishop.look4sat.data.repository.SatelliteRepo
|
import com.rtbishop.look4sat.data.repository.SatelliteRepo
|
||||||
import com.rtbishop.look4sat.utility.PrefsManager
|
import com.rtbishop.look4sat.utility.PrefsManager
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
@@ -35,20 +41,18 @@ class PolarViewModel @Inject constructor(
|
|||||||
) : ViewModel(), Orientation.OrientationListener {
|
) : ViewModel(), Orientation.OrientationListener {
|
||||||
|
|
||||||
private val magDeclination = prefsManager.getMagDeclination()
|
private val magDeclination = prefsManager.getMagDeclination()
|
||||||
|
private val _transmitters = MutableLiveData<List<SatTrans>>()
|
||||||
private val _azimuth = MutableLiveData<Float>()
|
private val _azimuth = MutableLiveData<Float>()
|
||||||
|
val transmitters: LiveData<List<SatTrans>> = _transmitters
|
||||||
val azimuth: LiveData<Float> = _azimuth
|
val azimuth: LiveData<Float> = _azimuth
|
||||||
|
|
||||||
fun getAppTimer() = liveData {
|
|
||||||
while (true) {
|
|
||||||
emit(System.currentTimeMillis())
|
|
||||||
delay(1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getPass(catNum: Int, aosTime: Long) = liveData {
|
fun getPass(catNum: Int, aosTime: Long) = liveData {
|
||||||
passesRepo.passes.collect { passes ->
|
passesRepo.passes.collect { passes ->
|
||||||
val pass = passes.find { it.catNum == catNum && it.aosDate.time == aosTime }
|
val pass = passes.find { it.catNum == catNum && it.aosDate.time == aosTime }
|
||||||
pass?.let { emit(it) }
|
pass?.let { satPass ->
|
||||||
|
processTransmitters(satPass)
|
||||||
|
emit(satPass)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,10 +64,28 @@ class PolarViewModel @Inject constructor(
|
|||||||
if (prefsManager.shouldUseCompass()) orientation.stopListening()
|
if (prefsManager.shouldUseCompass()) orientation.stopListening()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSatTransmitters(satId: Int) =
|
|
||||||
satelliteRepo.getSatTransmitters(satId).asLiveData(viewModelScope.coroutineContext)
|
|
||||||
|
|
||||||
override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
|
override fun onOrientationChanged(azimuth: Float, pitch: Float, roll: Float) {
|
||||||
_azimuth.value = azimuth + magDeclination
|
_azimuth.value = azimuth + magDeclination
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun processTransmitters(satPass: SatPass) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
satelliteRepo.getSatTransmitters(satPass.catNum).collect { transList ->
|
||||||
|
while (isActive) {
|
||||||
|
val timeNow = Date()
|
||||||
|
val copiedList = transList.map { it.copy() }
|
||||||
|
copiedList.forEach { transmitter ->
|
||||||
|
transmitter.downlink?.let {
|
||||||
|
transmitter.downlink = satPass.predictor.getDownlinkFreq(it, timeNow)
|
||||||
|
}
|
||||||
|
transmitter.uplink?.let {
|
||||||
|
transmitter.uplink = satPass.predictor.getUplinkFreq(it, timeNow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_transmitters.postValue(copiedList.map { it.copy() })
|
||||||
|
delay(1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -19,45 +19,44 @@ package com.rtbishop.look4sat.ui.polarScreen
|
|||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.AsyncListDiffer
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
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 java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class TransAdapter(private val pass: SatPass) : RecyclerView.Adapter<TransAdapter.TransHolder>() {
|
class TransAdapter : RecyclerView.Adapter<TransAdapter.TransHolder>() {
|
||||||
|
|
||||||
private var transmittersList = emptyList<SatTrans>()
|
private val diffCallback = object : DiffUtil.ItemCallback<SatTrans>() {
|
||||||
|
override fun areItemsTheSame(oldItem: SatTrans, newItem: SatTrans): Boolean {
|
||||||
|
return oldItem.uuid == newItem.uuid
|
||||||
|
}
|
||||||
|
|
||||||
fun setData(list: List<SatTrans>) {
|
override fun areContentsTheSame(oldItem: SatTrans, newItem: SatTrans): Boolean {
|
||||||
transmittersList = list
|
return oldItem.downlink == newItem.downlink
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun tickTransmitters() {
|
|
||||||
if (!pass.isDeepSpace) {
|
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private val differ = AsyncListDiffer(this, diffCallback)
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
fun submitList(transmitters: List<SatTrans>) {
|
||||||
return transmittersList.size
|
differ.submitList(transmitters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = differ.currentList.size
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransHolder {
|
||||||
return TransHolder.from(parent)
|
return TransHolder.from(parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: TransHolder, position: Int) {
|
override fun onBindViewHolder(holder: TransHolder, position: Int) {
|
||||||
holder.bind(transmittersList[position], pass)
|
holder.bind(differ.currentList[position])
|
||||||
}
|
}
|
||||||
|
|
||||||
class TransHolder private constructor(private val binding: ItemTransBinding) :
|
class TransHolder private constructor(private val binding: ItemTransBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
private val dateNow = Date()
|
|
||||||
private val divider = 1000000f
|
private val divider = 1000000f
|
||||||
private val strNo = itemView.context.getString(R.string.btn_no)
|
private val strNo = itemView.context.getString(R.string.btn_no)
|
||||||
private val strYes = itemView.context.getString(R.string.btn_yes)
|
private val strYes = itemView.context.getString(R.string.btn_yes)
|
||||||
@@ -66,11 +65,22 @@ class TransAdapter(private val pass: SatPass) : RecyclerView.Adapter<TransAdapte
|
|||||||
private val formatLinkNull = itemView.context.getString(R.string.trans_no_link)
|
private val formatLinkNull = itemView.context.getString(R.string.trans_no_link)
|
||||||
private val isInverted = itemView.context.getString(R.string.trans_inverted)
|
private val isInverted = itemView.context.getString(R.string.trans_inverted)
|
||||||
|
|
||||||
fun bind(satTrans: SatTrans, satPass: SatPass) {
|
fun bind(satTrans: SatTrans) {
|
||||||
binding.description.text = satTrans.info
|
binding.description.text = satTrans.info
|
||||||
|
|
||||||
if (satPass.isDeepSpace) setRegularFreq(satTrans)
|
satTrans.downlink.let { downlink ->
|
||||||
else setDopplerFreq(satTrans, satPass.predictor)
|
if (downlink != null) {
|
||||||
|
val downlinkFreq = downlink / divider
|
||||||
|
binding.downlink.text = String.format(Locale.ENGLISH, formatLink, downlinkFreq)
|
||||||
|
} else binding.downlink.text = formatLinkNull
|
||||||
|
}
|
||||||
|
|
||||||
|
satTrans.uplink.let { uplink ->
|
||||||
|
if (uplink != null) {
|
||||||
|
val uplinkFreq = uplink / divider
|
||||||
|
binding.uplink.text = String.format(Locale.ENGLISH, formatLink, uplinkFreq)
|
||||||
|
} else binding.uplink.text = formatLinkNull
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
@@ -79,30 +89,6 @@ class TransAdapter(private val pass: SatPass) : RecyclerView.Adapter<TransAdapte
|
|||||||
else binding.isInverted.text = String.format(isInverted, strNo)
|
else binding.isInverted.text = String.format(isInverted, strNo)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setRegularFreq(satTrans: SatTrans) {
|
|
||||||
if (satTrans.downlink != null) {
|
|
||||||
val downFreq = satTrans.downlink / divider
|
|
||||||
binding.downlink.text = String.format(Locale.ENGLISH, formatLink, downFreq)
|
|
||||||
} else binding.downlink.text = formatLinkNull
|
|
||||||
|
|
||||||
if (satTrans.uplink != null) {
|
|
||||||
val upFreq = satTrans.uplink / divider
|
|
||||||
binding.uplink.text = String.format(Locale.ENGLISH, formatLink, upFreq)
|
|
||||||
} else binding.uplink.text = formatLinkNull
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setDopplerFreq(satTrans: SatTrans, predictor: PassPredictor) {
|
|
||||||
if (satTrans.downlink != null) {
|
|
||||||
val downlink = predictor.getDownlinkFreq(satTrans.downlink, dateNow) / divider
|
|
||||||
binding.downlink.text = String.format(Locale.ENGLISH, formatLink, downlink)
|
|
||||||
} else binding.downlink.text = formatLinkNull
|
|
||||||
|
|
||||||
if (satTrans.uplink != null) {
|
|
||||||
val uplink = predictor.getUplinkFreq(satTrans.uplink, dateNow) / divider
|
|
||||||
binding.uplink.text = String.format(Locale.ENGLISH, formatLink, uplink)
|
|
||||||
} else binding.uplink.text = formatLinkNull
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun from(parent: ViewGroup): TransHolder {
|
fun from(parent: ViewGroup): TransHolder {
|
||||||
val inflater = LayoutInflater.from(parent.context)
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
|
|||||||
+3
-1
@@ -3,4 +3,6 @@ Now updating recyclers views asyncronously
|
|||||||
Switched to concurrent satellite data update
|
Switched to concurrent satellite data update
|
||||||
Minor visual changes to map info
|
Minor visual changes to map info
|
||||||
Separated application screens logic
|
Separated application screens logic
|
||||||
Bug fixes, huge code cleanup
|
Bug fixes, huge code cleanup
|
||||||
|
Fixed recent InflatingException
|
||||||
|
Fixed transmitters doppler frequency update logic
|
||||||
@@ -4,4 +4,5 @@ Switched to concurrent satellite data update
|
|||||||
Minor visual changes to map info
|
Minor visual changes to map info
|
||||||
Separated application screens logic
|
Separated application screens logic
|
||||||
Bug fixes, huge code cleanup
|
Bug fixes, huge code cleanup
|
||||||
Fixed recent InflatingException
|
Fixed recent InflatingException
|
||||||
|
Fixed transmitters doppler frequency update logic
|
||||||
Reference in new issue
Block a user