mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Various fixes to PassesFragment's ui state handling
This commit is contained in:
1 parent
9fd0d5f2e2
commit
00549bbcba
4 files changed
+55
-42
No files matched your search
+47
-22
@@ -17,8 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.presentation.passesScreen
|
package com.rtbishop.look4sat.presentation.passesScreen
|
||||||
|
|
||||||
|
import android.animation.ValueAnimator
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.animation.LinearInterpolator
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
@@ -38,8 +40,9 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesClickListener {
|
class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesClickListener {
|
||||||
|
|
||||||
|
private val viewModel: PassesViewModel by viewModels()
|
||||||
private lateinit var binding: FragmentPassesBinding
|
private lateinit var binding: FragmentPassesBinding
|
||||||
private val passesViewModel: PassesViewModel by viewModels()
|
private lateinit var refreshAnimator: ValueAnimator
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@@ -49,7 +52,7 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
|
|||||||
|
|
||||||
private fun setupComponents() {
|
private fun setupComponents() {
|
||||||
val context = requireContext()
|
val context = requireContext()
|
||||||
val adapter = PassesAdapter(passesViewModel.shouldUseUTC(), this)
|
val adapter = PassesAdapter(viewModel.shouldUseUTC(), this)
|
||||||
val layoutManager = LinearLayoutManager(context)
|
val layoutManager = LinearLayoutManager(context)
|
||||||
val itemDecoration = DividerItemDecoration(context, layoutManager.orientation)
|
val itemDecoration = DividerItemDecoration(context, layoutManager.orientation)
|
||||||
binding.run {
|
binding.run {
|
||||||
@@ -72,18 +75,34 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
|
|||||||
passesFab.setOnClickListener { navigateToEntries() }
|
passesFab.setOnClickListener { navigateToEntries() }
|
||||||
passesSettingsBtn.setOnClickListener { navigateToSettings() }
|
passesSettingsBtn.setOnClickListener { navigateToSettings() }
|
||||||
}
|
}
|
||||||
passesViewModel.passes.observe(viewLifecycleOwner) { passesResult ->
|
setupObservers(adapter)
|
||||||
|
setupAnimator()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupObservers(adapter: PassesAdapter) {
|
||||||
|
viewModel.passes.observe(viewLifecycleOwner) { passesResult ->
|
||||||
handleNewPasses(passesResult, adapter)
|
handleNewPasses(passesResult, adapter)
|
||||||
}
|
}
|
||||||
passesViewModel.entries.observe(viewLifecycleOwner) { number ->
|
viewModel.entries.observe(viewLifecycleOwner) { number ->
|
||||||
handleEntriesNumber(number)
|
handleEntriesNumber(number)
|
||||||
}
|
}
|
||||||
getNavResult<Pair<Int, Double>>(R.id.nav_passes, "prefs") { prefs ->
|
getNavResult<Pair<Int, Double>>(R.id.nav_passes, "prefs") { prefs ->
|
||||||
passesViewModel.saveCalculationPrefs(prefs.first, prefs.second)
|
viewModel.forceCalculation(prefs.first, prefs.second)
|
||||||
passesViewModel.forceCalculation(prefs.first, prefs.second)
|
|
||||||
}
|
}
|
||||||
getNavResult<List<Int>>(R.id.nav_passes, "selection") { selection ->
|
getNavResult<List<Int>>(R.id.nav_passes, "selection") { selection ->
|
||||||
passesViewModel.saveSelectionAndRecalc(selection)
|
viewModel.saveSelectionAndRecalc(selection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupAnimator() {
|
||||||
|
refreshAnimator = ValueAnimator.ofFloat(0f, -360f).apply {
|
||||||
|
duration = 875
|
||||||
|
interpolator = LinearInterpolator()
|
||||||
|
repeatMode = ValueAnimator.RESTART
|
||||||
|
repeatCount = ValueAnimator.INFINITE
|
||||||
|
addUpdateListener { anim ->
|
||||||
|
binding.passesRefreshBtn.rotation = anim.animatedValue as Float
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,30 +117,36 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
|
|||||||
when (state) {
|
when (state) {
|
||||||
is DataState.Success -> {
|
is DataState.Success -> {
|
||||||
adapter.submitList(state.data)
|
adapter.submitList(state.data)
|
||||||
binding.apply {
|
tickMainTimer(state.data)
|
||||||
passesRecycler.visibility = View.VISIBLE
|
if (state.data.isNotEmpty()) { // show new passes list
|
||||||
passesErrorMsg.visibility = View.INVISIBLE
|
binding.run {
|
||||||
|
passesRecycler.visibility = View.VISIBLE
|
||||||
|
passesErrorMsg.visibility = View.INVISIBLE
|
||||||
|
binding.passesRefreshBtn.isEnabled = true
|
||||||
|
refreshAnimator.cancel()
|
||||||
|
}
|
||||||
|
} else { // show no passes message
|
||||||
|
binding.run {
|
||||||
|
passesRecycler.visibility = View.INVISIBLE
|
||||||
|
passesErrorMsg.visibility = View.VISIBLE
|
||||||
|
binding.passesRefreshBtn.isEnabled = true
|
||||||
|
refreshAnimator.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tickMainTimer(state.data, binding)
|
|
||||||
}
|
}
|
||||||
is DataState.Loading -> {
|
is DataState.Loading -> {
|
||||||
binding.apply {
|
binding.run {
|
||||||
|
refreshAnimator.start()
|
||||||
|
passesRefreshBtn.isEnabled = false
|
||||||
passesTimer.text = 0L.toTimerString()
|
passesTimer.text = 0L.toTimerString()
|
||||||
passesRecycler.visibility = View.INVISIBLE
|
|
||||||
passesErrorMsg.visibility = View.INVISIBLE
|
passesErrorMsg.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {}
|
||||||
binding.apply {
|
|
||||||
passesTimer.text = 0L.toTimerString()
|
|
||||||
passesRecycler.visibility = View.INVISIBLE
|
|
||||||
passesErrorMsg.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tickMainTimer(passes: List<SatPass>, binding: FragmentPassesBinding) {
|
private fun tickMainTimer(passes: List<SatPass>) {
|
||||||
if (passes.isNotEmpty()) {
|
if (passes.isNotEmpty()) {
|
||||||
val timeNow = System.currentTimeMillis()
|
val timeNow = System.currentTimeMillis()
|
||||||
try {
|
try {
|
||||||
@@ -139,7 +164,7 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshPasses() {
|
private fun refreshPasses() {
|
||||||
passesViewModel.forceCalculation()
|
viewModel.forceCalculation()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateToMap() {
|
private fun navigateToMap() {
|
||||||
|
|||||||
+5
-10
@@ -35,7 +35,7 @@ class PassesViewModel @Inject constructor(
|
|||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private var passesProcessing: Job? = null
|
private var passesProcessing: Job? = null
|
||||||
private val _passes = MutableLiveData<DataState<List<SatPass>>>()
|
private val _passes = MutableLiveData<DataState<List<SatPass>>>(DataState.Loading)
|
||||||
val passes: LiveData<DataState<List<SatPass>>> = _passes
|
val passes: LiveData<DataState<List<SatPass>>> = _passes
|
||||||
val entries: LiveData<Int> = repository.getEntriesNumber().asLiveData()
|
val entries: LiveData<Int> = repository.getEntriesNumber().asLiveData()
|
||||||
|
|
||||||
@@ -55,6 +55,8 @@ class PassesViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun shouldUseUTC() = settings.getUseUTC()
|
||||||
|
|
||||||
fun saveSelectionAndRecalc(selection: List<Int>) {
|
fun saveSelectionAndRecalc(selection: List<Int>) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
repository.setEntriesSelection(selection)
|
repository.setEntriesSelection(selection)
|
||||||
@@ -70,18 +72,11 @@ class PassesViewModel @Inject constructor(
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_passes.postValue(DataState.Loading)
|
_passes.postValue(DataState.Loading)
|
||||||
passesProcessing?.cancelAndJoin()
|
passesProcessing?.cancelAndJoin()
|
||||||
|
settings.setHoursAhead(hoursAhead)
|
||||||
|
settings.setMinElevation(minElevation)
|
||||||
val satellites = repository.getSelectedEntries()
|
val satellites = repository.getSelectedEntries()
|
||||||
val stationPos = settings.loadStationPosition()
|
val stationPos = settings.loadStationPosition()
|
||||||
predictor.forceCalculation(satellites, stationPos, timeRef, hoursAhead, minElevation)
|
predictor.forceCalculation(satellites, stationPos, timeRef, hoursAhead, minElevation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shouldUseUTC(): Boolean {
|
|
||||||
return settings.getUseUTC()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun saveCalculationPrefs(hoursAhead: Int, minElevation: Double) {
|
|
||||||
settings.setHoursAhead(hoursAhead)
|
|
||||||
settings.setMinElevation(minElevation)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -44,19 +44,13 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/passes_progress"
|
|
||||||
android:visibility="invisible"
|
|
||||||
style="@style/RecyclerProgress" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/passes_error_msg"
|
android:id="@+id/passes_error_msg"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:text="@string/passes_error"
|
android:text="@string/passes_error"
|
||||||
android:textSize="@dimen/text_size_large"
|
android:textSize="@dimen/text_size_large" />
|
||||||
android:visibility="invisible" />
|
|
||||||
|
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
|||||||
@@ -62,8 +62,7 @@ class Predictor(private val predictorDispatcher: CoroutineDispatcher) {
|
|||||||
|
|
||||||
suspend fun processPasses(passList: List<SatPass>, time: Long): List<SatPass> {
|
suspend fun processPasses(passList: List<SatPass>, time: Long): List<SatPass> {
|
||||||
return withContext(predictorDispatcher) {
|
return withContext(predictorDispatcher) {
|
||||||
val copiedList = passList.map { it.copy() }
|
passList.forEach { pass ->
|
||||||
copiedList.forEach { pass ->
|
|
||||||
if (!pass.isDeepSpace) {
|
if (!pass.isDeepSpace) {
|
||||||
val timeStart = pass.aosTime
|
val timeStart = pass.aosTime
|
||||||
if (time > timeStart) {
|
if (time > timeStart) {
|
||||||
@@ -73,7 +72,7 @@ class Predictor(private val predictorDispatcher: CoroutineDispatcher) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
copiedList.filter { it.progress < 100 }.map { it.copy() }
|
passList.filter { pass -> pass.progress < 100 }.map { it.copy() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user