Trying to improve rendering speed of chat messages.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.note
|
package com.vitorpamplona.amethyst.ui.note
|
||||||
|
|
||||||
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
@@ -27,7 +28,6 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.ChevronRight
|
import androidx.compose.material.icons.filled.ChevronRight
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
@@ -50,9 +50,9 @@ import androidx.compose.ui.platform.LocalDensity
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.semantics.Role
|
import androidx.compose.ui.semantics.Role
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.IntSize
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.lifecycle.map
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.RelayInformation
|
import com.vitorpamplona.amethyst.model.RelayInformation
|
||||||
@@ -75,21 +75,19 @@ import com.vitorpamplona.amethyst.ui.theme.ChatBubbleMaxSizeModifier
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.ChatBubbleShapeMe
|
import com.vitorpamplona.amethyst.ui.theme.ChatBubbleShapeMe
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ChatBubbleShapeThem
|
import com.vitorpamplona.amethyst.ui.theme.ChatBubbleShapeThem
|
||||||
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.ReactionRowHeightChat
|
||||||
import com.vitorpamplona.amethyst.ui.theme.RelayIconFilter
|
import com.vitorpamplona.amethyst.ui.theme.RelayIconFilter
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size13dp
|
import com.vitorpamplona.amethyst.ui.theme.Size13dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size15Modifier
|
import com.vitorpamplona.amethyst.ui.theme.Size15Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size15dp
|
import com.vitorpamplona.amethyst.ui.theme.Size15dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size16dp
|
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size25dp
|
import com.vitorpamplona.amethyst.ui.theme.Size25dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.StdStartPadding
|
||||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
import com.vitorpamplona.amethyst.ui.theme.subtleBorder
|
import com.vitorpamplona.amethyst.ui.theme.subtleBorder
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
|
||||||
import kotlinx.collections.immutable.persistentSetOf
|
import kotlinx.collections.immutable.persistentSetOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
|
||||||
import kotlinx.collections.immutable.toImmutableSet
|
import kotlinx.collections.immutable.toImmutableSet
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@@ -103,10 +101,12 @@ fun ChatroomMessageCompose(
|
|||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
onWantsToReply: (Note) -> Unit
|
onWantsToReply: (Note) -> Unit
|
||||||
) {
|
) {
|
||||||
val noteState by baseNote.live().metadata.observeAsState()
|
val isBlank by baseNote.live().metadata.map {
|
||||||
val noteEvent = remember(noteState) { noteState?.note?.event }
|
it.note.event == null
|
||||||
|
}.observeAsState(baseNote.event == null)
|
||||||
|
|
||||||
if (noteEvent == null) {
|
Crossfade(targetState = isBlank) {
|
||||||
|
if (it) {
|
||||||
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
||||||
BlankNote(
|
BlankNote(
|
||||||
remember {
|
remember {
|
||||||
@@ -128,6 +128,7 @@ fun ChatroomMessageCompose(
|
|||||||
onWantsToReply
|
onWantsToReply
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -197,7 +198,8 @@ fun LoadedChatMessageCompose(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showHiddenNote) {
|
Crossfade(targetState = showHiddenNote) {
|
||||||
|
if (it) {
|
||||||
HiddenNote(
|
HiddenNote(
|
||||||
state.relevantReports,
|
state.relevantReports,
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
@@ -224,6 +226,7 @@ fun LoadedChatMessageCompose(
|
|||||||
onWantsToReply
|
onWantsToReply
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@@ -299,7 +302,7 @@ fun NormalChatNote(
|
|||||||
modifier = modif,
|
modifier = modif,
|
||||||
horizontalArrangement = alignment
|
horizontalArrangement = alignment
|
||||||
) {
|
) {
|
||||||
val availableBubbleSize = remember { mutableStateOf(IntSize.Zero) }
|
val availableBubbleSize = remember { mutableStateOf(0) }
|
||||||
var popupExpanded by remember { mutableStateOf(false) }
|
var popupExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val modif2 = remember {
|
val modif2 = remember {
|
||||||
@@ -321,7 +324,9 @@ fun NormalChatNote(
|
|||||||
Row(
|
Row(
|
||||||
horizontalArrangement = alignment,
|
horizontalArrangement = alignment,
|
||||||
modifier = modif2.onSizeChanged {
|
modifier = modif2.onSizeChanged {
|
||||||
availableBubbleSize.value = it
|
if (availableBubbleSize.value != it.width) {
|
||||||
|
availableBubbleSize.value = it.width
|
||||||
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
@@ -363,17 +368,19 @@ private fun RenderBubble(
|
|||||||
backgroundBubbleColor: MutableState<Color>,
|
backgroundBubbleColor: MutableState<Color>,
|
||||||
onWantsToReply: (Note) -> Unit,
|
onWantsToReply: (Note) -> Unit,
|
||||||
canPreview: Boolean,
|
canPreview: Boolean,
|
||||||
availableBubbleSize: MutableState<IntSize>,
|
availableBubbleSize: MutableState<Int>,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit
|
nav: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
val bubbleSize = remember { mutableStateOf(IntSize.Zero) }
|
val bubbleSize = remember { mutableStateOf(0) }
|
||||||
|
|
||||||
val bubbleModifier = remember {
|
val bubbleModifier = remember {
|
||||||
Modifier
|
Modifier
|
||||||
.padding(start = 10.dp, end = 5.dp, bottom = 5.dp)
|
.padding(start = 10.dp, end = 5.dp, bottom = 5.dp)
|
||||||
.onSizeChanged {
|
.onSizeChanged {
|
||||||
bubbleSize.value = it
|
if (bubbleSize.value != it.width) {
|
||||||
|
bubbleSize.value = it.width
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,8 +412,8 @@ private fun MessageBubbleLines(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
onWantsToReply: (Note) -> Unit,
|
onWantsToReply: (Note) -> Unit,
|
||||||
canPreview: Boolean,
|
canPreview: Boolean,
|
||||||
bubbleSize: MutableState<IntSize>,
|
bubbleSize: MutableState<Int>,
|
||||||
availableBubbleSize: MutableState<IntSize>
|
availableBubbleSize: MutableState<Int>
|
||||||
) {
|
) {
|
||||||
if (drawAuthorInfo) {
|
if (drawAuthorInfo) {
|
||||||
DrawAuthorInfo(
|
DrawAuthorInfo(
|
||||||
@@ -459,7 +466,7 @@ private fun RenderReplyRow(
|
|||||||
) {
|
) {
|
||||||
val hasReply by remember {
|
val hasReply by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
innerQuote && note.replyTo?.lastOrNull() != null
|
!innerQuote && note.replyTo?.lastOrNull() != null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,23 +536,22 @@ private fun NoteRow(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ConstrainedStatusRow(
|
private fun ConstrainedStatusRow(
|
||||||
bubbleSize: MutableState<IntSize>,
|
bubbleSize: MutableState<Int>,
|
||||||
availableBubbleSize: MutableState<IntSize>,
|
availableBubbleSize: MutableState<Int>,
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
modifier = Modifier
|
modifier = with(LocalDensity.current) {
|
||||||
|
Modifier
|
||||||
|
.height(26.dp)
|
||||||
.padding(top = 5.dp)
|
.padding(top = 5.dp)
|
||||||
.then(
|
.widthIn(
|
||||||
with(LocalDensity.current) {
|
bubbleSize.value.toDp(),
|
||||||
Modifier.widthIn(
|
availableBubbleSize.value.toDp()
|
||||||
bubbleSize.value.width.toDp(),
|
|
||||||
availableBubbleSize.value.width.toDp()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
content()
|
content()
|
||||||
}
|
}
|
||||||
@@ -558,29 +564,30 @@ private fun StatusRow(
|
|||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
onWantsToReply: (Note) -> Unit
|
onWantsToReply: (Note) -> Unit
|
||||||
) {
|
) {
|
||||||
Column {
|
Column(modifier = ReactionRowHeightChat) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically, modifier = ReactionRowHeightChat) {
|
||||||
ChatTimeAgo(baseNote)
|
ChatTimeAgo(baseNote)
|
||||||
RelayBadges(baseNote, accountViewModel, nav = nav)
|
RelayBadges(baseNote, accountViewModel, nav = nav)
|
||||||
Spacer(modifier = DoubleHorzSpacer)
|
Spacer(modifier = DoubleHorzSpacer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column(modifier = ReactionRowHeightChat) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically, modifier = ReactionRowHeightChat) {
|
||||||
LikeReaction(baseNote, MaterialTheme.colors.placeholderText, accountViewModel)
|
LikeReaction(baseNote, MaterialTheme.colors.placeholderText, accountViewModel)
|
||||||
Spacer(modifier = StdHorzSpacer)
|
Spacer(modifier = StdHorzSpacer)
|
||||||
ZapReaction(baseNote, MaterialTheme.colors.placeholderText, accountViewModel)
|
ZapReaction(baseNote, MaterialTheme.colors.placeholderText, accountViewModel)
|
||||||
Spacer(modifier = StdHorzSpacer)
|
Spacer(modifier = DoubleHorzSpacer)
|
||||||
ReplyReaction(
|
ReplyReaction(
|
||||||
baseNote = baseNote,
|
baseNote = baseNote,
|
||||||
grayTint = MaterialTheme.colors.placeholderText,
|
grayTint = MaterialTheme.colors.placeholderText,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
showCounter = false,
|
showCounter = false,
|
||||||
iconSize = Size16dp
|
iconSize = Size15dp
|
||||||
) {
|
) {
|
||||||
onWantsToReply(baseNote)
|
onWantsToReply(baseNote)
|
||||||
}
|
}
|
||||||
|
Spacer(modifier = StdHorzSpacer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -800,44 +807,54 @@ private fun DisplayMessageUsername(
|
|||||||
DrawPlayName(userDisplayName)
|
DrawPlayName(userDisplayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Immutable
|
@Composable
|
||||||
data class RelayBadgesState(
|
private fun RelayBadges(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||||
val shouldDisplayExpandButton: Boolean,
|
val expanded = remember { mutableStateOf(false) }
|
||||||
val noteRelays: ImmutableList<String>,
|
|
||||||
val noteRelaysSimple: ImmutableList<String>
|
RenderRelayList(baseNote, expanded, accountViewModel, nav)
|
||||||
)
|
|
||||||
|
RenderExpandButton(baseNote, expanded) {
|
||||||
|
ChatRelayExpandButton { expanded.value = true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun RelayBadges(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
fun RenderRelayList(baseNote: Note, expanded: MutableState<Boolean>, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||||
val noteRelaysState by baseNote.live().relays.observeAsState()
|
val noteRelays by baseNote.live().relays.map {
|
||||||
|
it.note.relays
|
||||||
|
}.observeAsState(baseNote.relays)
|
||||||
|
|
||||||
val state: RelayBadgesState by remember(noteRelaysState) {
|
FlowRow(StdStartPadding) {
|
||||||
val newShouldDisplayExpandButton = (noteRelaysState?.note?.relays?.size ?: 0) > 3
|
val relaysToDisplay = remember(noteRelays, expanded.value) {
|
||||||
val noteRelays = noteRelaysState?.note?.relays?.toImmutableList() ?: persistentListOf()
|
if (expanded.value) noteRelays else noteRelays.take(3)
|
||||||
val noteRelaysSimple = noteRelaysState?.note?.relays?.take(3)?.toImmutableList() ?: persistentListOf()
|
|
||||||
|
|
||||||
mutableStateOf(RelayBadgesState(newShouldDisplayExpandButton, noteRelays, noteRelaysSimple))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var expanded by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
val relaysToDisplay by remember(noteRelaysState) {
|
|
||||||
derivedStateOf {
|
|
||||||
if (expanded) state.noteRelays else state.noteRelaysSimple
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FlowRow(Modifier.padding(start = 10.dp)) {
|
|
||||||
relaysToDisplay.forEach {
|
relaysToDisplay.forEach {
|
||||||
RenderRelay(it, accountViewModel, nav)
|
RenderRelay(it, accountViewModel, nav)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (state.shouldDisplayExpandButton && !expanded) {
|
@Composable
|
||||||
|
fun RenderExpandButton(
|
||||||
|
baseNote: Note,
|
||||||
|
expanded: MutableState<Boolean>,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
val showExpandButton by baseNote.live().relays.map {
|
||||||
|
it.note.relays.size > 3
|
||||||
|
}.observeAsState(baseNote.relays.size > 3)
|
||||||
|
|
||||||
|
if (showExpandButton && !expanded.value) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ChatRelayExpandButton(onClick: () -> Unit) {
|
||||||
IconButton(
|
IconButton(
|
||||||
modifier = Size15Modifier,
|
modifier = Size15Modifier,
|
||||||
onClick = { expanded = true }
|
onClick = onClick
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.ChevronRight,
|
imageVector = Icons.Default.ChevronRight,
|
||||||
@@ -846,7 +863,6 @@ private fun RelayBadges(baseNote: Note, accountViewModel: AccountViewModel, nav:
|
|||||||
tint = MaterialTheme.colors.placeholderText
|
tint = MaterialTheme.colors.placeholderText
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ val WidthAuthorPictureModifier = Modifier.width(55.dp)
|
|||||||
val DiviserThickness = 0.25.dp
|
val DiviserThickness = 0.25.dp
|
||||||
|
|
||||||
val ReactionRowHeight = Modifier.height(24.dp).padding(start = 10.dp)
|
val ReactionRowHeight = Modifier.height(24.dp).padding(start = 10.dp)
|
||||||
|
val ReactionRowHeightChat = Modifier.height(25.dp)
|
||||||
|
|
||||||
val Height4dpModifier = Modifier.height(4.dp)
|
val Height4dpModifier = Modifier.height(4.dp)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user