fix mentions

This commit is contained in:
callebtc 2026-07-27 15:32:33 +02:00
parent 4863381dbb
commit b1d709fc4a
2 changed files with 91 additions and 13 deletions

View File

@ -1,6 +1,5 @@
package com.bitchat.android.ui
import com.bitchat.android.ui.theme.BitchatFontFamily
import com.bitchat.android.ui.theme.BitchatFontFamily
// [Goose] Bridge file share events to ViewModel via dispatcher is installed in ChatScreen composition
@ -593,14 +592,47 @@ fun ChatInputSection(
)
HorizontalDivider(thickness = 1.dp, color = palette.outlineVariant)
}
// Mention suggestions box
if (showMentionSuggestions && mentionSuggestions.isNotEmpty()) {
MentionSuggestionsBox(
suggestions = mentionSuggestions,
onSuggestionClick = onMentionSuggestionClick,
modifier = Modifier.fillMaxWidth()
)
HorizontalDivider(thickness = 1.dp, color = palette.outlineVariant)
// Retain the final populated list while the picker exits. The state layer clears
// suggestions together with visibility; without this snapshot the panel would empty and
// snap shut before its shrink/fade animation had a frame to run.
var retainedMentionSuggestions by remember { mutableStateOf(emptyList<String>()) }
LaunchedEffect(mentionSuggestions) {
if (mentionSuggestions.isNotEmpty()) {
retainedMentionSuggestions = mentionSuggestions
}
}
val mentionPickerVisible = showMentionSuggestions && mentionSuggestions.isNotEmpty()
val displayedMentionSuggestions = mentionSuggestions.ifEmpty {
retainedMentionSuggestions
}
AnimatedVisibility(
visible = mentionPickerVisible,
enter = fadeIn(tween(BitchatMotion.STANDARD_MS)) +
expandVertically(
animationSpec = tween(
BitchatMotion.STANDARD_MS,
easing = FastOutSlowInEasing
),
expandFrom = Alignment.Bottom
),
exit = fadeOut(tween(BitchatMotion.QUICK_MS)) +
shrinkVertically(
animationSpec = tween(
BitchatMotion.QUICK_MS,
easing = FastOutSlowInEasing
),
shrinkTowards = Alignment.Bottom
)
) {
Column {
MentionSuggestionsBox(
suggestions = displayedMentionSuggestions,
onSuggestionClick = onMentionSuggestionClick,
modifier = Modifier.fillMaxWidth()
)
HorizontalDivider(thickness = 1.dp, color = palette.outlineVariant)
}
}
MessageInput(
value = messageText,

View File

@ -19,9 +19,11 @@ import androidx.compose.animation.core.tween
import androidx.compose.animation.expandHorizontally
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.expandVertically
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.shrinkHorizontally
import androidx.compose.animation.shrinkVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.*
import androidx.compose.foundation.interaction.MutableInteractionSource
@ -700,6 +702,7 @@ fun CommandSuggestionItem(
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MentionSuggestionsBox(
suggestions: List<String>,
@ -711,6 +714,12 @@ fun MentionSuggestionsBox(
LazyColumn(
modifier = modifier
.heightIn(max = MentionSuggestionsMaxHeight)
.animateContentSize(
animationSpec = tween(
BitchatMotion.STANDARD_MS,
easing = FastOutSlowInEasing
)
)
.clip(MentionSuggestionsShape)
.background(palette.surface)
.border(1.dp, palette.outlineVariant, MentionSuggestionsShape),
@ -722,7 +731,18 @@ fun MentionSuggestionsBox(
) { suggestion ->
MentionSuggestionItem(
suggestion = suggestion,
onClick = { onSuggestionClick(suggestion) }
onClick = { onSuggestionClick(suggestion) },
modifier = Modifier.animateItem(
fadeInSpec = tween(
BitchatMotion.STANDARD_MS,
easing = FastOutSlowInEasing
),
placementSpec = tween(
BitchatMotion.STANDARD_MS,
easing = FastOutSlowInEasing
),
fadeOutSpec = tween(BitchatMotion.QUICK_MS)
)
)
}
}
@ -731,15 +751,41 @@ fun MentionSuggestionsBox(
@Composable
fun MentionSuggestionItem(
suggestion: String,
onClick: () -> Unit
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
val palette = LocalBitchatPalette.current
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()
val pressedBackground by animateColorAsState(
targetValue = if (isPressed) {
palette.accentOrange.copy(alpha = 0.10f)
} else {
Color.Transparent
},
animationSpec = tween(BitchatMotion.QUICK_MS, easing = FastOutSlowInEasing),
label = "mentionSuggestionPressedBackground"
)
val pressedScale by animateFloatAsState(
targetValue = if (isPressed) 0.985f else 1f,
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessHigh
),
label = "mentionSuggestionPressedScale"
)
Row(
modifier = Modifier
modifier = modifier
.fillMaxWidth()
.height(MentionSuggestionRowHeight)
.clickable { onClick() }
.scale(pressedScale)
.background(pressedBackground)
.clickable(
interactionSource = interactionSource,
indication = null,
onClick = onClick
)
.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {