Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions app/src/main/java/com/nextcloud/talk/ui/ComposeUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2026 Julius Linus <[email protected]>
* 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
)
}
}
}
5 changes: 4 additions & 1 deletion app/src/main/java/com/nextcloud/talk/ui/PinnedMessage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -160,7 +162,8 @@ fun PinnedMessageView(
text = {
Text(
text = pinnedText,
color = highEmphasisColor
color = highEmphasisColor,
fontWeight = FontWeight.Bold
)
},
onClick = { /* No-op or toggle expansion */ },
Expand Down
Loading