diff --git a/common/src/commonMain/kotlin/com/twidere/twiderex/component/TimelineComponent.kt b/common/src/commonMain/kotlin/com/twidere/twiderex/component/TimelineComponent.kt index ecde09812..36059cb11 100644 --- a/common/src/commonMain/kotlin/com/twidere/twiderex/component/TimelineComponent.kt +++ b/common/src/commonMain/kotlin/com/twidere/twiderex/component/TimelineComponent.kt @@ -87,7 +87,6 @@ fun TimelineComponent( .distinctUntilChanged() .filter { !it } .filter { listState.layoutInfo.totalItemsCount != 0 } - .filter { listState.firstVisibleItemIndex != 0 && listState.firstVisibleItemScrollOffset != 0 } .collect { viewModel.saveScrollState( TimelineScrollState( diff --git a/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/SelectionContainer.kt b/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/SelectionContainer.kt index dd12ed893..66a6337ba 100644 --- a/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/SelectionContainer.kt +++ b/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/SelectionContainer.kt @@ -45,8 +45,13 @@ class PositionWrapper { @Composable fun SelectionContainer( modifier: Modifier = Modifier, + enable: Boolean = true, content: @Composable (PositionWrapper?) -> Unit, ) { + if (!enable) { + content.invoke(null) + return + } val positionWrapper = remember { if (currentPlatform != Platform.Android) PositionWrapper() else null } diff --git a/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/StatusActions.kt b/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/StatusActions.kt index ca6d99888..f4d252db6 100644 --- a/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/StatusActions.kt +++ b/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/StatusActions.kt @@ -26,6 +26,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -75,14 +76,16 @@ fun ReplyButton( status: UiStatus, withNumber: Boolean = true, ) { - val navigator = LocalNavigator.current val icon = painterResource(res = com.twidere.twiderex.MR.files.ic_corner_up_left) val contentDescription = stringResource(res = com.twidere.twiderex.MR.strings.accessibility_common_status_actions_reply) + + val navigator = LocalNavigator.current val action = { navigator.compose(ComposeType.Reply, statusKey = status.statusKey) } - val data = status.retweet ?: status + if (withNumber) { + val data = status.retweet ?: status StatusActionButtonWithNumbers( modifier = modifier, icon = icon, @@ -388,55 +391,44 @@ private fun StatusActionButtonWithNumbers( onClick: () -> Unit, ) { val contentColor = color.copy(LocalContentAlpha.current) - Box( - modifier = modifier, + val source = remember { MutableInteractionSource() } + Row( + modifier = modifier + .defaultMinSize( + minHeight = ButtonDefaults.MinHeight + ) + .clickable( + onClick = onClick, + enabled = enabled, + interactionSource = source, + indication = null, + ) + .padding(StatusActionsDefaults.ContentPadding), + verticalAlignment = Alignment.CenterVertically, ) { - val source = remember { - MutableInteractionSource() - } - Row( + Icon( modifier = Modifier - .defaultMinSize( - minHeight = ButtonDefaults.MinHeight - ) - .clickable( - onClick = onClick, - enabled = enabled, - interactionSource = source, - indication = null, - ) - .padding(StatusActionsDefaults.ContentPadding), - verticalAlignment = Alignment.CenterVertically, - ) { - Icon( - modifier = Modifier - .size(MaterialTheme.typography.body1.fontSize.value.dp) - .indication( - source, - rememberRipple( - bounded = false, - radius = rippleSize - ) - ), - tint = contentColor, - painter = icon, - contentDescription = contentDescription, - ) - Row( - modifier = modifier - .weight(1f), - ) { - if (count > 0) { - Box(modifier = Modifier.width(4.dp)) - Text( - text = count.humanizedCount(), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - style = MaterialTheme.typography.body2, - color = contentColor, + .size(MaterialTheme.typography.body1.fontSize.value.dp) + .indication( + source, + rememberRipple( + bounded = false, + radius = rippleSize ) - } - } + ), + tint = contentColor, + painter = icon, + contentDescription = contentDescription, + ) + if (count > 0) { + Spacer(modifier = Modifier.width(4.dp)) + Text( + text = count.humanizedCount(), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + style = MaterialTheme.typography.body2, + color = contentColor, + ) } } } diff --git a/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/StatusMediaComponent.kt b/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/StatusMediaComponent.kt index 5fcffc68f..0eee802bb 100644 --- a/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/StatusMediaComponent.kt +++ b/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/StatusMediaComponent.kt @@ -131,7 +131,7 @@ fun StatusMediaComponent( modifier = Modifier .weight(1f) .fillMaxSize(), - sensitive = sensitive, + sensitive = sensitive && status.platformType === PlatformType.Mastodon, onClick = onItemClick, ) } @@ -148,7 +148,7 @@ fun StatusMediaComponent( modifier = Modifier .weight(1f) .fillMaxSize(), - sensitive = sensitive, + sensitive = sensitive && status.platformType === PlatformType.Mastodon, onClick = onItemClick, ) if (it != media.last()) { @@ -169,7 +169,7 @@ fun StatusMediaComponent( StatusMediaPreviewItem( media = it, onClick = onItemClick, - sensitive = sensitive + sensitive = sensitive && status.platformType === PlatformType.Mastodon ) } } @@ -250,6 +250,7 @@ object StatusMediaDefaults { object Mastodon { val IconSpacing = 8.dp } + object Icon { val ContentPadding = 6.dp } diff --git a/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/StatusText.kt b/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/StatusText.kt index 2eebe8771..2e414d500 100644 --- a/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/StatusText.kt +++ b/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/StatusText.kt @@ -54,7 +54,8 @@ import com.twidere.twiderex.model.ui.UiStatus fun ColumnScope.StatusText( status: UiStatus, maxLines: Int = Int.MAX_VALUE, - showMastodonPoll: Boolean = true + showMastodonPoll: Boolean = true, + isSelectionAble: Boolean = true, ) { val expandable = status.platformType == PlatformType.Mastodon && status.spoilerText != null @@ -85,7 +86,7 @@ fun ColumnScope.StatusText( } AnimatedVisibility(visible = expanded) { Column { - SelectionContainer { + SelectionContainer(enable = isSelectionAble) { HtmlText( modifier = Modifier.fillMaxWidth(), htmlText = status.htmlText, diff --git a/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/TimelineStatusComponent.kt b/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/TimelineStatusComponent.kt index dd8824d78..ae0915ce1 100644 --- a/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/TimelineStatusComponent.kt +++ b/common/src/commonMain/kotlin/com/twidere/twiderex/component/status/TimelineStatusComponent.kt @@ -20,10 +20,11 @@ */ package com.twidere.twiderex.component.status -import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.AnimatedContent import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope @@ -153,15 +154,13 @@ private fun NormalStatus( footer = { Column { if (showActions) { - Row { - Spacer(modifier = Modifier.width(UserAvatarDefaults.AvatarSize)) - StatusActions(data) - } + StatusActions(data) } else { Spacer(modifier = Modifier.height(NormalStatusDefaults.ContentSpacing)) } } - } + }, + isSelectionAble = false, ) } } @@ -322,10 +321,13 @@ private fun StatusActions(status: UiStatus) { CompositionLocalProvider( LocalContentAlpha provides ContentAlpha.medium, ) { - Row { - ReplyButton(modifier = Modifier.weight(1f), status = status) - RetweetButton(modifier = Modifier.weight(1f), status = status) - LikeButton(modifier = Modifier.weight(1f), status = status) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + ReplyButton(status = status) + RetweetButton(status = status) + LikeButton(status = status) ShareButton(status = status, compat = true) } } @@ -368,6 +370,7 @@ fun StatusContent( lineUp: Boolean = false, threadStyle: StatusThreadStyle = StatusThreadStyle.NONE, footer: @Composable () -> Unit = {}, + isSelectionAble: Boolean = true, ) { val layoutDirection = LocalLayoutDirection.current val status = data.retweet ?: data @@ -462,14 +465,22 @@ fun StatusContent( when (type) { StatusContentType.Normal -> { Spacer(modifier = Modifier.height(StatusContentDefaults.Normal.BodySpacing)) - StatusBody(status, type = type) + StatusBody( + status = status, + type = type, + isSelectionAble = isSelectionAble, + ) } StatusContentType.Extend -> UserScreenName(status.user) } if (type == StatusContentType.Extend) { Column { Spacer(modifier = Modifier.height(StatusContentDefaults.Extend.BodySpacing)) - StatusBody(status = status, type = type) + StatusBody( + status = status, + type = type, + isSelectionAble = isSelectionAble + ) } } Column { @@ -530,9 +541,11 @@ object StatusContentDefaults { fun ColumnScope.StatusBody( status: UiStatus, type: StatusContentType, + isSelectionAble: Boolean, ) { StatusText( status = status, + isSelectionAble = isSelectionAble ) StatusBodyMedia(status) @@ -616,17 +629,16 @@ private fun ColumnScope.StatusBodyMedia( val navigator = LocalNavigator.current if (status.media.any()) { Spacer(modifier = Modifier.height(StatusBodyMediaDefaults.Spacing)) - AnimatedVisibility(visible = LocalDisplayPreferences.current.mediaPreview) { - StatusMediaComponent( - status = status, - ) - } - AnimatedVisibility(visible = !LocalDisplayPreferences.current.mediaPreview) { - CompositionLocalProvider( - LocalContentAlpha provides ContentAlpha.medium - ) { - MediaPreviewButton { - navigator.media(statusKey = status.statusKey) + AnimatedContent(LocalDisplayPreferences.current.mediaPreview) { mediaPreview -> + if (mediaPreview) { + StatusMediaComponent(status = status) + } else { + CompositionLocalProvider( + LocalContentAlpha provides ContentAlpha.medium + ) { + MediaPreviewButton { + navigator.media(statusKey = status.statusKey) + } } } } @@ -654,7 +666,8 @@ fun MediaPreviewButton( onClick.invoke() } ) - .padding(4.dp) + .padding(horizontal = 4.dp) + .height(30.dp) ) { Icon( painter = painterResource(res = com.twidere.twiderex.MR.files.ic_photo), @@ -703,6 +716,7 @@ fun StatusQuote(quote: UiStatus) { StatusText( status = quote, maxLines = 5, + isSelectionAble = false ) StatusBodyMedia(status = quote) }