mirror of
https://github.com/pawelorzech/Swoosh.git
synced 2026-03-31 20:15:41 +00:00
perf: remove StaggeredItem animations from LazyColumn for smooth scrolling
StaggeredItem wrapped every list item in AnimatedVisibility with slideInVertically + fadeIn + LaunchedEffect delays, causing jittery scrolling due to excessive recompositions and layout passes.
This commit is contained in:
parent
c3fb3c7c98
commit
f3ab562a6c
1 changed files with 32 additions and 90 deletions
|
|
@ -129,8 +129,7 @@ fun FeedScreen(
|
||||||
var showRenameDialog by remember { mutableStateOf<GhostAccount?>(null) }
|
var showRenameDialog by remember { mutableStateOf<GhostAccount?>(null) }
|
||||||
|
|
||||||
// Staggered entrance tracking
|
// Staggered entrance tracking
|
||||||
val animatedKeys = remember { mutableStateMapOf<String, Boolean>() }
|
// Stagger animations removed for smooth scrolling performance
|
||||||
var initialLoadComplete by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
// FAB entrance animation
|
// FAB entrance animation
|
||||||
var fabVisible by remember { mutableStateOf(false) }
|
var fabVisible by remember { mutableStateOf(false) }
|
||||||
|
|
@ -535,12 +534,6 @@ fun FeedScreen(
|
||||||
key = { it.ghostId ?: "local_${it.localId}" },
|
key = { it.ghostId ?: "local_${it.localId}" },
|
||||||
contentType = { "search_post" }
|
contentType = { "search_post" }
|
||||||
) { post ->
|
) { post ->
|
||||||
val itemKey = post.ghostId ?: "local_${post.localId}"
|
|
||||||
StaggeredItem(
|
|
||||||
key = itemKey,
|
|
||||||
animatedKeys = animatedKeys,
|
|
||||||
initialLoadComplete = initialLoadComplete
|
|
||||||
) {
|
|
||||||
PostCard(
|
PostCard(
|
||||||
post = post,
|
post = post,
|
||||||
onClick = { onPostClick(post) },
|
onClick = { onPostClick(post) },
|
||||||
|
|
@ -548,7 +541,6 @@ fun FeedScreen(
|
||||||
highlightQuery = searchQuery
|
highlightQuery = searchQuery
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Normal feed: pinned section + swipe actions
|
// Normal feed: pinned section + swipe actions
|
||||||
// Pinned posts (pin icon on each post card is sufficient)
|
// Pinned posts (pin icon on each post card is sufficient)
|
||||||
|
|
@ -558,12 +550,6 @@ fun FeedScreen(
|
||||||
key = { "pinned_${it.ghostId ?: "local_${it.localId}"}" },
|
key = { "pinned_${it.ghostId ?: "local_${it.localId}"}" },
|
||||||
contentType = { "pinned_post" }
|
contentType = { "pinned_post" }
|
||||||
) { post ->
|
) { post ->
|
||||||
val itemKey = post.ghostId ?: "local_${post.localId}"
|
|
||||||
StaggeredItem(
|
|
||||||
key = itemKey,
|
|
||||||
animatedKeys = animatedKeys,
|
|
||||||
initialLoadComplete = initialLoadComplete
|
|
||||||
) {
|
|
||||||
SwipeablePostCard(
|
SwipeablePostCard(
|
||||||
post = post,
|
post = post,
|
||||||
onClick = { onPostClick(post) },
|
onClick = { onPostClick(post) },
|
||||||
|
|
@ -582,7 +568,6 @@ fun FeedScreen(
|
||||||
snackbarHostState = snackbarHostState
|
snackbarHostState = snackbarHostState
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// No extra separator — thick dividers built into each post
|
// No extra separator — thick dividers built into each post
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -591,12 +576,6 @@ fun FeedScreen(
|
||||||
key = { it.ghostId ?: "local_${it.localId}" },
|
key = { it.ghostId ?: "local_${it.localId}" },
|
||||||
contentType = { "regular_post" }
|
contentType = { "regular_post" }
|
||||||
) { post ->
|
) { post ->
|
||||||
val itemKey = post.ghostId ?: "local_${post.localId}"
|
|
||||||
StaggeredItem(
|
|
||||||
key = itemKey,
|
|
||||||
animatedKeys = animatedKeys,
|
|
||||||
initialLoadComplete = initialLoadComplete
|
|
||||||
) {
|
|
||||||
SwipeablePostCard(
|
SwipeablePostCard(
|
||||||
post = post,
|
post = post,
|
||||||
onClick = { onPostClick(post) },
|
onClick = { onPostClick(post) },
|
||||||
|
|
@ -616,7 +595,6 @@ fun FeedScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSearchActive && state.isLoadingMore) {
|
if (!isSearchActive && state.isLoadingMore) {
|
||||||
item {
|
item {
|
||||||
|
|
@ -630,14 +608,6 @@ fun FeedScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(state.posts) {
|
|
||||||
if (state.posts.isNotEmpty() && !initialLoadComplete) {
|
|
||||||
delay(SwooshMotion.StaggerDelayMs * minOf(state.posts.size, 8) + 200)
|
|
||||||
initialLoadComplete = true
|
|
||||||
animatedKeys.clear() // Free memory — no longer needed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSearchActive) {
|
if (!isSearchActive) {
|
||||||
PullRefreshIndicator(
|
PullRefreshIndicator(
|
||||||
refreshing = state.isRefreshing,
|
refreshing = state.isRefreshing,
|
||||||
|
|
@ -766,34 +736,6 @@ fun FeedScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun StaggeredItem(
|
|
||||||
key: String,
|
|
||||||
animatedKeys: MutableMap<String, Boolean>,
|
|
||||||
initialLoadComplete: Boolean,
|
|
||||||
content: @Composable () -> Unit
|
|
||||||
) {
|
|
||||||
val shouldAnimate = !initialLoadComplete && key !in animatedKeys
|
|
||||||
var visible by remember { mutableStateOf(!shouldAnimate) }
|
|
||||||
|
|
||||||
LaunchedEffect(key) {
|
|
||||||
if (shouldAnimate && animatedKeys.size < 8) {
|
|
||||||
delay(SwooshMotion.StaggerDelayMs * animatedKeys.size)
|
|
||||||
animatedKeys[key] = true
|
|
||||||
}
|
|
||||||
visible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility(
|
|
||||||
visible = visible,
|
|
||||||
enter = slideInVertically(
|
|
||||||
initialOffsetY = { it / 3 },
|
|
||||||
animationSpec = SwooshMotion.gentle()
|
|
||||||
) + fadeIn(animationSpec = SwooshMotion.quick())
|
|
||||||
) {
|
|
||||||
content()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue