mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
Created SelectionRepository, cleaned up code
This commit is contained in:
1 parent
5d2a870319
commit
208c587ddf
12 files changed
+156
-130
No files matched your search
@@ -9,6 +9,7 @@ import androidx.room.Room
|
||||
import com.rtbishop.look4sat.data.DataParser
|
||||
import com.rtbishop.look4sat.data.DataRepository
|
||||
import com.rtbishop.look4sat.data.SatelliteRepository
|
||||
import com.rtbishop.look4sat.data.SelectionRepository
|
||||
import com.rtbishop.look4sat.domain.IDataRepository
|
||||
import com.rtbishop.look4sat.domain.ISatelliteRepository
|
||||
import com.rtbishop.look4sat.domain.ISensorRepository
|
||||
@@ -58,6 +59,10 @@ class MainContainer(private val context: Context) {
|
||||
return DataRepository(parser, fileSource, entries, radios, remoteSource, scope, settings)
|
||||
}
|
||||
|
||||
fun provideSelectionRepository(): SelectionRepository {
|
||||
return SelectionRepository(Dispatchers.Default, dataRepository, settingsRepository)
|
||||
}
|
||||
|
||||
private fun provideSensorRepository(): ISensorRepository {
|
||||
val manager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
||||
val sensor = manager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
|
||||
|
||||
@@ -28,9 +28,9 @@ interface EntriesDao {
|
||||
@Query("SELECT COUNT(*) FROM entries")
|
||||
fun getEntriesTotal(): Flow<Int>
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT catnum, name FROM entries ORDER BY name ASC")
|
||||
suspend fun getEntriesWithModes(): List<SatItem>
|
||||
// @Transaction
|
||||
@Query("SELECT catnum, name FROM entries ORDER BY name ASC")
|
||||
suspend fun getEntriesList(): List<SatItem>
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM entries WHERE catnum IN (:selectedIds)")
|
||||
|
||||
@@ -29,8 +29,8 @@ class EntriesStorage(private val entriesDao: EntriesDao) : IEntriesStorage {
|
||||
|
||||
override fun getEntriesTotal() = entriesDao.getEntriesTotal()
|
||||
|
||||
override suspend fun getEntriesWithModes(): List<DomainItem> {
|
||||
return entriesDao.getEntriesWithModes().toDomainItems()
|
||||
override suspend fun getEntriesList(): List<DomainItem> {
|
||||
return entriesDao.getEntriesList().toDomainItems()
|
||||
}
|
||||
|
||||
override suspend fun getEntriesWithIds(ids: List<Int>): List<Satellite> {
|
||||
@@ -50,7 +50,7 @@ class EntriesStorage(private val entriesDao: EntriesDao) : IEntriesStorage {
|
||||
|
||||
private fun DomainEntry.toFramework() = FrameworkEntry(this.data, this.comment)
|
||||
|
||||
private fun FrameworkItem.toDomain() = DomainItem(this.catnum, this.name, this.modes, false)
|
||||
private fun FrameworkItem.toDomain() = DomainItem(this.catnum, this.name, false)
|
||||
|
||||
private fun List<DomainEntry>.toFrameworkEntries() = this.map { entry -> entry.toFramework() }
|
||||
|
||||
|
||||
@@ -17,16 +17,14 @@
|
||||
*/
|
||||
package com.rtbishop.look4sat.framework.model
|
||||
|
||||
import androidx.room.Relation
|
||||
|
||||
data class SatItem(
|
||||
val catnum: Int,
|
||||
val name: String,
|
||||
@Relation(
|
||||
parentColumn = "catnum",
|
||||
entity = SatRadio::class,
|
||||
entityColumn = "catnum",
|
||||
projection = ["mode"]
|
||||
)
|
||||
val modes: List<String>
|
||||
val name: String
|
||||
// @Relation(
|
||||
// parentColumn = "catnum",
|
||||
// entity = SatRadio::class,
|
||||
// entityColumn = "catnum",
|
||||
// projection = ["mode"]
|
||||
// )
|
||||
// val modes: List<String>
|
||||
)
|
||||
@@ -9,7 +9,6 @@ import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -26,7 +25,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.model.DataState
|
||||
import com.rtbishop.look4sat.model.SatItem
|
||||
import com.rtbishop.look4sat.presentation.CardIcon
|
||||
import com.rtbishop.look4sat.presentation.CardLoadingIndicator
|
||||
@@ -37,25 +35,33 @@ import com.rtbishop.look4sat.presentation.onClick
|
||||
@Composable
|
||||
fun EntriesScreen(navToPasses: () -> Unit) {
|
||||
val viewModel = viewModel(EntriesViewModel::class.java, factory = EntriesViewModel.Factory)
|
||||
val state = viewModel.satData.collectAsState(initial = DataState.Loading)
|
||||
val uiState = viewModel.uiState.value
|
||||
|
||||
val showDialog = rememberSaveable { mutableStateOf(false) }
|
||||
val toggleDialog = { showDialog.value = showDialog.value.not() }
|
||||
if (showDialog.value) {
|
||||
TypesDialog(list = viewModel.satTypes, selected = viewModel.getSatType(), toggleDialog) {
|
||||
viewModel.setSatType(it)
|
||||
TypesDialog(list = uiState.typesList, selected = uiState.currentType, toggleDialog) {
|
||||
viewModel.setType(it)
|
||||
}
|
||||
}
|
||||
|
||||
val unselectAll = { viewModel.selectCurrentItems(false) }
|
||||
val selectAll = { viewModel.selectCurrentItems(true) }
|
||||
val unselectAll = { viewModel.updateSelection(false) }
|
||||
val selectAll = { viewModel.updateSelection(true) }
|
||||
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||
TopBar(setQuery = { newQuery: String -> viewModel.setQuery(newQuery) }, saveSelection = {
|
||||
viewModel.saveSelection()
|
||||
navToPasses()
|
||||
})
|
||||
MiddleBar(viewModel.getSatType(), { toggleDialog() }, { unselectAll() }, { selectAll() })
|
||||
EntriesCard(state = state.value) { list, value -> viewModel.updateSelection(list, value) }
|
||||
MiddleBar(uiState.currentType, { toggleDialog() }, { unselectAll() }, { selectAll() })
|
||||
ElevatedCard(modifier = Modifier.fillMaxSize()) {
|
||||
if (uiState.isLoading) {
|
||||
CardLoadingIndicator()
|
||||
} else {
|
||||
EntriesCard(uiState.itemsList) { list, value ->
|
||||
viewModel.updateSelection(list, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +175,7 @@ private fun EntryTypeCard(type: String, onClick: () -> Unit, modifier: Modifier
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun EntryPreview() {
|
||||
val satItem = SatItem(45555, "SatName", emptyList(), true)
|
||||
val satItem = SatItem(45555, "Very long Satellite name", true)
|
||||
MainTheme { Entry(item = satItem, onSelected = { _, _ -> run {} }, modifier = Modifier) }
|
||||
}
|
||||
|
||||
@@ -206,23 +212,15 @@ private fun Entry(item: SatItem, onSelected: (List<Int>, Boolean) -> Unit, modif
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun EntriesPreview() {
|
||||
MainTheme { EntriesCard(DataState.Loading) { _, _ -> run {} } }
|
||||
MainTheme { EntriesCard(emptyList()) { _, _ -> run {} } }
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun EntriesCard(state: DataState<List<SatItem>>, onSelected: (List<Int>, Boolean) -> Unit) {
|
||||
ElevatedCard(modifier = Modifier.fillMaxSize()) {
|
||||
when (state) {
|
||||
is DataState.Success -> {
|
||||
LazyColumn {
|
||||
items(items = state.data, key = { item -> item.catnum }) { entry ->
|
||||
Entry(entry, onSelected, Modifier.animateItemPlacement())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> CardLoadingIndicator()
|
||||
fun EntriesCard(items: List<SatItem>, onSelected: (List<Int>, Boolean) -> Unit) {
|
||||
LazyColumn {
|
||||
items(items = items, key = { item -> item.catnum }) { entry ->
|
||||
Entry(entry, onSelected, Modifier.animateItemPlacement())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.rtbishop.look4sat.presentation.entries
|
||||
|
||||
import com.rtbishop.look4sat.model.SatItem
|
||||
|
||||
data class EntriesScreenState(
|
||||
val isLoading: Boolean,
|
||||
val itemsList: List<SatItem>,
|
||||
val currentType: String,
|
||||
val typesList: List<String>,
|
||||
)
|
||||
@@ -17,115 +17,59 @@
|
||||
*/
|
||||
package com.rtbishop.look4sat.presentation.entries
|
||||
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.rtbishop.look4sat.MainApplication
|
||||
import com.rtbishop.look4sat.domain.IDataRepository
|
||||
import com.rtbishop.look4sat.domain.ISettingsRepository
|
||||
import com.rtbishop.look4sat.model.DataState
|
||||
import com.rtbishop.look4sat.model.SatItem
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import com.rtbishop.look4sat.data.SelectionRepository
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class EntriesViewModel(
|
||||
private val dataRepository: IDataRepository,
|
||||
private val settingsRepository: ISettingsRepository,
|
||||
private val dispatcher: CoroutineDispatcher = Dispatchers.Default
|
||||
) : ViewModel() {
|
||||
class EntriesViewModel(private val selectionRepo: SelectionRepository) : ViewModel() {
|
||||
|
||||
private val satType = MutableStateFlow("All")
|
||||
private val currentQuery = MutableStateFlow(String())
|
||||
private val itemsFromRepo = MutableStateFlow<List<SatItem>>(emptyList())
|
||||
private val itemsWithType = satType.flatMapLatest { type ->
|
||||
itemsFromRepo.map { items -> filterByType(items, type) }
|
||||
}
|
||||
private val itemsWithQuery = currentQuery.flatMapLatest { query ->
|
||||
itemsWithType.map { items -> filterByQuery(items, query) }
|
||||
}
|
||||
val satData = itemsWithQuery.map { items -> DataState.Success(items) }
|
||||
val satTypes = dataRepository.getSatelliteTypes()
|
||||
private val defaultUiState = EntriesScreenState(
|
||||
isLoading = true,
|
||||
itemsList = emptyList(),
|
||||
currentType = selectionRepo.getCurrentType(),
|
||||
typesList = selectionRepo.getTypesList()
|
||||
)
|
||||
val uiState = mutableStateOf(defaultUiState)
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
delay(250)
|
||||
itemsFromRepo.value = dataRepository.getEntriesWithSelection()
|
||||
delay(1000)
|
||||
selectionRepo.getEntriesFlow().collect { items ->
|
||||
uiState.value = uiState.value.copy(isLoading = false, itemsList = items)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getSatType() = satType.value
|
||||
|
||||
fun setSatType(type: String) {
|
||||
satType.value = type
|
||||
fun setType(type: String) = viewModelScope.launch {
|
||||
selectionRepo.setType(type)
|
||||
uiState.value = uiState.value.copy(currentType = type)
|
||||
}
|
||||
|
||||
fun selectCurrentItems(selectAll: Boolean) = viewModelScope.launch {
|
||||
updateEntriesSelection(itemsWithQuery.first().map { item -> item.catnum }, selectAll)
|
||||
}
|
||||
fun setQuery(query: String) = viewModelScope.launch { selectionRepo.setQuery(query) }
|
||||
|
||||
fun setQuery(query: String) {
|
||||
currentQuery.value = query
|
||||
}
|
||||
|
||||
fun saveSelection() = viewModelScope.launch {
|
||||
val newSelection = itemsFromRepo.value.filter { it.isSelected }.map { it.catnum }
|
||||
settingsRepository.saveEntriesSelection(newSelection)
|
||||
fun updateSelection(selectAll: Boolean) = viewModelScope.launch {
|
||||
selectionRepo.updateSelection(selectAll)
|
||||
}
|
||||
|
||||
fun updateSelection(catNums: List<Int>, isSelected: Boolean) = viewModelScope.launch {
|
||||
updateEntriesSelection(catNums, isSelected)
|
||||
selectionRepo.updateSelection(catNums, isSelected)
|
||||
}
|
||||
|
||||
private suspend fun updateEntriesSelection(catNums: List<Int>, isSelected: Boolean) {
|
||||
withContext(dispatcher) {
|
||||
itemsFromRepo.value.let { itemsAll ->
|
||||
val copiedList = itemsAll.map { item -> item.copy() }
|
||||
catNums.forEach { catnum ->
|
||||
copiedList.find { item -> item.catnum == catnum }?.isSelected = isSelected
|
||||
}
|
||||
itemsFromRepo.value = copiedList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun filterByType(items: List<SatItem>, type: String): List<SatItem> {
|
||||
return withContext(dispatcher) {
|
||||
if (type == "All") return@withContext items
|
||||
val catnums = settingsRepository.loadSatType(type)
|
||||
if (catnums.isEmpty()) return@withContext items
|
||||
return@withContext items.filter { item -> item.catnum in catnums }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun filterByQuery(items: List<SatItem>, query: String): List<SatItem> {
|
||||
return withContext(dispatcher) {
|
||||
if (query.isBlank()) return@withContext items
|
||||
return@withContext try {
|
||||
items.filter { it.catnum == query.toInt() }
|
||||
} catch (e: Exception) {
|
||||
items.filter { item -> item.name.lowercase().contains(query.lowercase()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
fun saveSelection() = viewModelScope.launch { selectionRepo.saveSelection() }
|
||||
|
||||
companion object {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
val applicationKey = ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY
|
||||
initializer {
|
||||
val container = (this[applicationKey] as MainApplication).container
|
||||
EntriesViewModel(
|
||||
container.dataRepository,
|
||||
container.settingsRepository
|
||||
)
|
||||
EntriesViewModel(container.provideSelectionRepository())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user