Moved sat data update back to SharedViewModel.kt
This commit is contained in:
1 parent
d013afbf50
commit
c981f0900a
4 files changed
+88
-74
No files matched your search
@@ -21,36 +21,31 @@ import android.content.ContentResolver
|
||||
import android.net.Uri
|
||||
import com.github.amsacode.predict4java.Satellite
|
||||
import com.github.amsacode.predict4java.TLE
|
||||
import com.rtbishop.look4sat.data.*
|
||||
import com.rtbishop.look4sat.di.ExternalScope
|
||||
import com.rtbishop.look4sat.data.SatEntry
|
||||
import com.rtbishop.look4sat.data.SatTrans
|
||||
import com.rtbishop.look4sat.data.TleSource
|
||||
import com.rtbishop.look4sat.di.IoDispatcher
|
||||
import com.rtbishop.look4sat.repository.localData.SatelliteDao
|
||||
import com.rtbishop.look4sat.repository.remoteData.SatelliteService
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import timber.log.Timber
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.InputStream
|
||||
import java.util.zip.ZipInputStream
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@Singleton
|
||||
class SatelliteRepo @Inject constructor(
|
||||
private val resolver: ContentResolver,
|
||||
private val satelliteDao: SatelliteDao,
|
||||
private val satelliteService: SatelliteService,
|
||||
@ExternalScope private val externalScope: CoroutineScope,
|
||||
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
|
||||
) {
|
||||
private val _satData = MutableStateFlow<Result<List<SatItem>>>(Result.InProgress)
|
||||
val satData: Flow<Result<List<SatItem>>> = _satData
|
||||
|
||||
init {
|
||||
loadEntriesFromDb()
|
||||
}
|
||||
val satDataFlow = satelliteDao.getSatItems()
|
||||
|
||||
fun getTransmittersForSat(catNum: Int): Flow<List<SatTrans>> {
|
||||
return satelliteDao.getTransmittersForSat(catNum)
|
||||
@@ -65,49 +60,32 @@ class SatelliteRepo @Inject constructor(
|
||||
}
|
||||
|
||||
suspend fun updateSatDataFromFile(uri: Uri) {
|
||||
_satData.value = Result.InProgress
|
||||
externalScope.launch {
|
||||
runCatching {
|
||||
resolver.openInputStream(uri)?.use { stream ->
|
||||
val entries = importEntriesFromStreams(listOf(stream))
|
||||
insertEntriesAndRestoreSelection(entries)
|
||||
}
|
||||
}.onFailure { throwable: Throwable ->
|
||||
Timber.d("$throwable")
|
||||
_satData.value = Result.Error(throwable)
|
||||
runCatching {
|
||||
resolver.openInputStream(uri)?.use { stream ->
|
||||
val entries = importEntriesFromStreams(listOf(stream))
|
||||
insertEntriesAndRestoreSelection(entries)
|
||||
}
|
||||
loadEntriesFromDb()
|
||||
}.onFailure { throwable: Throwable ->
|
||||
throw throwable
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateSatDataFromWeb(sources: List<TleSource>) {
|
||||
_satData.value = Result.InProgress
|
||||
externalScope.launch {
|
||||
val updateTimeMillis = measureTimeMillis {
|
||||
runCatching {
|
||||
val streams = externalScope.async { getStreamsForSources(sources) }
|
||||
val transmitters = externalScope.async { satelliteService.fetchTransmitters() }
|
||||
val entries = importEntriesFromStreams(streams.await())
|
||||
satelliteDao.insertTransmitters(transmitters.await())
|
||||
insertEntriesAndRestoreSelection(entries)
|
||||
}.onFailure { throwable: Throwable ->
|
||||
Timber.d("$throwable")
|
||||
_satData.value = Result.Error(throwable)
|
||||
}
|
||||
loadEntriesFromDb()
|
||||
}
|
||||
Timber.d("Update from Web took $updateTimeMillis ms")
|
||||
coroutineScope {
|
||||
launch { updateEntriesFromSources(sources) }
|
||||
launch { updateTransmitters() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadEntriesFromDb() {
|
||||
_satData.value = Result.InProgress
|
||||
externalScope.launch {
|
||||
satelliteDao.getSatItems().collect { satItems ->
|
||||
delay(250)
|
||||
_satData.value = Result.Success(satItems)
|
||||
}
|
||||
}
|
||||
private suspend fun updateEntriesFromSources(sources: List<TleSource>) {
|
||||
val streams = getStreamsForSources(sources)
|
||||
val entries = importEntriesFromStreams(streams)
|
||||
insertEntriesAndRestoreSelection(entries)
|
||||
}
|
||||
|
||||
private suspend fun updateTransmitters() {
|
||||
val transmitters = satelliteService.fetchTransmitters()
|
||||
satelliteDao.insertTransmitters(transmitters)
|
||||
}
|
||||
|
||||
private suspend fun getStreamsForSources(sources: List<TleSource>): List<InputStream> {
|
||||
@@ -115,10 +93,7 @@ class SatelliteRepo @Inject constructor(
|
||||
sources.forEach { tleSource ->
|
||||
satelliteService.fetchFile(tleSource.url).body()?.byteStream()?.let { inputStream ->
|
||||
if (tleSource.url.contains(".zip", true)) {
|
||||
// Handle zip stream
|
||||
val zipInputStream = ZipInputStream(inputStream)
|
||||
val zipEntry = zipInputStream.nextEntry
|
||||
if (zipEntry != null && !zipEntry.isDirectory) streams.add(zipInputStream)
|
||||
streams.add(getZipStream(inputStream))
|
||||
} else {
|
||||
streams.add(inputStream)
|
||||
}
|
||||
@@ -127,6 +102,17 @@ class SatelliteRepo @Inject constructor(
|
||||
return streams
|
||||
}
|
||||
|
||||
private suspend fun getZipStream(inputStream: InputStream): InputStream {
|
||||
var stream: InputStream
|
||||
withContext(ioDispatcher) {
|
||||
ZipInputStream(inputStream).apply {
|
||||
nextEntry
|
||||
stream = this
|
||||
}
|
||||
}
|
||||
return stream
|
||||
}
|
||||
|
||||
private suspend fun importEntriesFromStreams(streams: List<InputStream>): List<SatEntry> {
|
||||
val importedEntries = mutableListOf<SatEntry>()
|
||||
withContext(ioDispatcher) {
|
||||
|
||||
@@ -31,9 +31,13 @@ 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.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@HiltViewModel
|
||||
class SharedViewModel @Inject constructor(
|
||||
@@ -41,19 +45,57 @@ class SharedViewModel @Inject constructor(
|
||||
private val satelliteRepo: SatelliteRepo,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _satData = MutableStateFlow<Result<List<SatItem>>>(Result.InProgress)
|
||||
private val _passes = MutableStateFlow<Result<MutableList<SatPass>>>(Result.InProgress)
|
||||
val passes: LiveData<Result<MutableList<SatPass>>> = _passes.asLiveData()
|
||||
|
||||
val satData = satelliteRepo.satData.asLiveData()
|
||||
val satData = _satData.asLiveData(viewModelScope.coroutineContext)
|
||||
|
||||
init {
|
||||
if (prefsRepo.isFirstLaunch()) {
|
||||
updateDefaultSourcesAndEntries()
|
||||
updateSatDataFromSources()
|
||||
prefsRepo.setFirstLaunchDone()
|
||||
}
|
||||
loadSatData()
|
||||
calculatePasses()
|
||||
}
|
||||
|
||||
private fun loadSatData() {
|
||||
viewModelScope.launch {
|
||||
delay(8)
|
||||
satelliteRepo.satDataFlow.map { Result.Success(it) }.collect {
|
||||
_satData.value = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSatDataFromFile(uri: Uri) {
|
||||
_satData.value = Result.InProgress
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
satelliteRepo.updateSatDataFromFile(uri)
|
||||
} catch (exception: Exception) {
|
||||
_satData.value = Result.Error(exception)
|
||||
}
|
||||
loadSatData()
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSatDataFromSources(sources: List<TleSource> = prefsRepo.loadTleSources()) {
|
||||
_satData.value = Result.InProgress
|
||||
viewModelScope.launch {
|
||||
val updateMillis = measureTimeMillis {
|
||||
try {
|
||||
prefsRepo.saveTleSources(sources)
|
||||
satelliteRepo.updateSatDataFromWeb(sources)
|
||||
} catch (exception: Exception) {
|
||||
_satData.value = Result.Error(exception)
|
||||
}
|
||||
loadSatData()
|
||||
}
|
||||
Timber.d("Update from WEB took $updateMillis ms")
|
||||
}
|
||||
}
|
||||
|
||||
fun getAppTimer() = liveData {
|
||||
while (true) {
|
||||
emit(System.currentTimeMillis())
|
||||
@@ -76,19 +118,6 @@ class SharedViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun updateEntriesFromFile(uri: Uri) {
|
||||
viewModelScope.launch {
|
||||
satelliteRepo.updateSatDataFromFile(uri)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateEntriesFromSources(sources: List<TleSource> = prefsRepo.loadTleSources()) {
|
||||
viewModelScope.launch {
|
||||
prefsRepo.saveTleSources(sources)
|
||||
satelliteRepo.updateSatDataFromWeb(sources)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateItemsSelection(items: List<SatItem>) {
|
||||
_passes.value = Result.InProgress
|
||||
viewModelScope.launch {
|
||||
@@ -117,8 +146,4 @@ class SharedViewModel @Inject constructor(
|
||||
passes.sortBy { it.pass.startTime }
|
||||
return passes
|
||||
}
|
||||
|
||||
private fun updateDefaultSourcesAndEntries() {
|
||||
updateEntriesFromSources()
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import com.rtbishop.look4sat.utility.RecyclerDivider
|
||||
import com.rtbishop.look4sat.utility.navigateSafe
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
||||
@AndroidEntryPoint
|
||||
class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
||||
@@ -40,11 +41,12 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
||||
private val viewModel: SharedViewModel by activityViewModels()
|
||||
private val filePicker =
|
||||
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||
uri?.let { viewModel.updateEntriesFromFile(uri) }
|
||||
uri?.let { viewModel.updateSatDataFromFile(uri) }
|
||||
}
|
||||
private var binding: FragmentEntriesBinding? = null
|
||||
private var entriesAdapter: EntriesAdapter? = null
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentEntriesBinding.bind(view)
|
||||
@@ -70,6 +72,7 @@ class EntriesFragment : Fragment(R.layout.fragment_entries) {
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
private fun setupObservers() {
|
||||
viewModel.satData.observe(viewLifecycleOwner, { result ->
|
||||
when (result) {
|
||||
|
||||
@@ -55,7 +55,7 @@ class SourcesDialog : AppCompatDialogFragment() {
|
||||
sourcesAdapter.addSource()
|
||||
}
|
||||
tleSourcesBtnPos.setOnClickListener {
|
||||
viewModel.updateEntriesFromSources(sourcesAdapter.getSources())
|
||||
viewModel.updateSatDataFromSources(sourcesAdapter.getSources())
|
||||
dismiss()
|
||||
}
|
||||
tleSourcesBtnNeg.setOnClickListener { dismiss() }
|
||||
|
||||
Reference in new issue
Block a user