mirror of
https://github.com/rt-bishop/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Added coroutine exception handler to EntriesViewModel.kt
This commit is contained in:
1 parent
b6d019ace7
commit
6fa63fdcff
6 files changed
+47
-44
No files matched your search
+5
-4
@@ -17,8 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.framework.model
|
package com.rtbishop.look4sat.framework.model
|
||||||
|
|
||||||
sealed class Result<out T : Any> {
|
sealed class DataState<out T> {
|
||||||
data class Success<out T : Any>(val data: T) : Result<T>()
|
data class Success<out T>(val data: T) : DataState<T>()
|
||||||
data class Error(val exception: Throwable) : Result<Nothing>()
|
data class Error(val error: Throwable) : DataState<Nothing>()
|
||||||
object InProgress : Result<Nothing>()
|
object Empty : DataState<Nothing>()
|
||||||
|
object Loading : DataState<Nothing>()
|
||||||
}
|
}
|
||||||
+7
-7
@@ -29,7 +29,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.data.SatItem
|
import com.rtbishop.look4sat.data.SatItem
|
||||||
import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
|
import com.rtbishop.look4sat.databinding.FragmentEntriesBinding
|
||||||
import com.rtbishop.look4sat.framework.model.Result
|
import com.rtbishop.look4sat.framework.model.DataState
|
||||||
import com.rtbishop.look4sat.utility.RecyclerDivider
|
import com.rtbishop.look4sat.utility.RecyclerDivider
|
||||||
import com.rtbishop.look4sat.utility.getNavResult
|
import com.rtbishop.look4sat.utility.getNavResult
|
||||||
import com.rtbishop.look4sat.utility.navigateSafe
|
import com.rtbishop.look4sat.utility.navigateSafe
|
||||||
@@ -79,21 +79,21 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSatData(
|
private fun handleSatData(
|
||||||
result: Result<List<SatItem>>,
|
dataState: DataState<List<SatItem>>,
|
||||||
binding: FragmentEntriesBinding,
|
binding: FragmentEntriesBinding,
|
||||||
entriesAdapter: EntriesAdapter
|
entriesAdapter: EntriesAdapter
|
||||||
) {
|
) {
|
||||||
when (result) {
|
when (dataState) {
|
||||||
is Result.Success -> {
|
is DataState.Success -> {
|
||||||
entriesAdapter.submitList(result.data)
|
entriesAdapter.submitList(dataState.data)
|
||||||
binding.entriesProgress.visibility = View.INVISIBLE
|
binding.entriesProgress.visibility = View.INVISIBLE
|
||||||
binding.entriesRecycler.visibility = View.VISIBLE
|
binding.entriesRecycler.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
is Result.InProgress -> {
|
is DataState.Loading -> {
|
||||||
binding.entriesProgress.visibility = View.VISIBLE
|
binding.entriesProgress.visibility = View.VISIBLE
|
||||||
binding.entriesRecycler.visibility = View.INVISIBLE
|
binding.entriesRecycler.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
is Result.Error -> {
|
is DataState.Error -> {
|
||||||
binding.entriesProgress.visibility = View.INVISIBLE
|
binding.entriesProgress.visibility = View.INVISIBLE
|
||||||
binding.entriesRecycler.visibility = View.VISIBLE
|
binding.entriesRecycler.visibility = View.VISIBLE
|
||||||
requireView().showSnack(getString(R.string.entries_update_error))
|
requireView().showSnack(getString(R.string.entries_update_error))
|
||||||
|
|||||||
+18
-16
@@ -24,10 +24,12 @@ import androidx.lifecycle.*
|
|||||||
import com.rtbishop.look4sat.data.Preferences
|
import com.rtbishop.look4sat.data.Preferences
|
||||||
import com.rtbishop.look4sat.data.SatelliteRepo
|
import com.rtbishop.look4sat.data.SatelliteRepo
|
||||||
import com.rtbishop.look4sat.data.SatItem
|
import com.rtbishop.look4sat.data.SatItem
|
||||||
import com.rtbishop.look4sat.framework.model.Result
|
import com.rtbishop.look4sat.framework.model.DataState
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -38,46 +40,46 @@ class EntriesViewModel @Inject constructor(
|
|||||||
private val satelliteRepo: SatelliteRepo,
|
private val satelliteRepo: SatelliteRepo,
|
||||||
) : ViewModel(), EntriesAdapter.EntriesClickListener, SearchView.OnQueryTextListener {
|
) : ViewModel(), EntriesAdapter.EntriesClickListener, SearchView.OnQueryTextListener {
|
||||||
|
|
||||||
|
private val coroutineHandler = CoroutineExceptionHandler { _, throwable ->
|
||||||
|
Timber.d(throwable)
|
||||||
|
_satData.value = DataState.Error(throwable)
|
||||||
|
}
|
||||||
private val transModes = MutableLiveData(satelliteRepo.loadSelectedModes())
|
private val transModes = MutableLiveData(satelliteRepo.loadSelectedModes())
|
||||||
private val currentQuery = MutableLiveData(String())
|
private val currentQuery = MutableLiveData(String())
|
||||||
private val itemsWithModes = transModes.switchMap { modes ->
|
private val itemsWithModes = transModes.switchMap { modes ->
|
||||||
liveData { satelliteRepo.getSatItems().collect { emit(filterByModes(it, modes)) } }
|
liveData { satelliteRepo.getSatItems().collect { emit(filterByModes(it, modes)) } }
|
||||||
}
|
}
|
||||||
private val itemsWithQuery = currentQuery.switchMap { query ->
|
private val itemsWithQuery = currentQuery.switchMap { query ->
|
||||||
itemsWithModes.map { items -> Result.Success(filterByQuery(items, query)) }
|
itemsWithModes.map { items -> DataState.Success(filterByQuery(items, query)) }
|
||||||
}
|
}
|
||||||
private val _satData = MediatorLiveData<Result<List<SatItem>>>().apply {
|
private val _satData = MediatorLiveData<DataState<List<SatItem>>>().apply {
|
||||||
addSource(itemsWithQuery) { value -> this.value = value }
|
addSource(itemsWithQuery) { value -> this.value = value }
|
||||||
}
|
}
|
||||||
private var shouldSelectAll = true
|
private var shouldSelectAll = true
|
||||||
val satData: LiveData<Result<List<SatItem>>> = _satData
|
val satData: LiveData<DataState<List<SatItem>>> = _satData
|
||||||
|
|
||||||
fun updateEntriesFromFile(uri: Uri) {
|
fun updateEntriesFromFile(uri: Uri) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch(coroutineHandler) {
|
||||||
_satData.value = Result.InProgress
|
_satData.value = DataState.Loading
|
||||||
runCatching {
|
runCatching {
|
||||||
resolver.openInputStream(uri)?.use { stream ->
|
resolver.openInputStream(uri)?.use { stream ->
|
||||||
satelliteRepo.updateEntriesFromFile(stream)
|
satelliteRepo.updateEntriesFromFile(stream)
|
||||||
}
|
}
|
||||||
}.onFailure { _satData.value = Result.Error(it) }
|
}.onFailure { _satData.value = DataState.Error(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateEntriesFromWeb(sources: List<String>) {
|
fun updateEntriesFromWeb(sources: List<String>) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch(coroutineHandler) {
|
||||||
_satData.value = Result.InProgress
|
_satData.value = DataState.Loading
|
||||||
try {
|
preferences.saveTleSources(sources)
|
||||||
preferences.saveTleSources(sources)
|
satelliteRepo.updateEntriesFromWeb(sources)
|
||||||
satelliteRepo.updateEntriesFromWeb(sources)
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
_satData.value = Result.Error(exception)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun selectCurrentItems() {
|
fun selectCurrentItems() {
|
||||||
val currentValue = _satData.value
|
val currentValue = _satData.value
|
||||||
if (currentValue is Result.Success) {
|
if (currentValue is DataState.Success) {
|
||||||
updateSelection(currentValue.data.map { it.catNum }, shouldSelectAll)
|
updateSelection(currentValue.data.map { it.catNum }, shouldSelectAll)
|
||||||
shouldSelectAll = shouldSelectAll.not()
|
shouldSelectAll = shouldSelectAll.not()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import androidx.recyclerview.widget.SimpleItemAnimator
|
|||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.databinding.FragmentPassesBinding
|
import com.rtbishop.look4sat.databinding.FragmentPassesBinding
|
||||||
import com.rtbishop.look4sat.domain.SatPass
|
import com.rtbishop.look4sat.domain.SatPass
|
||||||
import com.rtbishop.look4sat.framework.model.Result
|
import com.rtbishop.look4sat.framework.model.DataState
|
||||||
import com.rtbishop.look4sat.utility.RecyclerDivider
|
import com.rtbishop.look4sat.utility.RecyclerDivider
|
||||||
import com.rtbishop.look4sat.utility.navigateSafe
|
import com.rtbishop.look4sat.utility.navigateSafe
|
||||||
import com.rtbishop.look4sat.utility.toTimerString
|
import com.rtbishop.look4sat.utility.toTimerString
|
||||||
@@ -73,21 +73,21 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleNewPasses(
|
private fun handleNewPasses(
|
||||||
result: Result<List<SatPass>>,
|
dataState: DataState<List<SatPass>>,
|
||||||
passesAdapter: PassesAdapter,
|
passesAdapter: PassesAdapter,
|
||||||
binding: FragmentPassesBinding
|
binding: FragmentPassesBinding
|
||||||
) {
|
) {
|
||||||
when (result) {
|
when (dataState) {
|
||||||
is Result.Success -> {
|
is DataState.Success -> {
|
||||||
passesAdapter.submitList(result.data)
|
passesAdapter.submitList(dataState.data)
|
||||||
binding.apply {
|
binding.apply {
|
||||||
passesError.visibility = View.INVISIBLE
|
passesError.visibility = View.INVISIBLE
|
||||||
passesProgress.visibility = View.INVISIBLE
|
passesProgress.visibility = View.INVISIBLE
|
||||||
passesRecycler.visibility = View.VISIBLE
|
passesRecycler.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
tickMainTimer(result.data, binding)
|
tickMainTimer(dataState.data, binding)
|
||||||
}
|
}
|
||||||
is Result.InProgress -> {
|
is DataState.Loading -> {
|
||||||
binding.apply {
|
binding.apply {
|
||||||
passesTimer.text = 0L.toTimerString()
|
passesTimer.text = 0L.toTimerString()
|
||||||
passesError.visibility = View.INVISIBLE
|
passesError.visibility = View.INVISIBLE
|
||||||
@@ -95,7 +95,7 @@ class PassesFragment : Fragment(R.layout.fragment_passes), PassesAdapter.PassesC
|
|||||||
passesProgress.visibility = View.VISIBLE
|
passesProgress.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Result.Error -> {
|
is DataState.Error -> {
|
||||||
binding.apply {
|
binding.apply {
|
||||||
passesTimer.text = 0L.toTimerString()
|
passesTimer.text = 0L.toTimerString()
|
||||||
passesProgress.visibility = View.INVISIBLE
|
passesProgress.visibility = View.INVISIBLE
|
||||||
|
|||||||
+7
-7
@@ -25,7 +25,7 @@ import com.rtbishop.look4sat.data.Preferences
|
|||||||
import com.rtbishop.look4sat.data.SatelliteRepo
|
import com.rtbishop.look4sat.data.SatelliteRepo
|
||||||
import com.rtbishop.look4sat.domain.Predictor
|
import com.rtbishop.look4sat.domain.Predictor
|
||||||
import com.rtbishop.look4sat.domain.SatPass
|
import com.rtbishop.look4sat.domain.SatPass
|
||||||
import com.rtbishop.look4sat.framework.model.Result
|
import com.rtbishop.look4sat.framework.model.DataState
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
@@ -39,16 +39,16 @@ class PassesViewModel @Inject constructor(
|
|||||||
private val preferences: Preferences
|
private val preferences: Preferences
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _passes = MutableLiveData<Result<List<SatPass>>>(Result.InProgress)
|
private val _passes = MutableLiveData<DataState<List<SatPass>>>(DataState.Loading)
|
||||||
private val _isFirstLaunchDone = MutableLiveData<Boolean>()
|
private val _isFirstLaunchDone = MutableLiveData<Boolean>()
|
||||||
private var passesProcessing: Job? = null
|
private var passesProcessing: Job? = null
|
||||||
val passes: LiveData<Result<List<SatPass>>> = _passes
|
val passes: LiveData<DataState<List<SatPass>>> = _passes
|
||||||
val isFirstLaunchDone: LiveData<Boolean> = _isFirstLaunchDone
|
val isFirstLaunchDone: LiveData<Boolean> = _isFirstLaunchDone
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (preferences.isSetupDone()) {
|
if (preferences.isSetupDone()) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_passes.postValue(Result.InProgress)
|
_passes.postValue(DataState.Loading)
|
||||||
val dateNow = Date()
|
val dateNow = Date()
|
||||||
val satellites = satelliteRepo.getSelectedSatellites()
|
val satellites = satelliteRepo.getSelectedSatellites()
|
||||||
val stationPos = preferences.loadStationPosition()
|
val stationPos = preferences.loadStationPosition()
|
||||||
@@ -70,7 +70,7 @@ class PassesViewModel @Inject constructor(
|
|||||||
fun triggerInitialSetup() {
|
fun triggerInitialSetup() {
|
||||||
preferences.updatePositionFromGPS()
|
preferences.updatePositionFromGPS()
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_passes.postValue(Result.InProgress)
|
_passes.postValue(DataState.Loading)
|
||||||
val defaultCatNums = listOf(43700, 25544, 25338, 28654, 33591, 40069, 27607, 24278)
|
val defaultCatNums = listOf(43700, 25544, 25338, 28654, 33591, 40069, 27607, 24278)
|
||||||
val dateNow = Date()
|
val dateNow = Date()
|
||||||
val satellites = satelliteRepo.getSelectedSatellites()
|
val satellites = satelliteRepo.getSelectedSatellites()
|
||||||
@@ -87,7 +87,7 @@ class PassesViewModel @Inject constructor(
|
|||||||
|
|
||||||
fun forceCalculation() {
|
fun forceCalculation() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_passes.postValue(Result.InProgress)
|
_passes.postValue(DataState.Loading)
|
||||||
passesProcessing?.cancelAndJoin()
|
passesProcessing?.cancelAndJoin()
|
||||||
val dateNow = Date()
|
val dateNow = Date()
|
||||||
val satellites = satelliteRepo.getSelectedSatellites()
|
val satellites = satelliteRepo.getSelectedSatellites()
|
||||||
@@ -117,7 +117,7 @@ class PassesViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentPasses = currentPasses.filter { it.progress < 100 }
|
currentPasses = currentPasses.filter { it.progress < 100 }
|
||||||
_passes.postValue(Result.Success(currentPasses.map { it.copy() }))
|
_passes.postValue(DataState.Success(currentPasses.map { it.copy() }))
|
||||||
delay(1000)
|
delay(1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -5,12 +5,12 @@ buildscript {
|
|||||||
coroutines_version = '1.5.2-native-mt'
|
coroutines_version = '1.5.2-native-mt'
|
||||||
material_version = '1.4.0'
|
material_version = '1.4.0'
|
||||||
splash_screen_version = '1.0.0-alpha01'
|
splash_screen_version = '1.0.0-alpha01'
|
||||||
constraint_layout_version = '2.1.0'
|
constraint_layout_version = '2.1.1'
|
||||||
lifecycle_version = '2.3.1'
|
lifecycle_version = '2.3.1'
|
||||||
navigation_version = '2.3.5'
|
navigation_version = '2.3.5'
|
||||||
preference_version = '1.1.1'
|
preference_version = '1.1.1'
|
||||||
room_version = '2.3.0'
|
room_version = '2.3.0'
|
||||||
hilt_version = '2.38.1'
|
hilt_version = '2.39'
|
||||||
retrofit_version = '2.9.0'
|
retrofit_version = '2.9.0'
|
||||||
osmdroid_version = '6.1.11'
|
osmdroid_version = '6.1.11'
|
||||||
timber_version = '5.0.1'
|
timber_version = '5.0.1'
|
||||||
|
|||||||
Reference in new issue
Block a user