Better (?) units list loading

Moved from LaunchedEffect to another approach. Basically list is updated in onClick methods (not observing value in LaunchedEffect anymore)
This commit is contained in:
Sad Ellie 2022-05-12 21:39:49 +03:00
parent 0f92d24732
commit d119c94b0a
2 changed files with 63 additions and 42 deletions

View File

@ -413,49 +413,53 @@ class MainViewModel @Inject constructor(
* @param leftSide Decide whether or not we are on left side. Need it because right side requires * @param leftSide Decide whether or not we are on left side. Need it because right side requires
* us to mark disabled currency units * us to mark disabled currency units
*/ */
suspend fun loadUnitToShow( fun loadUnitsToShow(
query: String, query: String,
chosenUnitGroup: UnitGroup?, chosenUnitGroup: UnitGroup?,
leftSide: Boolean leftSide: Boolean
) { ) {
val filterGroup: Boolean = chosenUnitGroup != null viewModelScope.launch {
val filterGroup: Boolean = chosenUnitGroup != null
withContext(Dispatchers.Default) { // This is mostly not UI related stuff and viewModelScope.launch uses Dispatchers.Main
// Basic filtering // So we switch to Default
var basicFilteredUnits = ALL_UNITS.asSequence() withContext(Dispatchers.Default) {
basicFilteredUnits = when { // Basic filtering
// Both sides, Chip is selected, Only favorites var basicFilteredUnits = ALL_UNITS.asSequence()
(filterGroup) and (favoritesOnly) -> { basicFilteredUnits = when {
basicFilteredUnits.filter { (it.group == chosenUnitGroup) and it.isFavorite } // Both sides, Chip is selected, Only favorites
(filterGroup) and (favoritesOnly) -> {
basicFilteredUnits.filter { (it.group == chosenUnitGroup) and it.isFavorite }
}
// Both sides, Chip is selected, NOT Only favorites
(filterGroup) and (!favoritesOnly) -> {
basicFilteredUnits.filter { it.group == chosenUnitGroup }
}
// Chip is NOT selected, Only favorites
(!filterGroup) and (favoritesOnly) -> {
basicFilteredUnits.filter { it.isFavorite }
}
// Chip is NOT selected, NOT Only favorites
else -> basicFilteredUnits
} }
// Both sides, Chip is selected, NOT Only favorites
(filterGroup) and (!favoritesOnly) -> {
basicFilteredUnits.filter { it.group == chosenUnitGroup }
}
// Chip is NOT selected, Only favorites
(!filterGroup) and (favoritesOnly) -> {
basicFilteredUnits.filter { it.isFavorite }
}
// Chip is NOT selected, NOT Only favorites
else -> basicFilteredUnits
}
// Hiding broken currency units // Hiding broken currency units
if (leftSide) { if (leftSide) {
basicFilteredUnits = basicFilteredUnits.filter { it.isEnabled } basicFilteredUnits = basicFilteredUnits.filter { it.isEnabled }
} }
unitsToShow = if (query.isEmpty()) { unitsToShow = if (query.isEmpty()) {
// Query is empty, i.e. we want to see all units and they need to be sorted by usage // Query is empty, i.e. we want to see all units and they need to be sorted by usage
basicFilteredUnits basicFilteredUnits
.sortedByDescending { it.counter } .sortedByDescending { it.counter }
} else { } else {
// We are searching for a specific unit, we don't care about popularity // We are searching for a specific unit, we don't care about popularity
// We need search accuracy // We need search accuracy
basicFilteredUnits.sortByLev(query) basicFilteredUnits.sortByLev(query)
}
// Group by unit group
.groupBy { it.group }
} }
// Group by unit group
.groupBy { it.group }
} }
} }

View File

@ -46,9 +46,15 @@ fun SecondScreen(
.padding(8.dp), .padding(8.dp),
title = stringResource(id = if (leftSide) R.string.units_screen_from else R.string.units_screen_to), title = stringResource(id = if (leftSide) R.string.units_screen_from else R.string.units_screen_to),
value = searchQuery, value = searchQuery,
onValueChange = { searchQuery = it }, onValueChange = {
searchQuery = it
viewModel.loadUnitsToShow(searchQuery, chosenUnitGroup, leftSide)
},
favoritesOnly = favoritesOnly, favoritesOnly = favoritesOnly,
favoriteAction = { viewModel.toggleFavoritesOnly() }, favoriteAction = {
viewModel.toggleFavoritesOnly()
viewModel.loadUnitsToShow(searchQuery, chosenUnitGroup, leftSide)
},
navigateUpAction = navigateUp, navigateUpAction = navigateUp,
focusManager = focusManager focusManager = focusManager
) )
@ -58,7 +64,10 @@ fun SecondScreen(
lazyListState = chipsRowLazyListState, lazyListState = chipsRowLazyListState,
items = ALL_UNIT_GROUPS, items = ALL_UNIT_GROUPS,
chosenUnitGroup = chosenUnitGroup, chosenUnitGroup = chosenUnitGroup,
selectAction = { chosenUnitGroup = if (it == chosenUnitGroup) null else it } selectAction = {
chosenUnitGroup = if (it == chosenUnitGroup) null else it
viewModel.loadUnitsToShow(searchQuery, chosenUnitGroup, leftSide)
}
) )
UnitsList( UnitsList(
groupedUnits = unitsList, groupedUnits = unitsList,
@ -77,12 +86,20 @@ fun SecondScreen(
) )
} }
} }
LaunchedEffect(searchQuery, favoritesOnly, chosenUnitGroup) {
// Everytime we change query, toggle favorites or click chip, this block will be called // This block is called only once on initial composition
viewModel.loadUnitToShow(searchQuery, chosenUnitGroup, leftSide)
}
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
// This block is called only once on initial composition /**
* Telling viewModel that it needs to update the list
* Also while the below is being computed user will composable will use cached list from viewModel
*
* User actually doesn't see cached list. Computation takes few milliseconds since we don't
* compute any Levenshtein distance when the screen is launched and the list is limited
* to a specific [UnitGroup]
*
* Adding animation/spinners will cause flickering and confuse user
*/
viewModel.loadUnitsToShow(searchQuery, chosenUnitGroup, leftSide)
// Scrolling chips to current group // Scrolling chips to current group
chosenUnitGroup?.let { chosenUnitGroup?.let {
chipsRowLazyListState.animateScrollToItem(ALL_UNIT_GROUPS.indexOf(chosenUnitGroup)) chipsRowLazyListState.animateScrollToItem(ALL_UNIT_GROUPS.indexOf(chosenUnitGroup))