feat(ui): click on top bar to scroll back to top

This commit is contained in:
junkfood 2024-11-12 20:27:07 +08:00
parent fe22c445f0
commit 05b249b708
No known key found for this signature in database
GPG Key ID: 2EA5B648DB112A34
3 changed files with 125 additions and 81 deletions

View File

@ -17,17 +17,19 @@ import me.ash.reader.ui.theme.palette.onDark
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun RYScaffold( fun RYScaffold(
modifier: Modifier = Modifier,
containerColor: Color = MaterialTheme.colorScheme.surface, containerColor: Color = MaterialTheme.colorScheme.surface,
topBarTonalElevation: Dp = 0.dp, topBarTonalElevation: Dp = 0.dp,
containerTonalElevation: Dp = 0.dp, containerTonalElevation: Dp = 0.dp,
navigationIcon: (@Composable () -> Unit)? = null, navigationIcon: (@Composable () -> Unit)? = null,
actions: (@Composable RowScope.() -> Unit)? = null, actions: (@Composable RowScope.() -> Unit)? = null,
topBar: (@Composable () -> Unit)? = null,
bottomBar: (@Composable () -> Unit)? = null, bottomBar: (@Composable () -> Unit)? = null,
floatingActionButton: (@Composable () -> Unit)? = null, floatingActionButton: (@Composable () -> Unit)? = null,
content: @Composable () -> Unit = {}, content: @Composable () -> Unit = {},
) { ) {
Scaffold( Scaffold(
modifier = Modifier modifier = modifier
.background( .background(
MaterialTheme.colorScheme.surfaceColorAtElevation( MaterialTheme.colorScheme.surfaceColorAtElevation(
topBarTonalElevation, topBarTonalElevation,
@ -39,7 +41,7 @@ fun RYScaffold(
color = containerColor color = containerColor
) onDark MaterialTheme.colorScheme.surface, ) onDark MaterialTheme.colorScheme.surface,
topBar = { topBar = {
if (navigationIcon != null || actions != null) { if (topBar != null) topBar() else if (navigationIcon != null || actions != null) {
TopAppBar( TopAppBar(
title = {}, title = {},
navigationIcon = { navigationIcon?.invoke() }, navigationIcon = { navigationIcon?.invoke() },

View File

@ -2,6 +2,7 @@ package me.ash.reader.ui.page.home.feeds
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -31,6 +32,8 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -76,6 +79,7 @@ import me.ash.reader.ui.ext.currentAccountId
import me.ash.reader.ui.ext.findActivity import me.ash.reader.ui.ext.findActivity
import me.ash.reader.ui.ext.getCurrentVersion import me.ash.reader.ui.ext.getCurrentVersion
import me.ash.reader.ui.ext.getDefaultGroupId import me.ash.reader.ui.ext.getDefaultGroupId
import me.ash.reader.ui.ext.surfaceColorAtElevation
import me.ash.reader.ui.page.common.RouteName import me.ash.reader.ui.page.common.RouteName
import me.ash.reader.ui.page.home.FilterState import me.ash.reader.ui.page.home.FilterState
import me.ash.reader.ui.page.home.HomeViewModel import me.ash.reader.ui.page.home.HomeViewModel
@ -207,6 +211,20 @@ fun FeedsPage(
RYScaffold( RYScaffold(
topBarTonalElevation = topBarTonalElevation.value.dp, topBarTonalElevation = topBarTonalElevation.value.dp,
containerTonalElevation = groupListTonalElevation.value.dp, containerTonalElevation = groupListTonalElevation.value.dp,
topBar = {
TopAppBar(
modifier = Modifier.clickable(
onClick = {
scope.launch {
if (listState.firstVisibleItemIndex != 0) {
listState.animateScrollToItem(0)
}
}
},
indication = null,
interactionSource = remember { MutableInteractionSource() }
),
title = {},
navigationIcon = { navigationIcon = {
FeedbackIconButton( FeedbackIconButton(
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
@ -231,6 +249,13 @@ fun FeedsPage(
} }
} }
}, },
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
topBarTonalElevation.value.dp
),
)
)
},
content = { content = {
PullToRefreshBox( PullToRefreshBox(
state = syncingState, state = syncingState,

View File

@ -1,6 +1,8 @@
package me.ash.reader.ui.page.home.flow package me.ash.reader.ui.page.home.flow
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -15,7 +17,10 @@ import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.rounded.DoneAll import androidx.compose.material.icons.rounded.DoneAll
import androidx.compose.material.icons.rounded.Search import androidx.compose.material.icons.rounded.Search
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -61,6 +66,7 @@ import me.ash.reader.ui.component.base.FeedbackIconButton
import me.ash.reader.ui.component.base.RYExtensibleVisibility import me.ash.reader.ui.component.base.RYExtensibleVisibility
import me.ash.reader.ui.component.base.RYScaffold import me.ash.reader.ui.component.base.RYScaffold
import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.ext.collectAsStateValue
import me.ash.reader.ui.ext.surfaceColorAtElevation
import me.ash.reader.ui.page.common.RouteName import me.ash.reader.ui.page.common.RouteName
import me.ash.reader.ui.page.home.HomeViewModel import me.ash.reader.ui.page.home.HomeViewModel
@ -228,6 +234,20 @@ fun FlowPage(
RYScaffold( RYScaffold(
topBarTonalElevation = topBarTonalElevation.value.dp, topBarTonalElevation = topBarTonalElevation.value.dp,
containerTonalElevation = articleListTonalElevation.value.dp, containerTonalElevation = articleListTonalElevation.value.dp,
topBar = {
TopAppBar(
modifier = Modifier.clickable(
onClick = {
scope.launch {
if (listState.firstVisibleItemIndex != 0) {
listState.animateScrollToItem(0)
}
}
},
indication = null,
interactionSource = remember { MutableInteractionSource() }
),
title = {},
navigationIcon = { navigationIcon = {
FeedbackIconButton( FeedbackIconButton(
imageVector = Icons.AutoMirrored.Rounded.ArrowBack, imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
@ -256,11 +276,8 @@ fun FlowPage(
}, },
) { ) {
scope.launch { scope.launch {
// java.lang.NullPointerException: Attempt to invoke virtual method
// 'boolean androidx.compose.ui.node.LayoutNode.getNeedsOnPositionedDispatch$ui_release()'
// on a null object reference
if (flowUiState.listState.firstVisibleItemIndex != 0) { if (flowUiState.listState.firstVisibleItemIndex != 0) {
flowUiState.listState.scrollToItem(0) flowUiState.listState.animateScrollToItem(0)
} }
markAsRead = !markAsRead markAsRead = !markAsRead
onSearch = false onSearch = false
@ -277,15 +294,18 @@ fun FlowPage(
}, },
) { ) {
scope.launch { scope.launch {
// java.lang.NullPointerException: Attempt to invoke virtual method
// 'boolean androidx.compose.ui.node.LayoutNode.getNeedsOnPositionedDispatch$ui_release()'
// on a null object reference
if (flowUiState.listState.firstVisibleItemIndex != 0) { if (flowUiState.listState.firstVisibleItemIndex != 0) {
flowUiState.listState.scrollToItem(0) flowUiState.listState.animateScrollToItem(0)
} }
onSearch = !onSearch onSearch = !onSearch
} }
} }
}, colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
topBarTonalElevation.value.dp
),
)
)
}, },
content = { content = {
PullToRefreshBox( PullToRefreshBox(
@ -394,9 +414,6 @@ fun FlowPage(
filterBarTonalElevation = filterBarTonalElevation.value.dp, filterBarTonalElevation = filterBarTonalElevation.value.dp,
) { ) {
scope.launch { scope.launch {
// java.lang.NullPointerException: Attempt to invoke virtual method
// 'boolean androidx.compose.ui.node.LayoutNode.getNeedsOnPositionedDispatch$ui_release()'
// on a null object reference
if (flowUiState.listState.firstVisibleItemIndex != 0) { if (flowUiState.listState.firstVisibleItemIndex != 0) {
flowUiState.listState.animateScrollToItem(0) flowUiState.listState.animateScrollToItem(0)
} }