Fixed transmitters doppler frequency update logic

This commit is contained in:
Arty Bishop committed 2021-04-05 19:32:07 +01:00
1 parent 555c2fe626
commit db710c55c4
7 files changed
+105 -87

No files matched your search

+2 -2
View File
@@ -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")
if (list.isNotEmpty()) { viewModel.getPass(catNum, aosTime).observe(viewLifecycleOwner) { pass ->
transmitterAdapter.setData(list) polarView = PolarView(requireContext()).apply { setPass(pass) }
binding.recycler.apply { binding.frame.addView(polarView)
setHasFixedSize(true) observeTransmitters(pass, transAdapter, binding)
adapter = transmitterAdapter
isVerticalScrollBarEnabled = false
layoutManager = LinearLayoutManager(context)
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
addItemDecoration(RecyclerDivider(R.drawable.rec_divider_dark))
visibility = View.VISIBLE
} }
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()) {
transAdapter.submitList(list)
binding.recycler.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 {
fun setData(list: List<SatTrans>) { return oldItem.uuid == newItem.uuid
transmittersList = list
notifyDataSetChanged()
} }
fun tickTransmitters() { override fun areContentsTheSame(oldItem: SatTrans, newItem: SatTrans): Boolean {
if (!pass.isDeepSpace) { return oldItem.downlink == newItem.downlink
notifyDataSetChanged()
} }
} }
private val differ = AsyncListDiffer(this, diffCallback)
fun submitList(transmitters: List<SatTrans>) {
differ.submitList(transmitters)
}
override fun getItemCount(): Int { override fun getItemCount() = differ.currentList.size
return transmittersList.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)
@@ -4,3 +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 transmitters doppler frequency update logic
@@ -5,3 +5,4 @@ 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