Swapped SingleLiveEvent for MutableStateFlow

This commit is contained in:
Arty Bishop committed 2021-03-11 21:34:57 +00:00
1 parent d493e3e87b
commit 8134db90d6
7 files changed
+49 -73

No files matched your search

@@ -1,34 +0,0 @@
/*
* Look4Sat. Amateur radio satellite tracker and pass predictor.
* Copyright (C) 2019-2021 Arty Bishop (bishop.arty@gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.rtbishop.look4sat.data
class Event<out T>(private val content: T) {
private var hasBeenHandled = false
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
fun peekContent(): T = content
}
@@ -20,13 +20,18 @@ package com.rtbishop.look4sat.ui
import android.net.Uri
import androidx.lifecycle.*
import com.github.amsacode.predict4java.Satellite
import com.rtbishop.look4sat.data.*
import com.rtbishop.look4sat.data.Result
import com.rtbishop.look4sat.data.SatItem
import com.rtbishop.look4sat.data.SatPass
import com.rtbishop.look4sat.data.TleSource
import com.rtbishop.look4sat.repository.PrefsRepo
import com.rtbishop.look4sat.repository.SatelliteRepo
import com.rtbishop.look4sat.utility.getPredictor
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import java.util.*
import javax.inject.Inject
@@ -37,18 +42,21 @@ class SharedViewModel @Inject constructor(
private val satelliteRepo: SatelliteRepo,
) : ViewModel() {
private val _passes = MutableLiveData<Result<MutableList<SatPass>>>()
private val _appEvent = MutableLiveData<Event<Int>>()
private val _passes = MutableStateFlow<Result<MutableList<SatPass>>>(Result.InProgress)
val passes: LiveData<Result<MutableList<SatPass>>> = _passes.asLiveData()
private val _satData = MutableStateFlow<Result<List<SatItem>>>(Result.InProgress)
val satData: LiveData<Result<List<SatItem>>> = _satData.asLiveData()
init {
if (prefsRepo.isFirstLaunch()) {
updateDefaultSourcesAndEntries()
prefsRepo.setFirstLaunchDone()
}
loadDataFromDb()
calculatePasses()
}
fun getAppEvent(): LiveData<Event<Int>> = _appEvent
fun getAppTimer() = liveData {
while (true) {
emit(System.currentTimeMillis())
@@ -57,10 +65,7 @@ class SharedViewModel @Inject constructor(
}
fun getSources() = prefsRepo.loadTleSources()
fun getSatItems() = satelliteRepo.getSatItems().asLiveData()
fun getPasses(): LiveData<Result<MutableList<SatPass>>> = _passes
fun getTransmittersForSat(satId: Int) =
satelliteRepo.getTransmittersForSat(satId).asLiveData()
fun getTransmittersForSat(satId: Int) = satelliteRepo.getTransmittersForSat(satId).asLiveData()
fun calculatePasses(dateNow: Date = Date(System.currentTimeMillis())) {
_passes.value = Result.InProgress
@@ -70,30 +75,30 @@ class SharedViewModel @Inject constructor(
passes.addAll(getPasses(satellite, dateNow))
}
val filteredPasses = sortList(passes, dateNow)
_passes.postValue(Result.Success(filteredPasses))
_passes.value = Result.Success(filteredPasses)
}
}
fun updateEntriesFromFile(uri: Uri) {
postAppEvent(Event(0))
_satData.value = Result.InProgress
viewModelScope.launch {
try {
satelliteRepo.updateEntriesFromFile(uri)
} catch (exception: Exception) {
postAppEvent(Event(1))
_satData.value = Result.Error(exception)
}
}
}
fun updateEntriesFromSources(sources: List<TleSource>) {
postAppEvent(Event(0))
fun updateEntriesFromSources(sources: List<TleSource> = prefsRepo.loadTleSources()) {
_satData.value = Result.InProgress
viewModelScope.launch {
try {
prefsRepo.saveTleSources(sources)
satelliteRepo.updateEntriesFromWeb(sources)
satelliteRepo.updateTransmitters()
} catch (exception: Exception) {
postAppEvent(Event(1))
_satData.value = Result.Error(exception)
}
}
}
@@ -107,10 +112,6 @@ class SharedViewModel @Inject constructor(
}
}
private fun postAppEvent(event: Event<Int>) {
_appEvent.value = event
}
private fun getPasses(satellite: Satellite, dateNow: Date): MutableList<SatPass> {
val predictor = satellite.getPredictor(prefsRepo.getStationPosition())
val passes = predictor.getPasses(dateNow, prefsRepo.getHoursAhead(), true)
@@ -130,8 +131,19 @@ class SharedViewModel @Inject constructor(
passes.sortBy { it.pass.startTime }
return passes
}
private fun loadDataFromDb() {
_satData.value = Result.InProgress
viewModelScope.launch {
satelliteRepo.getSatItems().collect { satItems: List<SatItem> ->
if (satItems.isNotEmpty()) {
_satData.value = Result.Success(satItems)
}
}
}
}
private fun updateDefaultSourcesAndEntries() {
updateEntriesFromSources(prefsRepo.loadTleSources())
updateEntriesFromSources()
}
}
@@ -27,6 +27,7 @@ import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar
import com.rtbishop.look4sat.R
import com.rtbishop.look4sat.data.Result
import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
import com.rtbishop.look4sat.ui.SharedViewModel
import com.rtbishop.look4sat.utility.RecyclerDivider
@@ -70,19 +71,16 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
}
private fun setupObservers() {
setLoading()
viewModel.getSatItems().observe(viewLifecycleOwner, { satItems ->
if (satItems.isNullOrEmpty()) {
setError()
} else {
entriesAdapter?.setItems(satItems)
setLoaded()
}
})
viewModel.getAppEvent().observe(viewLifecycleOwner, { event ->
event.getContentIfNotHandled()?.let { content ->
if (content == 0) setLoading()
else if (content == 1) {
viewModel.satData.observe(viewLifecycleOwner, { result ->
when (result) {
is Result.Success -> {
entriesAdapter?.setItems(result.data)
setLoaded()
}
is Result.InProgress -> {
setLoading()
}
is Result.Error -> {
val errorMsg = getString(R.string.entries_update_error)
Snackbar.make(requireView(), errorMsg, Snackbar.LENGTH_SHORT).show()
entriesAdapter?.let { adapter ->
@@ -83,7 +83,7 @@ class MapFragment : Fragment(R.layout.fragment_map) {
private fun setupObservers() {
mapViewModel.getGSP().observe(viewLifecycleOwner, { setupPosOverlay(it) })
sharedViewModel.getPasses().observe(viewLifecycleOwner, {
sharedViewModel.passes.observe(viewLifecycleOwner, {
if (it is Result.Success && it.data.isNotEmpty()) {
mapViewModel.setPasses(it.data)
binding.fabPrev.setOnClickListener { mapViewModel.scrollSelection(true) }
@@ -54,7 +54,7 @@ class PassesFragment : Fragment(R.layout.fragment_passes) {
}
private fun setupObservers() {
viewModel.getPasses().observe(viewLifecycleOwner, { result ->
viewModel.passes.observe(viewLifecycleOwner, { result ->
if (result is Result.Success) {
if (result.data.isEmpty()) {
binding?.apply {
@@ -97,7 +97,7 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
}
private fun observePasses() {
viewModel.getPasses().observe(viewLifecycleOwner, { result ->
viewModel.passes.observe(viewLifecycleOwner, { result ->
if (result is Result.Success) {
satPass = result.data[requireArguments().getInt("index")]
polarView = PolarView(requireContext()).apply { setPass(satPass) }
+1 -1
View File
@@ -5,7 +5,7 @@ buildscript {
material_version = '1.3.0'
constraint_layout_version = '2.0.4'
lifecycle_version = '2.3.0'
navigation_version = '2.3.3'
navigation_version = '2.3.4'
preference_version = '1.1.1'
room_version = '2.2.6'
hilt_version = '2.33-beta'