mirror of
https://github.com/rt-bishop/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Enabled data update progress indicator
This commit is contained in:
1 parent
61cbc212b5
commit
9b38e2c63e
5 files changed
+95
-54
No files matched your search
@@ -37,6 +37,8 @@ import dagger.hilt.InstallIn
|
|||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@@ -46,7 +48,7 @@ object CoreModule {
|
|||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideSatelliteRepo(
|
fun provideSatelliteRepo(
|
||||||
settingsHandler: ISettingsHandler,
|
settings: ISettingsHandler,
|
||||||
@ApplicationContext context: Context,
|
@ApplicationContext context: Context,
|
||||||
@IoDispatcher ioDispatcher: CoroutineDispatcher,
|
@IoDispatcher ioDispatcher: CoroutineDispatcher,
|
||||||
@DefaultDispatcher defaultDispatcher: CoroutineDispatcher
|
@DefaultDispatcher defaultDispatcher: CoroutineDispatcher
|
||||||
@@ -57,7 +59,8 @@ object CoreModule {
|
|||||||
.fallbackToDestructiveMigration().build()
|
.fallbackToDestructiveMigration().build()
|
||||||
val localSource = LocalSource(db.entriesDao(), db.transmittersDao())
|
val localSource = LocalSource(db.entriesDao(), db.transmittersDao())
|
||||||
val remoteSource = RemoteSource(ioDispatcher)
|
val remoteSource = RemoteSource(ioDispatcher)
|
||||||
return DataRepository(dataParser, localSource, remoteSource, settingsHandler)
|
val repositoryScope = CoroutineScope(SupervisorJob())
|
||||||
|
return DataRepository(dataParser, settings, localSource, remoteSource, repositoryScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
+26
-4
@@ -56,7 +56,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
|
|||||||
}
|
}
|
||||||
private val contentContract = ActivityResultContracts.GetContent()
|
private val contentContract = ActivityResultContracts.GetContent()
|
||||||
private val contentRequest = registerForActivityResult(contentContract) { uri ->
|
private val contentRequest = registerForActivityResult(contentContract) { uri ->
|
||||||
viewModel.updateDataFromFile(uri)
|
uri?.let { viewModel.updateDataFromFile(uri) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
@@ -70,7 +70,10 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
|
|||||||
setupOtherCard(settingsBinding)
|
setupOtherCard(settingsBinding)
|
||||||
setupWarrantyCard(settingsBinding)
|
setupWarrantyCard(settingsBinding)
|
||||||
viewModel.stationPosition.asLiveData().observe(viewLifecycleOwner) { stationPos ->
|
viewModel.stationPosition.asLiveData().observe(viewLifecycleOwner) { stationPos ->
|
||||||
stationPos?.let { handleStationPosition(it, settingsBinding) }
|
stationPos?.let { handleStationPosition(stationPos, settingsBinding) }
|
||||||
|
}
|
||||||
|
viewModel.getUpdateState().asLiveData().observe(viewLifecycleOwner) { updateState ->
|
||||||
|
updateState?.let { handleSatState(updateState, settingsBinding) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,13 +174,13 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
|
|||||||
is DataState.Success -> {
|
is DataState.Success -> {
|
||||||
setPositionText(pos.data, binding)
|
setPositionText(pos.data, binding)
|
||||||
binding.prefsLocation.locationProgress.isIndeterminate = false
|
binding.prefsLocation.locationProgress.isIndeterminate = false
|
||||||
showToast(getString(R.string.pref_pos_success))
|
|
||||||
viewModel.setPositionHandled()
|
viewModel.setPositionHandled()
|
||||||
|
showToast(getString(R.string.pref_pos_success))
|
||||||
}
|
}
|
||||||
is DataState.Error -> {
|
is DataState.Error -> {
|
||||||
binding.prefsLocation.locationProgress.isIndeterminate = false
|
binding.prefsLocation.locationProgress.isIndeterminate = false
|
||||||
showToast(pos.message.toString())
|
|
||||||
viewModel.setPositionHandled()
|
viewModel.setPositionHandled()
|
||||||
|
showToast(pos.message.toString())
|
||||||
}
|
}
|
||||||
DataState.Loading -> {
|
DataState.Loading -> {
|
||||||
binding.prefsLocation.locationProgress.isIndeterminate = true
|
binding.prefsLocation.locationProgress.isIndeterminate = true
|
||||||
@@ -186,6 +189,25 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleSatState(state: DataState<Long>, binding: FragmentSettingsBinding) {
|
||||||
|
when (state) {
|
||||||
|
is DataState.Success -> {
|
||||||
|
binding.prefsData.updateProgress.isIndeterminate = false
|
||||||
|
viewModel.setUpdateHandled()
|
||||||
|
showToast("Data updated successfully")
|
||||||
|
}
|
||||||
|
is DataState.Error -> {
|
||||||
|
binding.prefsData.updateProgress.isIndeterminate = false
|
||||||
|
viewModel.setUpdateHandled()
|
||||||
|
showToast(state.message.toString())
|
||||||
|
}
|
||||||
|
is DataState.Loading -> {
|
||||||
|
binding.prefsData.updateProgress.isIndeterminate = true
|
||||||
|
}
|
||||||
|
is DataState.Handled -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun showToast(message: String) {
|
private fun showToast(message: String) {
|
||||||
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-24
@@ -10,7 +10,6 @@ import com.rtbishop.look4sat.domain.ILocationHandler
|
|||||||
import com.rtbishop.look4sat.domain.model.DataState
|
import com.rtbishop.look4sat.domain.model.DataState
|
||||||
import com.rtbishop.look4sat.domain.predict.GeoPos
|
import com.rtbishop.look4sat.domain.predict.GeoPos
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -21,14 +20,10 @@ class SettingsViewModel @Inject constructor(
|
|||||||
private val settings: ISettingsHandler,
|
private val settings: ISettingsHandler,
|
||||||
private val repository: IDataRepository,
|
private val repository: IDataRepository,
|
||||||
private val locationHandler: ILocationHandler
|
private val locationHandler: ILocationHandler
|
||||||
) : ViewModel(), ILocationHandler {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val exceptionHandler = CoroutineExceptionHandler { _, exception ->
|
|
||||||
println("Handled $exception in CoroutineExceptionHandler")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateDataFromFile(uri: Uri) {
|
fun updateDataFromFile(uri: Uri) {
|
||||||
viewModelScope.launch(exceptionHandler) {
|
viewModelScope.launch {
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
resolver.openInputStream(uri)?.use { fileUri ->
|
resolver.openInputStream(uri)?.use { fileUri ->
|
||||||
repository.updateDataFromFile(fileUri)
|
repository.updateDataFromFile(fileUri)
|
||||||
@@ -37,10 +32,8 @@ class SettingsViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun updateDataFromWeb(sources: List<String>) {
|
fun updateDataFromWeb(sources: List<String>) {
|
||||||
viewModelScope.launch(exceptionHandler) {
|
|
||||||
repository.updateDataFromWeb(sources)
|
repository.updateDataFromWeb(sources)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun getUseUTC(): Boolean = settings.getUseUTC()
|
fun getUseUTC(): Boolean = settings.getUseUTC()
|
||||||
|
|
||||||
@@ -66,21 +59,19 @@ class SettingsViewModel @Inject constructor(
|
|||||||
|
|
||||||
fun setRotatorPort(value: String) = settings.setRotatorPort(value)
|
fun setRotatorPort(value: String) = settings.setRotatorPort(value)
|
||||||
|
|
||||||
override val stationPosition: SharedFlow<DataState<GeoPos>> = locationHandler.stationPosition
|
fun getUpdateState() = repository.dataUpdateState
|
||||||
|
|
||||||
override fun getStationPosition(): GeoPos = locationHandler.getStationPosition()
|
fun setUpdateHandled() = repository.setDataUpdateHandled()
|
||||||
|
|
||||||
override fun setStationPosition(latitude: Double, longitude: Double) {
|
val stationPosition: SharedFlow<DataState<GeoPos>> = locationHandler.stationPosition
|
||||||
locationHandler.setStationPosition(latitude, longitude)
|
|
||||||
}
|
fun getStationPosition(): GeoPos = locationHandler.getStationPosition()
|
||||||
|
|
||||||
override fun setPositionFromGps() = locationHandler.setPositionFromGps()
|
fun setPositionFromGps() = locationHandler.setPositionFromGps()
|
||||||
|
|
||||||
override fun setPositionFromNet() = locationHandler.setPositionFromNet()
|
fun setPositionFromNet() = locationHandler.setPositionFromNet()
|
||||||
|
|
||||||
override fun setPositionFromQth(qthString: String) {
|
fun setPositionFromQth(qthString: String) = locationHandler.setPositionFromQth(qthString)
|
||||||
locationHandler.setPositionFromQth(qthString)
|
|
||||||
}
|
fun setPositionHandled() = locationHandler.setPositionHandled()
|
||||||
|
|
||||||
override fun setPositionHandled() = locationHandler.setPositionHandled()
|
|
||||||
}
|
}
|
||||||
@@ -19,38 +19,51 @@ package com.rtbishop.look4sat.data
|
|||||||
|
|
||||||
import com.rtbishop.look4sat.domain.DataParser
|
import com.rtbishop.look4sat.domain.DataParser
|
||||||
import com.rtbishop.look4sat.domain.IDataRepository
|
import com.rtbishop.look4sat.domain.IDataRepository
|
||||||
|
import com.rtbishop.look4sat.domain.model.DataState
|
||||||
import com.rtbishop.look4sat.domain.model.SatEntry
|
import com.rtbishop.look4sat.domain.model.SatEntry
|
||||||
import kotlinx.coroutines.Deferred
|
import com.rtbishop.look4sat.domain.model.SatItem
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
class DataRepository(
|
class DataRepository(
|
||||||
private val dataParser: DataParser,
|
private val dataParser: DataParser,
|
||||||
|
private val settings: ISettingsHandler,
|
||||||
private val localSource: ILocalSource,
|
private val localSource: ILocalSource,
|
||||||
private val remoteSource: IRemoteSource,
|
private val remoteSource: IRemoteSource,
|
||||||
private val settingsHandler: ISettingsHandler
|
private val repositoryScope: CoroutineScope
|
||||||
) : IDataRepository {
|
) : IDataRepository {
|
||||||
|
|
||||||
override fun getSatelliteItems() = localSource.getSatelliteItems()
|
private val exceptionHandler = CoroutineExceptionHandler { _, exception ->
|
||||||
|
println("DataRepository: handled $exception")
|
||||||
|
_updateState.value = DataState.Error(exception.message)
|
||||||
|
}
|
||||||
|
private val _updateState = MutableStateFlow<DataState<Long>>(DataState.Handled)
|
||||||
|
override val dataUpdateState: StateFlow<DataState<Long>> = _updateState
|
||||||
|
|
||||||
override suspend fun getSelectedSatellites() = localSource.getSelectedSatellites()
|
override fun setDataUpdateHandled() {
|
||||||
|
_updateState.value = DataState.Handled
|
||||||
override suspend fun getTransmitters(catnum: Int) = localSource.getTransmitters(catnum)
|
|
||||||
|
|
||||||
override suspend fun updateDataFromFile(stream: InputStream) {
|
|
||||||
localSource.updateEntries(importSatellites(stream))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun updateDataFromWeb(sources: List<String>) {
|
override fun updateDataFromFile(stream: InputStream) {
|
||||||
coroutineScope {
|
repositoryScope.launch(exceptionHandler) {
|
||||||
launch {
|
_updateState.value = DataState.Loading
|
||||||
settingsHandler.saveDataSources(sources)
|
val importedSatellites = importSatellites(stream)
|
||||||
|
localSource.updateEntries(importedSatellites)
|
||||||
|
_updateState.value = DataState.Success(0L)
|
||||||
}
|
}
|
||||||
launch {
|
}
|
||||||
|
|
||||||
|
override fun updateDataFromWeb(sources: List<String>) {
|
||||||
|
_updateState.value = DataState.Loading
|
||||||
|
repositoryScope.launch(exceptionHandler) {
|
||||||
|
settings.saveDataSources(sources)
|
||||||
|
}
|
||||||
|
repositoryScope.launch(exceptionHandler) {
|
||||||
val updateTimeMillis = measureTimeMillis {
|
val updateTimeMillis = measureTimeMillis {
|
||||||
val jobsMap = mutableMapOf<String, Deferred<InputStream?>>()
|
val jobsMap = mutableMapOf<String, Deferred<InputStream?>>()
|
||||||
val streamsMap = mutableMapOf<String, InputStream?>()
|
val streamsMap = mutableMapOf<String, InputStream?>()
|
||||||
@@ -76,15 +89,21 @@ class DataRepository(
|
|||||||
localSource.updateEntries(entries)
|
localSource.updateEntries(entries)
|
||||||
}
|
}
|
||||||
println("Update from web took $updateTimeMillis ms")
|
println("Update from web took $updateTimeMillis ms")
|
||||||
|
_updateState.value = DataState.Success(updateTimeMillis)
|
||||||
}
|
}
|
||||||
launch {
|
repositoryScope.launch(exceptionHandler) {
|
||||||
remoteSource.fetchFileStream(settingsHandler.transmittersSource)?.let { stream ->
|
remoteSource.fetchFileStream(settings.transmittersSource)?.let { stream ->
|
||||||
val transmitters = dataParser.parseJSONStream(stream)
|
val transmitters = dataParser.parseJSONStream(stream)
|
||||||
localSource.updateTransmitters(transmitters)
|
localSource.updateTransmitters(transmitters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
override fun getSatelliteItems(): Flow<List<SatItem>> = localSource.getSatelliteItems()
|
||||||
|
|
||||||
|
override suspend fun getSelectedSatellites() = localSource.getSelectedSatellites()
|
||||||
|
|
||||||
|
override suspend fun getTransmitters(catnum: Int) = localSource.getTransmitters(catnum)
|
||||||
|
|
||||||
override suspend fun updateSelection(catnums: List<Int>, isSelected: Boolean) {
|
override suspend fun updateSelection(catnums: List<Int>, isSelected: Boolean) {
|
||||||
localSource.updateEntriesSelection(catnums, isSelected)
|
localSource.updateEntriesSelection(catnums, isSelected)
|
||||||
|
|||||||
@@ -17,23 +17,29 @@
|
|||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.domain
|
package com.rtbishop.look4sat.domain
|
||||||
|
|
||||||
|
import com.rtbishop.look4sat.domain.model.DataState
|
||||||
import com.rtbishop.look4sat.domain.model.SatItem
|
import com.rtbishop.look4sat.domain.model.SatItem
|
||||||
import com.rtbishop.look4sat.domain.model.Transmitter
|
import com.rtbishop.look4sat.domain.model.Transmitter
|
||||||
import com.rtbishop.look4sat.domain.predict.Satellite
|
import com.rtbishop.look4sat.domain.predict.Satellite
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
interface IDataRepository {
|
interface IDataRepository {
|
||||||
|
|
||||||
|
val dataUpdateState: StateFlow<DataState<Long>>
|
||||||
|
|
||||||
|
fun setDataUpdateHandled()
|
||||||
|
|
||||||
|
fun updateDataFromFile(stream: InputStream)
|
||||||
|
|
||||||
|
fun updateDataFromWeb(sources: List<String>)
|
||||||
|
|
||||||
fun getSatelliteItems(): Flow<List<SatItem>>
|
fun getSatelliteItems(): Flow<List<SatItem>>
|
||||||
|
|
||||||
suspend fun getSelectedSatellites(): List<Satellite>
|
suspend fun getSelectedSatellites(): List<Satellite>
|
||||||
|
|
||||||
suspend fun getTransmitters(catnum: Int): List<Transmitter>
|
suspend fun getTransmitters(catnum: Int): List<Transmitter>
|
||||||
|
|
||||||
suspend fun updateDataFromFile(stream: InputStream)
|
|
||||||
|
|
||||||
suspend fun updateDataFromWeb(sources: List<String>)
|
|
||||||
|
|
||||||
suspend fun updateSelection(catnums: List<Int>, isSelected: Boolean = true)
|
suspend fun updateSelection(catnums: List<Int>, isSelected: Boolean = true)
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user