Skip to content

Commit

Permalink
achievements: Optimize recomposition
Browse files Browse the repository at this point in the history
  • Loading branch information
Omico committed Jun 13, 2024
1 parent 5a38335 commit 3b75145
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.compose.runtime.setValue
import com.slack.circuit.retained.collectAsRetainedState
import dev.omico.wwm.resources.model.game.WwLocale
import dev.omico.wwm.ui.WwmUiComponent
import dev.omico.wwm.ui.rememberUpdatedListState
import kotlinx.coroutines.launch

context(WwmUiComponent)
Expand All @@ -30,12 +31,12 @@ internal fun produceAchievementsUiState(): AchievementsUiState {
LaunchedEffect(Unit) { achievementsRepository.load() }
LaunchedEffect(locale) { achievementsRepository.reloadMultiText(locale) }
return AchievementsUiState(
achievements = achievements,
achievementCategories = achievementCategories,
achievementGroups = achievementGroups,
multiText = multiText,
achievements = rememberUpdatedListState(achievements),
achievementCategories = rememberUpdatedListState(achievementCategories),
achievementGroups = rememberUpdatedListState(achievementGroups),
multiText = rememberUpdatedListState(multiText),
locale = locale,
markedAchievementIds = markedAchievementIds,
markedAchievementIds = rememberUpdatedListState(markedAchievementIds),
eventSink = { event ->
when (event) {
is AchievementsUiEvent.ChangeLocale -> locale = event.locale
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import androidx.compose.ui.unit.dp
import dev.omico.wwm.feature.achievements.component.AchievementsDetailPaneUi
import dev.omico.wwm.feature.achievements.component.AchievementsListPaneUi
import dev.omico.wwm.resources.model.game.WwAchievementGroup
import dev.omico.wwm.ui.rememberWwText

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
Expand Down Expand Up @@ -47,9 +48,14 @@ internal fun AchievementsUi(
AnimatedPane(
modifier = Modifier,
content = {
val achievementGroup = navigator.currentDestination?.content ?: return@AnimatedPane
AchievementsDetailPaneUi(
state = state,
achievementGroup = navigator.currentDestination?.content ?: return@AnimatedPane,
achievementGroupId = achievementGroup.id,
achievementGroupName = rememberWwText(
multiText = state.multiText,
name = achievementGroup.name,
),
onNavigateBack = navigator::navigateBack,
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
*/
package dev.omico.wwm.feature.achievements

import androidx.compose.runtime.snapshots.SnapshotStateList
import com.slack.circuit.runtime.CircuitUiState
import dev.omico.wwm.data.WwmMarkedAchievementIds
import dev.omico.wwm.resources.model.game.WwAchievementCategories
import dev.omico.wwm.resources.model.game.WwAchievementGroups
import dev.omico.wwm.resources.model.game.WwAchievements
import dev.omico.wwm.resources.model.game.WwAchievement
import dev.omico.wwm.resources.model.game.WwAchievementCategory
import dev.omico.wwm.resources.model.game.WwAchievementGroup
import dev.omico.wwm.resources.model.game.WwLocale
import dev.omico.wwm.resources.model.game.WwMultiText
import dev.omico.wwm.resources.model.game.WwText

data class AchievementsUiState(
val achievements: WwAchievements,
val achievementCategories: WwAchievementCategories,
val achievementGroups: WwAchievementGroups,
val multiText: WwMultiText,
val achievements: SnapshotStateList<WwAchievement>,
val achievementCategories: SnapshotStateList<WwAchievementCategory>,
val achievementGroups: SnapshotStateList<WwAchievementGroup>,
val multiText: SnapshotStateList<WwText>,
val locale: WwLocale,
val markedAchievementIds: WwmMarkedAchievementIds,
val markedAchievementIds: SnapshotStateList<Int>,
val eventSink: (AchievementsUiEvent) -> Unit,
) : CircuitUiState
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,24 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
import dev.omico.wwm.feature.achievements.AchievementsUiEvent
import dev.omico.wwm.feature.achievements.AchievementsUiState
import dev.omico.wwm.resources.model.game.WwAchievement
import dev.omico.wwm.resources.model.game.WwAchievementGroup
import dev.omico.wwm.resources.rememberWwText
import dev.omico.wwm.ui.rememberWwText

@OptIn(ExperimentalFoundationApi::class)
@Composable
internal fun AchievementsDetailContent(
state: AchievementsUiState,
achievementGroup: WwAchievementGroup,
achievementGroupId: Int,
contentPadding: PaddingValues,
) {
val achievementGroupId by rememberUpdatedState(achievementGroup.id)
val markedAchievementIds by rememberUpdatedState(state.markedAchievementIds)
val achievements by remember(achievementGroupId, markedAchievementIds) {
val achievements by remember(achievementGroupId, state.markedAchievementIds) {
derivedStateOf {
state.achievements
.filter { achievement -> achievement.groupId == achievementGroupId }
.sortedBy { achievement -> achievement.id in markedAchievementIds }
.sortedBy { achievement -> achievement.id in state.markedAchievementIds }
}
}
LazyColumn(
Expand All @@ -43,7 +39,7 @@ internal fun AchievementsDetailContent(
key = WwAchievement::id,
itemContent = { achievement ->
AchievementsDetailItem(
marked = achievement.id in markedAchievementIds,
marked = achievement.id in state.markedAchievementIds,
onMarkedChange = { marked ->
state.eventSink(
AchievementsUiEvent.ChangeAchievementMark(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,27 @@ package dev.omico.wwm.feature.achievements.component
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import dev.omico.wwm.feature.achievements.AchievementsUiState
import dev.omico.wwm.resources.model.game.WwAchievementGroup

@Composable
internal fun AchievementsDetailPaneUi(
state: AchievementsUiState,
achievementGroup: WwAchievementGroup,
achievementGroupId: Int,
achievementGroupName: String,
onNavigateBack: () -> Unit,
) {
Scaffold(
topBar = {
AchievementsDetailTopAppBar(
state = state,
achievementGroup = achievementGroup,
achievementGroupId = achievementGroupId,
achievementGroupName = achievementGroupName,
onNavigateBack = onNavigateBack,
)
},
content = { innerPadding ->
AchievementsDetailContent(
state = state,
achievementGroup = achievementGroup,
achievementGroupId = achievementGroupId,
contentPadding = innerPadding,
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import dev.omico.wwm.feature.achievements.AchievementsUiState
import dev.omico.wwm.resources.model.game.WwAchievementGroup
import dev.omico.wwm.resources.rememberWwText
import dev.omico.wwm.ui.LocalNavigationSuiteType

@OptIn(
Expand All @@ -29,26 +26,21 @@ import dev.omico.wwm.ui.LocalNavigationSuiteType
@Composable
internal fun AchievementsDetailTopAppBar(
state: AchievementsUiState,
achievementGroup: WwAchievementGroup,
achievementGroupId: Int,
achievementGroupName: String,
onNavigateBack: () -> Unit,
) {
TopAppBar(
title = {
val achievementGroupName = rememberWwText(
multiText = state.multiText,
name = achievementGroup.name,
)
val markedAchievementIds by rememberUpdatedState(state.markedAchievementIds)
val achievementGroupId by rememberUpdatedState(achievementGroup.id)
val countAchievementGroup by remember(achievementGroupId) {
derivedStateOf {
state.achievements.count { achievement -> achievement.groupId == achievementGroupId }
}
}
val countMarkedAchievementGroup by remember(achievementGroupId, markedAchievementIds) {
val countMarkedAchievementGroup by remember(achievementGroupId, state.markedAchievementIds) {
derivedStateOf {
state.achievements.count { achievement ->
achievement.groupId == achievementGroupId && achievement.id in markedAchievementIds
achievement.groupId == achievementGroupId && achievement.id in state.markedAchievementIds
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package dev.omico.wwm.feature.achievements.component

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
Expand All @@ -19,14 +20,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import dev.omico.wwm.feature.achievements.AchievementsUiState
import dev.omico.wwm.resources.WwmIcons
import dev.omico.wwm.resources.model.game.WwAchievementCategory
import dev.omico.wwm.resources.model.game.WwAchievementGroup
import dev.omico.wwm.resources.rememberWwText
import dev.omico.wwm.ui.rememberWwText
import org.jetbrains.compose.resources.painterResource

@OptIn(ExperimentalMaterial3Api::class)
Expand All @@ -40,11 +40,10 @@ internal fun AchievementsListPaneUi(
topBar = {
TopAppBar(
title = {
val markedAchievementIds by rememberUpdatedState(state.markedAchievementIds)
val countAchievement by remember { derivedStateOf { state.achievements.count() } }
val countMarkedAchievement by remember(markedAchievementIds) {
val countMarkedAchievement by remember(state.markedAchievementIds) {
derivedStateOf {
state.achievements.count { achievement -> achievement.id in markedAchievementIds }
state.achievements.count { achievement -> achievement.id in state.markedAchievementIds }
}
}
Text("Achievements $countMarkedAchievement/$countAchievement")
Expand Down Expand Up @@ -73,6 +72,7 @@ internal fun AchievementsListPaneUi(
},
content = { innerPadding ->
LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(space = 8.dp),
contentPadding = innerPadding,
content = {
Expand Down Expand Up @@ -101,6 +101,7 @@ private fun LazyListScope.achievementsCategoryItem(
) {
item(
key = category.id,
contentType = category::class,
content = {
AchievementsListItem(
text = rememberWwText(
Expand All @@ -112,24 +113,28 @@ private fun LazyListScope.achievementsCategoryItem(
)
},
)
if (isExpanded) {
items(
items = state.achievementGroups.filter { it.category == category.id },
key = WwAchievementGroup::id,
itemContent = { achievementGroup ->
AchievementsListItem(
text = rememberWwText(
multiText = state.multiText,
name = achievementGroup.name,
),
modifier = run {
Modifier
.padding(start = 16.dp)
.animateItemPlacement()
},
onClick = { onGroupItemClick(achievementGroup) },
)
},
)
}
items(
items = when {
isExpanded ->
state.achievementGroups
.filter { achievementGroup -> achievementGroup.category == category.id }
else -> emptyList()
},
key = WwAchievementGroup::id,
contentType = { achievementGroup -> achievementGroup::class },
itemContent = { achievementGroup ->
AchievementsListItem(
text = rememberWwText(
multiText = state.multiText,
name = achievementGroup.name,
),
modifier = run {
Modifier
.padding(start = 16.dp)
.animateItemPlacement()
},
onClick = { onGroupItemClick(achievementGroup) },
)
},
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright 2024 Omico. All Rights Reserved.
*/
package dev.omico.wwm.ui

import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshots.SnapshotStateList

// TODO Waiting for Delusion 0.10.0
@Composable
fun <T> rememberUpdatedListState(newValues: Iterable<T>): SnapshotStateList<T> =
remember<SnapshotStateList<T>>(::mutableStateListOf)
.apply(SnapshotStateList<T>::clear)
.apply { addAll(newValues) }
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Copyright 2024 Omico. All Rights Reserved.
*/
package dev.omico.wwm.resources
package dev.omico.wwm.ui

import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
Expand All @@ -11,9 +11,10 @@ import dev.omico.wwm.resources.model.game.WwMultiText

@Composable
fun rememberWwText(multiText: WwMultiText, name: String): String {
val text by remember(multiText, name) {
val currentMultiText = rememberUpdatedListState(multiText)
val text by remember(currentMultiText, name) {
derivedStateOf {
multiText.firstOrNull { it.id == name }?.content ?: name
currentMultiText.firstOrNull { it.id == name }?.content ?: name
}
}
return text
Expand Down

0 comments on commit 3b75145

Please sign in to comment.