Merge pull request #2916 from vitorpamplona/claude/fix-pulltorefresh-padding-eR5sf

Fix pull-to-refresh indicator positioning in DisappearingScaffold
This commit is contained in:
Vitor Pamplona
2026-05-15 17:42:07 -04:00
committed by GitHub
@@ -23,43 +23,31 @@ package com.vitorpamplona.amethyst.ui.feeds
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import com.vitorpamplona.amethyst.ui.layouts.LocalDisappearingScaffoldPadding
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun RefresheableBox( fun RefresheableBox(
invalidateableContent: InvalidatableContent, invalidateableContent: InvalidatableContent,
enablePullRefresh: Boolean = true, enablePullRefresh: Boolean = true,
content: @Composable BoxScope.() -> Unit, 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) { if (enablePullRefresh) {
PullToRefreshBox( RefresheableBox(onRefresh = invalidateableContent::invalidateData, content = content)
isRefreshing = isRefreshing,
onRefresh = onRefresh,
modifier = Modifier.fillMaxSize(),
content = content,
)
} else { } else {
Box(Modifier.fillMaxSize(), content = content) Box(Modifier.fillMaxSize(), content = content)
} }
@@ -73,19 +61,35 @@ fun RefresheableBox(
) { ) {
var isRefreshing by remember { mutableStateOf(false) } var isRefreshing by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val onRefreshWrapped: () -> Unit = { val state = rememberPullToRefreshState()
isRefreshing = true val topPadding = LocalDisappearingScaffoldPadding.current.calculateTopPadding()
scope.launch {
onRefresh()
delay(500)
isRefreshing = false
}
}
PullToRefreshBox( PullToRefreshBox(
isRefreshing = isRefreshing, isRefreshing = isRefreshing,
onRefresh = onRefreshWrapped, onRefresh = {
isRefreshing = true
scope.launch {
onRefresh()
delay(500)
isRefreshing = false
}
},
state = state,
modifier = Modifier.fillMaxSize(), 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 =
Modifier
.align(Alignment.TopCenter)
.padding(top = topPadding),
isRefreshing = isRefreshing,
state = state,
)
},
content = content, content = content,
) )
} }