v1.2.7: поиск сообщений, скелетон, анимация перехода и правка бейджа Requests
This commit is contained in:
@@ -1377,8 +1377,35 @@ fun ChatDetailScreen(
|
||||
isDarkTheme
|
||||
)
|
||||
|
||||
// Smooth transition when switching to another dialog from in-message mentions/tags.
|
||||
// SwipeBackContainer stays mounted, so we animate content change locally.
|
||||
var runDialogSwitchEnterAnimation by remember(user.publicKey) { mutableStateOf(false) }
|
||||
LaunchedEffect(user.publicKey) {
|
||||
runDialogSwitchEnterAnimation = false
|
||||
withFrameNanos { }
|
||||
runDialogSwitchEnterAnimation = true
|
||||
}
|
||||
val dialogSwitchAlpha by
|
||||
animateFloatAsState(
|
||||
targetValue = if (runDialogSwitchEnterAnimation) 1f else 0.9f,
|
||||
animationSpec = tween(durationMillis = 240),
|
||||
label = "dialogSwitchAlpha"
|
||||
)
|
||||
val dialogSwitchOffsetX by
|
||||
animateDpAsState(
|
||||
targetValue = if (runDialogSwitchEnterAnimation) 0.dp else 24.dp,
|
||||
animationSpec = tween(durationMillis = 240),
|
||||
label = "dialogSwitchOffsetX"
|
||||
)
|
||||
|
||||
// 🚀 Весь контент (swipe-back обрабатывается в SwipeBackContainer)
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
Box(
|
||||
modifier =
|
||||
Modifier.fillMaxSize().graphicsLayer {
|
||||
alpha = dialogSwitchAlpha
|
||||
translationX = with(density) { dialogSwitchOffsetX.toPx() }
|
||||
}
|
||||
) {
|
||||
// Telegram-style solid header background (без blur)
|
||||
val headerBackground = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFF228BE6)
|
||||
|
||||
|
||||
@@ -1612,6 +1612,8 @@ fun ChatsListScreen(
|
||||
}
|
||||
}
|
||||
val badgeBg = Color.White
|
||||
val badgeTextColor =
|
||||
if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFF228BE6)
|
||||
val badgeShape = RoundedCornerShape(50)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
@@ -1630,7 +1632,7 @@ fun ChatsListScreen(
|
||||
text = badgeText,
|
||||
fontSize = 10.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Color(0xFF228BE6),
|
||||
color = badgeTextColor,
|
||||
lineHeight = 10.sp,
|
||||
modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp)
|
||||
)
|
||||
|
||||
@@ -1146,27 +1146,7 @@ private fun MessagesTabContent(
|
||||
}
|
||||
}
|
||||
isSearching -> {
|
||||
// Loading state
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.imePadding(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(32.dp),
|
||||
color = PrimaryBlue,
|
||||
strokeWidth = 2.5.dp
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(
|
||||
text = "Searching messages...",
|
||||
fontSize = 14.sp,
|
||||
color = secondaryTextColor
|
||||
)
|
||||
}
|
||||
}
|
||||
MessageSearchSkeleton(isDarkTheme = isDarkTheme)
|
||||
}
|
||||
results.isEmpty() -> {
|
||||
// No results
|
||||
@@ -1236,6 +1216,107 @@ private fun MessagesTabContent(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MessageSearchSkeleton(isDarkTheme: Boolean) {
|
||||
val shimmerColor = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFE8E8E8)
|
||||
val highlightColor = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFF5F5F5)
|
||||
val dividerColor = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFE8E8E8)
|
||||
|
||||
val transition = rememberInfiniteTransition(label = "message_search_shimmer")
|
||||
val translateAnim by transition.animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = 1000f,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(durationMillis = 1200, easing = LinearEasing),
|
||||
repeatMode = RepeatMode.Restart
|
||||
),
|
||||
label = "message_search_shimmer_translate"
|
||||
)
|
||||
|
||||
val shimmerBrush = androidx.compose.ui.graphics.Brush.linearGradient(
|
||||
colors = listOf(shimmerColor, highlightColor, shimmerColor),
|
||||
start = androidx.compose.ui.geometry.Offset(translateAnim - 200f, 0f),
|
||||
end = androidx.compose.ui.geometry.Offset(translateAnim, 0f)
|
||||
)
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize().imePadding(),
|
||||
contentPadding = PaddingValues(vertical = 4.dp)
|
||||
) {
|
||||
items(8) { index ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box(
|
||||
modifier =
|
||||
Modifier.size(48.dp)
|
||||
.clip(CircleShape)
|
||||
.background(shimmerBrush)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth(
|
||||
fraction = if (index % 2 == 0) 0.48f else 0.62f
|
||||
)
|
||||
.height(14.dp)
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(shimmerBrush)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Box(
|
||||
modifier =
|
||||
Modifier.width(if (index % 2 == 0) 58.dp else 50.dp)
|
||||
.height(12.dp)
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(shimmerBrush)
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Box(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth(
|
||||
fraction = if (index % 2 == 0) 0.86f else 0.74f
|
||||
)
|
||||
.height(12.dp)
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(shimmerBrush)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(6.dp))
|
||||
Box(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth(
|
||||
fraction = if (index % 2 == 0) 0.67f else 0.79f
|
||||
)
|
||||
.height(12.dp)
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(shimmerBrush)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Divider(
|
||||
color = dividerColor,
|
||||
thickness = 0.5.dp,
|
||||
modifier = Modifier.padding(start = 76.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MessageSearchResultItem(
|
||||
result: MessageSearchResult,
|
||||
|
||||
Reference in New Issue
Block a user