From b9f98a4f5b931ba6b46647adb783f097b2e6a143 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 15 May 2026 21:40:34 +0000 Subject: [PATCH] refactor(feeds): collapse RefresheableBox overloads to a single PullToRefreshBox The InvalidatableContent overload now delegates to the onRefresh overload, so there is only one PullToRefreshBox/state-management path to maintain. https://claude.ai/code/session_01MgnMaw8U83rXPSnoGF4KBY --- .../amethyst/ui/feeds/RefresheableBox.kt | 61 ++++--------------- 1 file changed, 13 insertions(+), 48 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/RefresheableBox.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/RefresheableBox.kt index 82d4f2625..bd38e9d4b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/RefresheableBox.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/RefresheableBox.kt @@ -40,30 +40,14 @@ import com.vitorpamplona.amethyst.ui.layouts.LocalDisappearingScaffoldPadding import kotlinx.coroutines.delay import kotlinx.coroutines.launch -@OptIn(ExperimentalMaterial3Api::class) @Composable fun RefresheableBox( invalidateableContent: InvalidatableContent, enablePullRefresh: Boolean = true, content: @Composable BoxScope.() -> Unit, ) { - var isRefreshing by remember { mutableStateOf(false) } - val scope = rememberCoroutineScope() - val onRefresh: () -> Unit = { - isRefreshing = true - scope.launch { - invalidateableContent.invalidateData() - delay(500) - isRefreshing = false - } - } - if (enablePullRefresh) { - PullToRefreshBoxWithScaffoldPadding( - isRefreshing = isRefreshing, - onRefresh = onRefresh, - content = content, - ) + RefresheableBox(onRefresh = invalidateableContent::invalidateData, content = content) } else { Box(Modifier.fillMaxSize(), content = content) } @@ -77,44 +61,25 @@ fun RefresheableBox( ) { var isRefreshing by remember { mutableStateOf(false) } val scope = rememberCoroutineScope() - val onRefreshWrapped: () -> Unit = { - isRefreshing = true - scope.launch { - onRefresh() - delay(500) - isRefreshing = false - } - } - - PullToRefreshBoxWithScaffoldPadding( - isRefreshing = isRefreshing, - onRefresh = onRefreshWrapped, - content = content, - ) -} - -/** - * [PullToRefreshBox] anchors its indicator at the top of the box. Inside a - * [DisappearingScaffold] the content fills the full screen height (feed items - * scroll behind the top bar), so the default indicator would appear behind the - * top bar. Offset the indicator down by the scaffold's top padding so it - * surfaces just below the bar. - */ -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun PullToRefreshBoxWithScaffoldPadding( - isRefreshing: Boolean, - onRefresh: () -> Unit, - content: @Composable BoxScope.() -> Unit, -) { val state = rememberPullToRefreshState() val topPadding = LocalDisappearingScaffoldPadding.current.calculateTopPadding() PullToRefreshBox( isRefreshing = isRefreshing, - onRefresh = onRefresh, + onRefresh = { + isRefreshing = true + scope.launch { + onRefresh() + delay(500) + isRefreshing = false + } + }, state = state, modifier = Modifier.fillMaxSize(), + // Anchor the indicator below the scaffold's top bar. Inside a DisappearingScaffold + // the content fills the full screen height (feed items scroll behind the bar), + // so the default top-aligned indicator would sit behind the top bar. Outside a + // scaffold the local default is 0.dp and behaviour is unchanged. indicator = { PullToRefreshDefaults.Indicator( modifier =