diff --git a/app/src/main/java/com/nextcloud/talk/ui/ComposeUtils.kt b/app/src/main/java/com/nextcloud/talk/ui/ComposeUtils.kt new file mode 100644 index 00000000000..51f60efab04 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/ui/ComposeUtils.kt @@ -0,0 +1,62 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Julius Linus + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package com.nextcloud.talk.ui + +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.ScrollState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import kotlin.math.min + +private const val SCROLL_DUR = 150 +private const val ANIM_DUR_LONG = 500 +private const val FLOAT_100 = 100f +private const val INT_100 = 100 + +// Adapted from source - https://stackoverflow.com/a/68056586 +@Composable +fun Modifier.customVerticalScrollbar(state: ScrollState, width: Dp = 8.dp, color: Color = Color.Red): Modifier { + val targetAlpha = if (state.isScrollInProgress) 1f else 0f + val duration = if (state.isScrollInProgress) SCROLL_DUR else ANIM_DUR_LONG + val alpha by animateFloatAsState( + targetValue = targetAlpha, + animationSpec = tween(durationMillis = duration) + ) + val cr = CORNER_RADIUS.toFloat() + + return drawWithContent { + drawContent() + + val needDrawScrollbar = state.isScrollInProgress || alpha > 0.0 + + if (needDrawScrollbar) { + val elementHeight = this.size.height + val pinnedViewHeight = MAX_HEIGHT + val scrollBarHeightPercentage = (pinnedViewHeight * FLOAT_100) / elementHeight + val scrollBarHeight = (scrollBarHeightPercentage / INT_100) * pinnedViewHeight + val offset = state.scrollIndicatorState?.scrollOffset?.toFloat() ?: 0f + + drawRoundRect( + color = color, + topLeft = Offset(this.size.width - width.toPx(), min(offset, elementHeight)), + size = Size(width.toPx(), scrollBarHeight), + cornerRadius = CornerRadius(cr, cr), + alpha = alpha + ) + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/ui/PinnedMessage.kt b/app/src/main/java/com/nextcloud/talk/ui/PinnedMessage.kt index 263859ad3c1..c65f8372b75 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/PinnedMessage.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/PinnedMessage.kt @@ -40,6 +40,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.nextcloud.talk.R import com.nextcloud.talk.chat.data.model.ChatMessage @@ -107,6 +108,7 @@ fun PinnedMessageView( .background(incomingBubbleColor, RoundedCornerShape(CORNER_RADIUS.dp)) .padding(SPACE_16.dp) .heightIn(max = MAX_HEIGHT.dp) + .customVerticalScrollbar(scrollState, color = outgoingBubbleColor) .verticalScroll(scrollState) .clickable { scrollToMessageWithIdWithOffset(message.id) @@ -160,7 +162,8 @@ fun PinnedMessageView( text = { Text( text = pinnedText, - color = highEmphasisColor + color = highEmphasisColor, + fontWeight = FontWeight.Bold ) }, onClick = { /* No-op or toggle expansion */ },