feat: Update menu icon color for improved visibility in ChatsListScreen
This commit is contained in:
@@ -105,7 +105,7 @@ fun SetPasswordScreen(
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = "Back",
|
||||
tint = textColor
|
||||
tint = textColor.copy(alpha = 0.6f)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
@@ -285,7 +285,7 @@ fun UnlockScreen(
|
||||
Icon(
|
||||
imageVector = Icons.Default.KeyboardArrowDown,
|
||||
contentDescription = null,
|
||||
tint = secondaryTextColor,
|
||||
tint = secondaryTextColor.copy(alpha = 0.6f),
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.graphicsLayer {
|
||||
@@ -332,7 +332,7 @@ fun UnlockScreen(
|
||||
Icon(
|
||||
Icons.Default.Search,
|
||||
contentDescription = null,
|
||||
tint = secondaryTextColor
|
||||
tint = secondaryTextColor.copy(alpha = 0.6f)
|
||||
)
|
||||
},
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
|
||||
@@ -80,7 +80,7 @@ fun WelcomeScreen(
|
||||
Icon(
|
||||
Icons.Default.ArrowBack,
|
||||
contentDescription = "Back",
|
||||
tint = textColor
|
||||
tint = textColor.copy(alpha = 0.6f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,7 +802,7 @@ fun ChatDetailScreen(
|
||||
Icon(
|
||||
Icons.Default.Call,
|
||||
contentDescription = "Call",
|
||||
tint = headerIconColor
|
||||
tint = headerIconColor.copy(alpha = 0.6f)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -826,7 +826,7 @@ fun ChatDetailScreen(
|
||||
Icon(
|
||||
Icons.Default.MoreVert,
|
||||
contentDescription = "More",
|
||||
tint = headerIconColor,
|
||||
tint = headerIconColor.copy(alpha = 0.6f),
|
||||
modifier = Modifier.size(26.dp)
|
||||
)
|
||||
}
|
||||
@@ -2480,7 +2480,7 @@ private fun MessageInputBar(
|
||||
Icon(
|
||||
Icons.Default.AttachFile,
|
||||
contentDescription = "Attach",
|
||||
tint = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF8E8E93),
|
||||
tint = if (isDarkTheme) Color(0xFF8E8E93).copy(alpha = 0.6f) else Color(0xFF8E8E93).copy(alpha = 0.6f),
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
@@ -2534,7 +2534,7 @@ private fun MessageInputBar(
|
||||
if (showEmojiPicker) Icons.Default.Keyboard
|
||||
else Icons.Default.SentimentSatisfiedAlt,
|
||||
contentDescription = "Emoji",
|
||||
tint = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF8E8E93),
|
||||
tint = if (isDarkTheme) Color(0xFF8E8E93).copy(alpha = 0.6f) else Color(0xFF8E8E93).copy(alpha = 0.6f),
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.rosetta.messenger.ui.chats
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
@@ -19,26 +21,19 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import android.content.Context
|
||||
import com.airbnb.lottie.compose.*
|
||||
import com.rosetta.messenger.R
|
||||
import com.rosetta.messenger.data.RecentSearchesManager
|
||||
import com.rosetta.messenger.database.RosettaDatabase
|
||||
import com.rosetta.messenger.network.ProtocolManager
|
||||
import com.rosetta.messenger.network.ProtocolState
|
||||
import com.rosetta.messenger.ui.components.AppleEmojiText
|
||||
@@ -255,33 +250,33 @@ fun ChatsListScreen(
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(max = 500.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxWidth().heightIn(max = 500.dp)) {
|
||||
// Status indicator
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 12.dp)
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 12.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(12.dp)
|
||||
modifier =
|
||||
Modifier.size(12.dp)
|
||||
.clip(CircleShape)
|
||||
.background(
|
||||
when (protocolState) {
|
||||
ProtocolState.AUTHENTICATED -> Color(0xFF4CAF50)
|
||||
ProtocolState.CONNECTING, ProtocolState.CONNECTED, ProtocolState.HANDSHAKING -> Color(0xFFFFC107)
|
||||
ProtocolState.DISCONNECTED -> Color(0xFFF44336)
|
||||
ProtocolState.AUTHENTICATED ->
|
||||
Color(0xFF4CAF50)
|
||||
ProtocolState.CONNECTING,
|
||||
ProtocolState.CONNECTED,
|
||||
ProtocolState.HANDSHAKING ->
|
||||
Color(0xFFFFC107)
|
||||
ProtocolState.DISCONNECTED ->
|
||||
Color(0xFFF44336)
|
||||
}
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Text(
|
||||
text = when (protocolState) {
|
||||
text =
|
||||
when (protocolState) {
|
||||
ProtocolState.DISCONNECTED -> "Disconnected"
|
||||
ProtocolState.CONNECTING -> "Connecting..."
|
||||
ProtocolState.CONNECTED -> "Connected"
|
||||
@@ -301,9 +296,7 @@ fun ChatsListScreen(
|
||||
|
||||
// Logs header with copy button
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 8.dp),
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
@@ -316,30 +309,38 @@ fun ChatsListScreen(
|
||||
TextButton(
|
||||
onClick = {
|
||||
val logsText = debugLogs.joinToString("\n")
|
||||
clipboardManager.setText(androidx.compose.ui.text.AnnotatedString(logsText))
|
||||
clipboardManager.setText(
|
||||
androidx.compose.ui.text.AnnotatedString(logsText)
|
||||
)
|
||||
android.widget.Toast.makeText(
|
||||
context,
|
||||
"Logs copied to clipboard!",
|
||||
android.widget.Toast.LENGTH_SHORT
|
||||
).show()
|
||||
)
|
||||
.show()
|
||||
},
|
||||
enabled = debugLogs.isNotEmpty()
|
||||
) {
|
||||
Text(
|
||||
"Copy All",
|
||||
fontSize = 12.sp,
|
||||
color = if (debugLogs.isNotEmpty()) PrimaryBlue else Color.Gray
|
||||
color =
|
||||
if (debugLogs.isNotEmpty()) PrimaryBlue
|
||||
else Color.Gray
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Logs content
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.weight(1f, fill = false)
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFF5F5F5))
|
||||
.background(
|
||||
if (isDarkTheme) Color(0xFF1A1A1A)
|
||||
else Color(0xFFF5F5F5)
|
||||
)
|
||||
.padding(8.dp)
|
||||
) {
|
||||
if (debugLogs.isEmpty()) {
|
||||
@@ -351,9 +352,8 @@ fun ChatsListScreen(
|
||||
)
|
||||
} else {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.verticalScroll(scrollState)
|
||||
modifier =
|
||||
Modifier.fillMaxWidth().verticalScroll(scrollState)
|
||||
) {
|
||||
debugLogs.forEach { log ->
|
||||
Text(
|
||||
@@ -361,8 +361,8 @@ fun ChatsListScreen(
|
||||
fontSize = 11.sp,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
color = textColor,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.padding(vertical = 2.dp)
|
||||
)
|
||||
}
|
||||
@@ -376,18 +376,20 @@ fun ChatsListScreen(
|
||||
ProtocolManager.enableUILogs(!debugLogs.isNotEmpty())
|
||||
android.widget.Toast.makeText(
|
||||
context,
|
||||
if (debugLogs.isEmpty()) "Logs enabled" else "Logs disabled",
|
||||
if (debugLogs.isEmpty()) "Logs enabled"
|
||||
else "Logs disabled",
|
||||
android.widget.Toast.LENGTH_SHORT
|
||||
).show()
|
||||
)
|
||||
.show()
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp)
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 8.dp)
|
||||
) {
|
||||
Text(
|
||||
if (debugLogs.isEmpty()) "⚠️ Enable Logs" else "Disable Logs",
|
||||
fontSize = 12.sp,
|
||||
color = if (debugLogs.isEmpty()) Color(0xFFFFC107) else Color.Gray
|
||||
color =
|
||||
if (debugLogs.isEmpty()) Color(0xFFFFC107)
|
||||
else Color.Gray
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -395,12 +397,8 @@ fun ChatsListScreen(
|
||||
confirmButton = {
|
||||
Button(
|
||||
onClick = { showStatusDialog = false },
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = PrimaryBlue
|
||||
)
|
||||
) {
|
||||
Text("Close", color = Color.White)
|
||||
}
|
||||
colors = ButtonDefaults.buttonColors(containerColor = PrimaryBlue)
|
||||
) { Text("Close", color = Color.White) }
|
||||
},
|
||||
containerColor = if (isDarkTheme) Color(0xFF212121) else Color.White
|
||||
)
|
||||
@@ -413,28 +411,31 @@ fun ChatsListScreen(
|
||||
drawerContent = {
|
||||
ModalDrawerSheet(
|
||||
drawerContainerColor = Color.Transparent,
|
||||
windowInsets = WindowInsets(0), // 🎨 Убираем системные отступы - drawer идет до верха
|
||||
windowInsets =
|
||||
WindowInsets(
|
||||
0
|
||||
), // 🎨 Убираем системные отступы - drawer идет до верха
|
||||
modifier = Modifier.width(300.dp)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(drawerBackgroundColor)
|
||||
modifier = Modifier.fillMaxSize().background(drawerBackgroundColor)
|
||||
) {
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 🎨 DRAWER HEADER - Avatar and status
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
val headerColor = if (isDarkTheme) {
|
||||
val headerColor =
|
||||
if (isDarkTheme) {
|
||||
Color(0xFF2C5282)
|
||||
} else {
|
||||
Color(0xFF4A90D9)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.background(color = headerColor)
|
||||
.statusBarsPadding() // 🎨 Контент начинается после status bar
|
||||
.statusBarsPadding() // 🎨 Контент начинается
|
||||
// после status bar
|
||||
.padding(
|
||||
top = 16.dp,
|
||||
start = 20.dp,
|
||||
@@ -446,13 +447,17 @@ fun ChatsListScreen(
|
||||
// Avatar with border
|
||||
val avatarColors = getAvatarColor(accountPublicKey, isDarkTheme)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(72.dp)
|
||||
modifier =
|
||||
Modifier.size(72.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color.White.copy(alpha = 0.2f))
|
||||
.background(
|
||||
Color.White.copy(alpha = 0.2f)
|
||||
)
|
||||
.padding(3.dp)
|
||||
.clip(CircleShape)
|
||||
.background(avatarColors.backgroundColor),
|
||||
.background(
|
||||
avatarColors.backgroundColor
|
||||
),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
@@ -488,12 +493,30 @@ fun ChatsListScreen(
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = Color.White,
|
||||
fontStyle = if (isCopied) androidx.compose.ui.text.font.FontStyle.Italic else androidx.compose.ui.text.font.FontStyle.Normal,
|
||||
modifier = Modifier.clickable {
|
||||
fontStyle =
|
||||
if (isCopied)
|
||||
androidx.compose.ui.text.font
|
||||
.FontStyle.Italic
|
||||
else
|
||||
androidx.compose.ui.text.font
|
||||
.FontStyle.Normal,
|
||||
modifier =
|
||||
Modifier.clickable {
|
||||
if (!showCopiedToast) {
|
||||
// Копируем публичный ключ
|
||||
val clipboard = context.getSystemService(android.content.Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
|
||||
val clip = android.content.ClipData.newPlainText("Public Key", accountPublicKey)
|
||||
val clipboard =
|
||||
context.getSystemService(
|
||||
android.content
|
||||
.Context
|
||||
.CLIPBOARD_SERVICE
|
||||
) as
|
||||
android.content.ClipboardManager
|
||||
val clip =
|
||||
android.content.ClipData
|
||||
.newPlainText(
|
||||
"Public Key",
|
||||
accountPublicKey
|
||||
)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
showCopiedToast = true
|
||||
}
|
||||
@@ -514,22 +537,29 @@ fun ChatsListScreen(
|
||||
// Connection status indicator
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.clickable { showStatusDialog = true }
|
||||
modifier =
|
||||
Modifier.clickable { showStatusDialog = true }
|
||||
) {
|
||||
val statusColor = when (protocolState) {
|
||||
val statusColor =
|
||||
when (protocolState) {
|
||||
ProtocolState.AUTHENTICATED -> Color(0xFF4ADE80)
|
||||
ProtocolState.CONNECTING, ProtocolState.CONNECTED, ProtocolState.HANDSHAKING -> Color(0xFFFBBF24)
|
||||
ProtocolState.CONNECTING,
|
||||
ProtocolState.CONNECTED,
|
||||
ProtocolState.HANDSHAKING -> Color(0xFFFBBF24)
|
||||
else -> Color(0xFFF87171)
|
||||
}
|
||||
val statusText = when (protocolState) {
|
||||
val statusText =
|
||||
when (protocolState) {
|
||||
ProtocolState.AUTHENTICATED -> "Online"
|
||||
ProtocolState.CONNECTING, ProtocolState.CONNECTED, ProtocolState.HANDSHAKING -> "Connecting..."
|
||||
ProtocolState.CONNECTING,
|
||||
ProtocolState.CONNECTED,
|
||||
ProtocolState.HANDSHAKING -> "Connecting..."
|
||||
else -> "Offline"
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(8.dp)
|
||||
modifier =
|
||||
Modifier.size(8.dp)
|
||||
.clip(CircleShape)
|
||||
.background(statusColor)
|
||||
)
|
||||
@@ -547,13 +577,13 @@ fun ChatsListScreen(
|
||||
// 📱 MENU ITEMS
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(vertical = 8.dp)
|
||||
) {
|
||||
val menuIconColor = if (isDarkTheme) Color(0xFFB0B0B0) else Color(0xFF5C5C5C)
|
||||
val menuIconColor = textColor.copy(alpha = 0.6f)
|
||||
|
||||
// 👤 Profile Section
|
||||
DrawerMenuItemEnhanced(
|
||||
@@ -633,7 +663,9 @@ fun ChatsListScreen(
|
||||
|
||||
// 🌓 Theme Toggle
|
||||
DrawerMenuItemEnhanced(
|
||||
icon = if (isDarkTheme) Icons.Outlined.LightMode else Icons.Outlined.DarkMode,
|
||||
icon =
|
||||
if (isDarkTheme) Icons.Outlined.LightMode
|
||||
else Icons.Outlined.DarkMode,
|
||||
text = if (isDarkTheme) "Light Mode" else "Dark Mode",
|
||||
iconColor = menuIconColor,
|
||||
textColor = textColor,
|
||||
@@ -656,11 +688,11 @@ fun ChatsListScreen(
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 🚪 FOOTER - Logout & Version
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
Divider(
|
||||
color = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFE8E8E8),
|
||||
color =
|
||||
if (isDarkTheme) Color(0xFF2A2A2A)
|
||||
else Color(0xFFE8E8E8),
|
||||
thickness = 0.5.dp
|
||||
)
|
||||
|
||||
@@ -681,15 +713,20 @@ fun ChatsListScreen(
|
||||
|
||||
// Version info
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp, vertical = 12.dp),
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.padding(
|
||||
horizontal = 20.dp,
|
||||
vertical = 12.dp
|
||||
),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
Text(
|
||||
text = "Rosetta v1.0.0",
|
||||
fontSize = 12.sp,
|
||||
color = if (isDarkTheme) Color(0xFF666666) else Color(0xFF999999)
|
||||
color =
|
||||
if (isDarkTheme) Color(0xFF666666)
|
||||
else Color(0xFF999999)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -703,19 +740,27 @@ fun ChatsListScreen(
|
||||
topBar = {
|
||||
AnimatedVisibility(
|
||||
visible = visible,
|
||||
enter = fadeIn(tween(300)) + expandVertically(
|
||||
animationSpec = tween(300, easing = FastOutSlowInEasing)
|
||||
),
|
||||
exit = fadeOut(tween(200)) + shrinkVertically(
|
||||
animationSpec = tween(200)
|
||||
enter =
|
||||
fadeIn(tween(300)) +
|
||||
expandVertically(
|
||||
animationSpec =
|
||||
tween(
|
||||
300,
|
||||
easing = FastOutSlowInEasing
|
||||
)
|
||||
),
|
||||
exit =
|
||||
fadeOut(tween(200)) +
|
||||
shrinkVertically(animationSpec = tween(200))
|
||||
) {
|
||||
key(isDarkTheme, showRequestsScreen) {
|
||||
TopAppBar(
|
||||
navigationIcon = {
|
||||
if (showRequestsScreen) {
|
||||
// Back button for Requests
|
||||
IconButton(onClick = { showRequestsScreen = false }) {
|
||||
IconButton(
|
||||
onClick = { showRequestsScreen = false }
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.ArrowBack,
|
||||
contentDescription = "Back",
|
||||
@@ -732,7 +777,7 @@ fun ChatsListScreen(
|
||||
Icon(
|
||||
Icons.Default.Menu,
|
||||
contentDescription = "Menu",
|
||||
tint = textColor
|
||||
tint = textColor.copy(alpha = 0.6f)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -749,7 +794,8 @@ fun ChatsListScreen(
|
||||
} else {
|
||||
// Rosetta title with status
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
verticalAlignment =
|
||||
Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
"Rosetta",
|
||||
@@ -759,17 +805,37 @@ fun ChatsListScreen(
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(10.dp)
|
||||
modifier =
|
||||
Modifier.size(10.dp)
|
||||
.clip(CircleShape)
|
||||
.background(
|
||||
when (protocolState) {
|
||||
ProtocolState.AUTHENTICATED -> Color(0xFF4CAF50)
|
||||
ProtocolState.CONNECTING, ProtocolState.CONNECTED, ProtocolState.HANDSHAKING -> Color(0xFFFFC107)
|
||||
ProtocolState.DISCONNECTED -> Color(0xFFF44336)
|
||||
when (protocolState
|
||||
) {
|
||||
ProtocolState
|
||||
.AUTHENTICATED ->
|
||||
Color(
|
||||
0xFF4CAF50
|
||||
)
|
||||
ProtocolState
|
||||
.CONNECTING,
|
||||
ProtocolState
|
||||
.CONNECTED,
|
||||
ProtocolState
|
||||
.HANDSHAKING ->
|
||||
Color(
|
||||
0xFFFFC107
|
||||
)
|
||||
ProtocolState
|
||||
.DISCONNECTED ->
|
||||
Color(
|
||||
0xFFF44336
|
||||
)
|
||||
}
|
||||
)
|
||||
.clickable { showStatusDialog = true }
|
||||
.clickable {
|
||||
showStatusDialog =
|
||||
true
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -779,22 +845,36 @@ fun ChatsListScreen(
|
||||
if (!showRequestsScreen) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (protocolState == ProtocolState.AUTHENTICATED) {
|
||||
if (protocolState ==
|
||||
ProtocolState
|
||||
.AUTHENTICATED
|
||||
) {
|
||||
onSearchClick()
|
||||
}
|
||||
},
|
||||
enabled = protocolState == ProtocolState.AUTHENTICATED
|
||||
enabled =
|
||||
protocolState ==
|
||||
ProtocolState.AUTHENTICATED
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Search,
|
||||
contentDescription = "Search",
|
||||
tint = if (protocolState == ProtocolState.AUTHENTICATED)
|
||||
textColor else textColor.copy(alpha = 0.5f)
|
||||
tint =
|
||||
if (protocolState ==
|
||||
ProtocolState
|
||||
.AUTHENTICATED
|
||||
)
|
||||
textColor.copy(alpha = 0.6f)
|
||||
else
|
||||
textColor.copy(
|
||||
alpha = 0.5f
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
colors =
|
||||
TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = backgroundColor,
|
||||
scrolledContainerColor = backgroundColor,
|
||||
navigationIconContentColor = textColor,
|
||||
@@ -829,7 +909,8 @@ fun ChatsListScreen(
|
||||
// Main content
|
||||
Box(modifier = Modifier.fillMaxSize().padding(paddingValues)) {
|
||||
// <20> Используем комбинированное состояние для атомарного обновления
|
||||
// Это предотвращает "дергание" UI когда dialogs и requests обновляются независимо
|
||||
// Это предотвращает "дергание" UI когда dialogs и requests обновляются
|
||||
// независимо
|
||||
val chatsState by chatsViewModel.chatsState.collectAsState()
|
||||
val requests = chatsState.requests
|
||||
val requestsCount = chatsState.requestsCount
|
||||
@@ -841,21 +922,31 @@ fun ChatsListScreen(
|
||||
if (targetState) {
|
||||
// Переход на Requests: slide in from right + fade
|
||||
(slideInHorizontally(
|
||||
animationSpec = tween(300, easing = FastOutSlowInEasing),
|
||||
animationSpec =
|
||||
tween(300, easing = FastOutSlowInEasing),
|
||||
initialOffsetX = { it }
|
||||
) + fadeIn(tween(300))) togetherWith
|
||||
(slideOutHorizontally(
|
||||
animationSpec = tween(300, easing = FastOutSlowInEasing),
|
||||
animationSpec =
|
||||
tween(
|
||||
300,
|
||||
easing = FastOutSlowInEasing
|
||||
),
|
||||
targetOffsetX = { -it / 3 }
|
||||
) + fadeOut(tween(200)))
|
||||
} else {
|
||||
// Возврат из Requests: slide out to right
|
||||
(slideInHorizontally(
|
||||
animationSpec = tween(300, easing = FastOutSlowInEasing),
|
||||
animationSpec =
|
||||
tween(300, easing = FastOutSlowInEasing),
|
||||
initialOffsetX = { -it / 3 }
|
||||
) + fadeIn(tween(300))) togetherWith
|
||||
(slideOutHorizontally(
|
||||
animationSpec = tween(300, easing = FastOutSlowInEasing),
|
||||
animationSpec =
|
||||
tween(
|
||||
300,
|
||||
easing = FastOutSlowInEasing
|
||||
),
|
||||
targetOffsetX = { it }
|
||||
) + fadeOut(tween(200)))
|
||||
}
|
||||
@@ -882,7 +973,8 @@ fun ChatsListScreen(
|
||||
)
|
||||
} else {
|
||||
// Show dialogs list
|
||||
val dividerColor = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE8E8E8)
|
||||
val dividerColor =
|
||||
if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE8E8E8)
|
||||
// 🔥 Берем dialogs из chatsState для консистентности
|
||||
val currentDialogs = chatsState.dialogs
|
||||
|
||||
@@ -895,10 +987,7 @@ fun ChatsListScreen(
|
||||
isDarkTheme = isDarkTheme,
|
||||
onClick = { showRequestsScreen = true }
|
||||
)
|
||||
Divider(
|
||||
color = dividerColor,
|
||||
thickness = 0.5.dp
|
||||
)
|
||||
Divider(color = dividerColor, thickness = 0.5.dp)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,18 +1007,15 @@ fun ChatsListScreen(
|
||||
isBlocked = isBlocked,
|
||||
isSavedMessages = isSavedMessages,
|
||||
onClick = {
|
||||
val user = chatsViewModel.dialogToSearchUser(dialog)
|
||||
val user =
|
||||
chatsViewModel.dialogToSearchUser(
|
||||
dialog
|
||||
)
|
||||
onUserSelect(user)
|
||||
},
|
||||
onDelete = {
|
||||
dialogToDelete = dialog
|
||||
},
|
||||
onBlock = {
|
||||
dialogToBlock = dialog
|
||||
},
|
||||
onUnblock = {
|
||||
dialogToUnblock = dialog
|
||||
}
|
||||
onDelete = { dialogToDelete = dialog },
|
||||
onBlock = { dialogToBlock = dialog },
|
||||
onUnblock = { dialogToUnblock = dialog }
|
||||
)
|
||||
|
||||
// 🔥 СЕПАРАТОР - линия разделения между диалогами
|
||||
@@ -957,11 +1043,7 @@ fun ChatsListScreen(
|
||||
onDismissRequest = { dialogToDelete = null },
|
||||
containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
|
||||
title = {
|
||||
Text(
|
||||
"Delete Chat",
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = textColor
|
||||
)
|
||||
Text("Delete Chat", fontWeight = FontWeight.Bold, color = textColor)
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
@@ -974,13 +1056,9 @@ fun ChatsListScreen(
|
||||
onClick = {
|
||||
val opponentKey = dialog.opponentKey
|
||||
dialogToDelete = null
|
||||
scope.launch {
|
||||
chatsViewModel.deleteDialog(opponentKey)
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text("Delete", color = Color(0xFFFF3B30))
|
||||
scope.launch { chatsViewModel.deleteDialog(opponentKey) }
|
||||
}
|
||||
) { Text("Delete", color = Color(0xFFFF3B30)) }
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { dialogToDelete = null }) {
|
||||
@@ -1018,9 +1096,7 @@ fun ChatsListScreen(
|
||||
blocklistUpdateTrigger++
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text("Block", color = Color(0xFFFF3B30))
|
||||
}
|
||||
) { Text("Block", color = Color(0xFFFF3B30)) }
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { dialogToBlock = null }) {
|
||||
@@ -1058,9 +1134,7 @@ fun ChatsListScreen(
|
||||
blocklistUpdateTrigger++
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text("Unblock", color = PrimaryBlue)
|
||||
}
|
||||
) { Text("Unblock", color = PrimaryBlue) }
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { dialogToUnblock = null }) {
|
||||
@@ -1223,7 +1297,7 @@ fun ChatItem(chat: Chat, isDarkTheme: Boolean, onClick: () -> Unit) {
|
||||
Icon(
|
||||
Icons.Default.PushPin,
|
||||
contentDescription = "Pinned",
|
||||
tint = secondaryTextColor,
|
||||
tint = secondaryTextColor.copy(alpha = 0.6f),
|
||||
modifier = Modifier.size(16.dp).padding(end = 4.dp)
|
||||
)
|
||||
}
|
||||
@@ -1324,7 +1398,7 @@ fun DrawerMenuItem(
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = textColor,
|
||||
tint = textColor.copy(alpha = 0.6f),
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
|
||||
@@ -1335,8 +1409,8 @@ fun DrawerMenuItem(
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔥 Swipeable wrapper для DialogItem с кнопками Block и Delete
|
||||
* Свайп влево показывает действия (как в React Native версии)
|
||||
* 🔥 Swipeable wrapper для DialogItem с кнопками Block и Delete Свайп влево показывает действия
|
||||
* (как в React Native версии)
|
||||
*/
|
||||
@Composable
|
||||
fun SwipeableDialogItem(
|
||||
@@ -1360,32 +1434,26 @@ fun SwipeableDialogItem(
|
||||
val itemHeight = 80.dp
|
||||
|
||||
// Анимация возврата
|
||||
val animatedOffsetX by animateFloatAsState(
|
||||
val animatedOffsetX by
|
||||
animateFloatAsState(
|
||||
targetValue = offsetX,
|
||||
animationSpec = spring(dampingRatio = 0.7f, stiffness = 400f),
|
||||
label = "swipeOffset"
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(itemHeight)
|
||||
.clipToBounds()
|
||||
) {
|
||||
Box(modifier = Modifier.fillMaxWidth().height(itemHeight).clipToBounds()) {
|
||||
// 1. КНОПКИ - позиционированы справа, всегда видны при свайпе
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.height(itemHeight)
|
||||
.width(swipeWidthDp)
|
||||
) {
|
||||
Row(modifier = Modifier.align(Alignment.CenterEnd).height(itemHeight).width(swipeWidthDp)) {
|
||||
// Кнопка Block/Unblock (только если не Saved Messages)
|
||||
if (!isSavedMessages) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(80.dp)
|
||||
modifier =
|
||||
Modifier.width(80.dp)
|
||||
.fillMaxHeight()
|
||||
.background(if (isBlocked) Color(0xFF4CAF50) else Color(0xFFFF6B6B))
|
||||
.background(
|
||||
if (isBlocked) Color(0xFF4CAF50)
|
||||
else Color(0xFFFF6B6B)
|
||||
)
|
||||
.clickable {
|
||||
if (isBlocked) onUnblock() else onBlock()
|
||||
offsetX = 0f
|
||||
@@ -1397,7 +1465,9 @@ fun SwipeableDialogItem(
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isBlocked) Icons.Default.LockOpen else Icons.Default.Block,
|
||||
imageVector =
|
||||
if (isBlocked) Icons.Default.LockOpen
|
||||
else Icons.Default.Block,
|
||||
contentDescription = if (isBlocked) "Unblock" else "Block",
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(22.dp)
|
||||
@@ -1415,8 +1485,8 @@ fun SwipeableDialogItem(
|
||||
|
||||
// Кнопка Delete
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(80.dp)
|
||||
modifier =
|
||||
Modifier.width(80.dp)
|
||||
.fillMaxHeight()
|
||||
.background(PrimaryBlue)
|
||||
.clickable {
|
||||
@@ -1449,8 +1519,8 @@ fun SwipeableDialogItem(
|
||||
|
||||
// 2. КОНТЕНТ - поверх кнопок, сдвигается при свайпе
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
modifier =
|
||||
Modifier.fillMaxSize()
|
||||
.offset { IntOffset(animatedOffsetX.toInt(), 0) }
|
||||
.background(backgroundColor)
|
||||
.pointerInput(Unit) {
|
||||
@@ -1463,9 +1533,7 @@ fun SwipeableDialogItem(
|
||||
offsetX = 0f
|
||||
}
|
||||
},
|
||||
onDragCancel = {
|
||||
offsetX = 0f
|
||||
},
|
||||
onDragCancel = { offsetX = 0f },
|
||||
onHorizontalDrag = { _, dragAmount ->
|
||||
// Только свайп влево (отрицательное значение)
|
||||
val newOffset = offsetX + dragAmount
|
||||
@@ -1494,16 +1562,27 @@ fun SwipeableDialogItem(
|
||||
|
||||
/** Элемент диалога из базы данных - ОПТИМИЗИРОВАННЫЙ (без сепаратора для SwipeableDialogItem) */
|
||||
@Composable
|
||||
fun DialogItemContent(dialog: DialogUiModel, isDarkTheme: Boolean, isTyping: Boolean = false, onClick: () -> Unit) {
|
||||
fun DialogItemContent(
|
||||
dialog: DialogUiModel,
|
||||
isDarkTheme: Boolean,
|
||||
isTyping: Boolean = false,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
// 🔥 ОПТИМИЗАЦИЯ: Кешируем цвета и строки
|
||||
val textColor = remember(isDarkTheme) { if (isDarkTheme) Color.White else Color.Black }
|
||||
val secondaryTextColor = remember(isDarkTheme) { if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666) }
|
||||
val secondaryTextColor =
|
||||
remember(isDarkTheme) { if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666) }
|
||||
|
||||
val avatarColors = remember(dialog.opponentKey, isDarkTheme) { getAvatarColor(dialog.opponentKey, isDarkTheme) }
|
||||
val displayName = remember(dialog.opponentTitle, dialog.opponentKey) {
|
||||
val avatarColors =
|
||||
remember(dialog.opponentKey, isDarkTheme) {
|
||||
getAvatarColor(dialog.opponentKey, isDarkTheme)
|
||||
}
|
||||
val displayName =
|
||||
remember(dialog.opponentTitle, dialog.opponentKey) {
|
||||
dialog.opponentTitle.ifEmpty { dialog.opponentKey.take(8) }
|
||||
}
|
||||
val initials = remember(dialog.opponentTitle, dialog.opponentKey) {
|
||||
val initials =
|
||||
remember(dialog.opponentTitle, dialog.opponentKey) {
|
||||
if (dialog.opponentTitle.isNotEmpty()) {
|
||||
dialog.opponentTitle
|
||||
.split(" ")
|
||||
@@ -1549,8 +1628,7 @@ fun DialogItemContent(dialog: DialogUiModel, isDarkTheme: Boolean, isTyping: Boo
|
||||
.offset(x = (-2).dp, y = (-2).dp)
|
||||
.clip(CircleShape)
|
||||
.background(
|
||||
if (isDarkTheme) Color(0xFF1C1C1E)
|
||||
else Color.White
|
||||
if (isDarkTheme) Color(0xFF1C1C1E) else Color.White
|
||||
)
|
||||
.padding(3.dp)
|
||||
.clip(CircleShape)
|
||||
@@ -1601,8 +1679,12 @@ fun DialogItemContent(dialog: DialogUiModel, isDarkTheme: Boolean, isTyping: Boo
|
||||
AppleEmojiText(
|
||||
text = dialog.lastMessage.ifEmpty { "No messages" },
|
||||
fontSize = 14.sp,
|
||||
color = if (dialog.unreadCount > 0) textColor.copy(alpha = 0.85f) else secondaryTextColor,
|
||||
fontWeight = if (dialog.unreadCount > 0) FontWeight.Medium else FontWeight.Normal,
|
||||
color =
|
||||
if (dialog.unreadCount > 0) textColor.copy(alpha = 0.85f)
|
||||
else secondaryTextColor,
|
||||
fontWeight =
|
||||
if (dialog.unreadCount > 0) FontWeight.Medium
|
||||
else FontWeight.Normal,
|
||||
maxLines = 1,
|
||||
overflow = android.text.TextUtils.TruncateAt.END,
|
||||
modifier = Modifier.weight(1f)
|
||||
@@ -1612,7 +1694,8 @@ fun DialogItemContent(dialog: DialogUiModel, isDarkTheme: Boolean, isTyping: Boo
|
||||
// Unread badge
|
||||
if (dialog.unreadCount > 0) {
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
val unreadText = when {
|
||||
val unreadText =
|
||||
when {
|
||||
dialog.unreadCount > 999 -> "999+"
|
||||
dialog.unreadCount > 99 -> "99+"
|
||||
else -> dialog.unreadCount.toString()
|
||||
@@ -1641,8 +1724,7 @@ fun DialogItemContent(dialog: DialogUiModel, isDarkTheme: Boolean, isTyping: Boo
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔥 Компактный индикатор typing для списка чатов
|
||||
* Голубой текст "typing" с анимированными точками
|
||||
* 🔥 Компактный индикатор typing для списка чатов Голубой текст "typing" с анимированными точками
|
||||
*/
|
||||
@Composable
|
||||
fun TypingIndicatorSmall() {
|
||||
@@ -1653,20 +1735,18 @@ fun TypingIndicatorSmall() {
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(1.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "typing",
|
||||
fontSize = 14.sp,
|
||||
color = typingColor,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
Text(text = "typing", fontSize = 14.sp, color = typingColor, fontWeight = FontWeight.Medium)
|
||||
|
||||
// 3 анимированные точки
|
||||
repeat(3) { index ->
|
||||
val offsetY by infiniteTransition.animateFloat(
|
||||
val offsetY by
|
||||
infiniteTransition.animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = -3f,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(
|
||||
animationSpec =
|
||||
infiniteRepeatable(
|
||||
animation =
|
||||
tween(
|
||||
durationMillis = 500,
|
||||
delayMillis = index * 120,
|
||||
easing = FastOutSlowInEasing
|
||||
@@ -1687,21 +1767,15 @@ fun TypingIndicatorSmall() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 📬 Секция Requests - кнопка для перехода к списку запросов
|
||||
*/
|
||||
/** 📬 Секция Requests - кнопка для перехода к списку запросов */
|
||||
@Composable
|
||||
fun RequestsSection(
|
||||
count: Int,
|
||||
isDarkTheme: Boolean,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
fun RequestsSection(count: Int, isDarkTheme: Boolean, onClick: () -> Unit) {
|
||||
val textColor = if (isDarkTheme) Color(0xFF4DABF7) else Color(0xFF228BE6)
|
||||
val arrowColor = if (isDarkTheme) Color(0xFFC9C9C9) else Color(0xFF228BE6)
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 16.dp, vertical = 14.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
@@ -1717,15 +1791,13 @@ fun RequestsSection(
|
||||
Icon(
|
||||
imageVector = Icons.Default.ChevronRight,
|
||||
contentDescription = "Open requests",
|
||||
tint = arrowColor,
|
||||
tint = arrowColor.copy(alpha = 0.6f),
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 📬 Экран со списком Requests (без хедера - хедер в основном TopAppBar)
|
||||
*/
|
||||
/** 📬 Экран со списком Requests (без хедера - хедер в основном TopAppBar) */
|
||||
@Composable
|
||||
fun RequestsScreen(
|
||||
requests: List<DialogUiModel>,
|
||||
@@ -1736,17 +1808,11 @@ fun RequestsScreen(
|
||||
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
|
||||
val dividerColor = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE8E8E8)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(backgroundColor)
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxSize().background(backgroundColor)) {
|
||||
if (requests.isEmpty()) {
|
||||
// Empty state
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(32.dp),
|
||||
modifier = Modifier.fillMaxSize().padding(32.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
@@ -1758,9 +1824,7 @@ fun RequestsScreen(
|
||||
}
|
||||
} else {
|
||||
// Requests list
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||
items(requests, key = { it.opponentKey }) { request ->
|
||||
DialogItemContent(
|
||||
dialog = request,
|
||||
@@ -1780,9 +1844,7 @@ fun RequestsScreen(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🎨 Enhanced Drawer Menu Item - красивый пункт меню с hover эффектом
|
||||
*/
|
||||
/** 🎨 Enhanced Drawer Menu Item - красивый пункт меню с hover эффектом */
|
||||
@Composable
|
||||
fun DrawerMenuItemEnhanced(
|
||||
icon: androidx.compose.ui.graphics.vector.ImageVector,
|
||||
@@ -1793,8 +1855,8 @@ fun DrawerMenuItemEnhanced(
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 20.dp, vertical = 14.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
@@ -1818,8 +1880,8 @@ fun DrawerMenuItemEnhanced(
|
||||
|
||||
badge?.let {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
modifier =
|
||||
Modifier.background(
|
||||
color = Color(0xFF4A90D9),
|
||||
shape = RoundedCornerShape(10.dp)
|
||||
)
|
||||
@@ -1836,9 +1898,7 @@ fun DrawerMenuItemEnhanced(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 📏 Drawer Divider - разделитель между секциями
|
||||
*/
|
||||
/** 📏 Drawer Divider - разделитель между секциями */
|
||||
@Composable
|
||||
fun DrawerDivider(isDarkTheme: Boolean) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
@@ -136,7 +136,7 @@ fun ForwardChatPickerBottomSheet(
|
||||
Icon(
|
||||
Icons.Default.Close,
|
||||
contentDescription = "Close",
|
||||
tint = secondaryTextColor
|
||||
tint = secondaryTextColor.copy(alpha = 0.6f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ fun SearchScreen(
|
||||
Icon(
|
||||
Icons.Default.ArrowBack,
|
||||
contentDescription = "Back",
|
||||
tint = textColor
|
||||
tint = textColor.copy(alpha = 0.6f)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ fun SearchScreen(
|
||||
Icon(
|
||||
Icons.Default.Clear,
|
||||
contentDescription = "Clear",
|
||||
tint = secondaryTextColor
|
||||
tint = secondaryTextColor.copy(alpha = 0.6f)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -381,7 +381,7 @@ private fun RecentUserItem(
|
||||
Icon(
|
||||
Icons.Default.Close,
|
||||
contentDescription = "Remove",
|
||||
tint = secondaryTextColor,
|
||||
tint = secondaryTextColor.copy(alpha = 0.6f),
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user