From f8564594940e1957e64a4d4e4fb728cf40c9e349 Mon Sep 17 00:00:00 2001 From: k1ngsterr1 Date: Wed, 21 Jan 2026 00:08:33 +0500 Subject: [PATCH] feat: Implement collapsing header for ProfileScreen with enhanced navigation and logging features --- .../messenger/ui/settings/ProfileScreen.kt | 602 ++++++++++++------ 1 file changed, 413 insertions(+), 189 deletions(-) diff --git a/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileScreen.kt index 7b8edc7..30fae62 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileScreen.kt @@ -4,8 +4,10 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import androidx.compose.animation.* +import androidx.compose.animation.core.* import androidx.compose.foundation.* import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField @@ -16,22 +18,28 @@ import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.TextStyle 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.lifecycle.viewmodel.compose.viewModel -import com.rosetta.messenger.ui.onboarding.PrimaryBlue import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import kotlin.math.roundToInt // 🎨 Avatar colors - ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ‚Π΅ ΠΆΠ΅ Ρ†Π²Π΅Ρ‚Π° Ρ‡Ρ‚ΠΎ ΠΈ Π² ChatsListScreen private val avatarColorsLight = @@ -91,6 +99,15 @@ private fun getInitials(name: String): String { } } +// ═════════════════════════════════════════════════════════════ +// 🎯 COLLAPSING HEADER CONSTANTS +// ═════════════════════════════════════════════════════════════ +private val EXPANDED_HEADER_HEIGHT = 280.dp +private val COLLAPSED_HEADER_HEIGHT = 56.dp +private val AVATAR_SIZE_EXPANDED = 120.dp +private val AVATAR_SIZE_COLLAPSED = 36.dp +private val STATUS_BAR_HEIGHT = 24.dp + @OptIn(ExperimentalMaterial3Api::class) @Composable fun ProfileScreen( @@ -107,13 +124,12 @@ fun ProfileScreen( onNavigateToLogs: () -> Unit = {}, viewModel: ProfileViewModel = androidx.lifecycle.viewmodel.compose.viewModel() ) { - // Π¦Π²Π΅Ρ‚Π° Π² зависимости ΠΎΡ‚ Ρ‚Π΅ΠΌΡ‹ - Ρ‚Π°ΠΊΠΈΠ΅ ΠΆΠ΅ ΠΊΠ°ΠΊ Π² ChatsListScreen + // Π¦Π²Π΅Ρ‚Π° Π² зависимости ΠΎΡ‚ Ρ‚Π΅ΠΌΡ‹ val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF) val surfaceColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color(0xFFF2F2F7) val textColor = if (isDarkTheme) Color.White else Color.Black val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666) - val dividerColor = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE8E8E8) - val iconTintColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666) + val avatarColors = getAvatarColor(accountPublicKey, isDarkTheme) // State for editing var editedName by remember { mutableStateOf(accountName) } @@ -123,8 +139,50 @@ fun ProfileScreen( // ViewModel state val profileState by viewModel.state.collectAsState() - // Show success toast + // Scroll state for collapsing header animation + val density = LocalDensity.current + val expandedHeightPx = with(density) { EXPANDED_HEADER_HEIGHT.toPx() } + val collapsedHeightPx = with(density) { (COLLAPSED_HEADER_HEIGHT + STATUS_BAR_HEIGHT).toPx() } + + // Track scroll offset with animated state for smooth transitions + var scrollOffset by remember { mutableFloatStateOf(0f) } + val maxScrollOffset = expandedHeightPx - collapsedHeightPx + + // Calculate collapse progress (0 = expanded, 1 = collapsed) + val collapseProgress by remember { + derivedStateOf { + (scrollOffset / maxScrollOffset).coerceIn(0f, 1f) + } + } + + // Nested scroll connection for tracking scroll + val nestedScrollConnection = remember { + object : NestedScrollConnection { + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + val delta = available.y + val newOffset = scrollOffset - delta + val consumed = when { + delta < 0 && scrollOffset < maxScrollOffset -> { + val consumed = (newOffset.coerceIn(0f, maxScrollOffset) - scrollOffset) + scrollOffset = newOffset.coerceIn(0f, maxScrollOffset) + -consumed + } + delta > 0 && scrollOffset > 0 -> { + val consumed = scrollOffset - newOffset.coerceIn(0f, maxScrollOffset) + scrollOffset = newOffset.coerceIn(0f, maxScrollOffset) + consumed + } + else -> 0f + } + return Offset(0f, consumed) + } + } + } + + // Context val context = LocalContext.current + + // Show success toast LaunchedEffect(profileState.saveSuccess) { if (profileState.saveSuccess) { android.widget.Toast.makeText( @@ -159,198 +217,365 @@ fun ProfileScreen( modifier = Modifier .fillMaxSize() .background(backgroundColor) + .nestedScroll(nestedScrollConnection) ) { - Column( + // Scrollable content + LazyColumn( modifier = Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) + .padding(top = with(density) { (expandedHeightPx - scrollOffset).toDp() }) ) { - // ═════════════════════════════════════════════════════════════ - // πŸ‘€ PROFILE CARD with colored header - // ═════════════════════════════════════════════════════════════ - ProfileCard( - name = editedName.ifBlank { accountPublicKey.take(10) }, - username = editedUsername, - publicKey = accountPublicKey, - isDarkTheme = isDarkTheme, - onBack = null, // Кнопка Π½Π°Π·Π°Π΄ Π±ΡƒΠ΄Π΅Ρ‚ снаруТи - hasChanges = hasChanges, - onSave = { - // Save via ViewModel - viewModel.saveProfile( - publicKey = accountPublicKey, - privateKeyHash = accountPrivateKeyHash, - name = editedName, - username = editedUsername - ) - // Also update local account name - viewModel.updateLocalAccountName(accountPublicKey, editedName) + item { + Spacer(modifier = Modifier.height(16.dp)) + + // ═════════════════════════════════════════════════════════════ + // ✏️ EDITABLE FIELDS + // ═════════════════════════════════════════════════════════════ + ProfileSectionTitle(title = "Profile Information", isDarkTheme = isDarkTheme) + + Surface( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + color = surfaceColor, + shape = RoundedCornerShape(16.dp) + ) { + Column { + ProfileEditableField( + label = "Your name", + value = editedName, + onValueChange = { editedName = it }, + placeholder = "ex. Freddie Gibson", + isDarkTheme = isDarkTheme, + showDivider = true + ) + ProfileEditableField( + label = "Username", + value = editedUsername, + onValueChange = { editedUsername = it }, + placeholder = "ex. freddie871", + isDarkTheme = isDarkTheme + ) + } } - ) - Spacer(modifier = Modifier.height(16.dp)) + Spacer(modifier = Modifier.height(8.dp)) - // ═════════════════════════════════════════════════════════════ - // ✏️ EDITABLE FIELDS - // ═════════════════════════════════════════════════════════════ - ProfileSectionTitle(title = "Profile Information", isDarkTheme = isDarkTheme) - - Surface( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - color = surfaceColor, - shape = RoundedCornerShape(16.dp) - ) { - Column { - ProfileEditableField( - label = "Your name", - value = editedName, - onValueChange = { editedName = it }, - placeholder = "ex. Freddie Gibson", - isDarkTheme = isDarkTheme, - showDivider = true - ) - ProfileEditableField( - label = "Username", - value = editedUsername, - onValueChange = { editedUsername = it }, - placeholder = "ex. freddie871", - isDarkTheme = isDarkTheme - ) - } - } - - Spacer(modifier = Modifier.height(8.dp)) - - // Public Key Copy Field - ProfileCopyField( - label = "Public Key", - value = accountPublicKey, - isDarkTheme = isDarkTheme - ) - - Text( - text = "This is your public key. If you haven't set a @username yet, you can ask a friend to message you using your public key.", - fontSize = 12.sp, - color = secondaryTextColor, - modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp), - lineHeight = 16.sp - ) - - Spacer(modifier = Modifier.height(24.dp)) - - // ═════════════════════════════════════════════════════════════ - // πŸ”§ SETTINGS SECTION - // ═════════════════════════════════════════════════════════════ - ProfileSectionTitle(title = "Settings", isDarkTheme = isDarkTheme) - - Surface( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - color = surfaceColor, - shape = RoundedCornerShape(16.dp) - ) { - Column { - ProfileNavigationItem( - icon = Icons.Outlined.Brush, - iconBackground = Color(0xFF6366F1), // indigo - title = "Theme", - subtitle = "Customize appearance", - onClick = onNavigateToTheme, - isDarkTheme = isDarkTheme, - showDivider = true - ) - ProfileNavigationItem( - icon = Icons.Outlined.AdminPanelSettings, - iconBackground = Color(0xFF9333EA), // grape/purple - title = "Safety", - subtitle = "Backup and security settings", - onClick = onNavigateToSafety, - isDarkTheme = isDarkTheme - ) - } - } - - Text( - text = "You can learn more about your safety on the safety page, please make sure you are viewing the screen alone before proceeding to the safety page.", - fontSize = 12.sp, - color = secondaryTextColor, - modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp), - lineHeight = 16.sp - ) - - Spacer(modifier = Modifier.height(24.dp)) - - // ═════════════════════════════════════════════════════════════ - // οΏ½ DEBUG / LOGS SECTION - // ═════════════════════════════════════════════════════════════ - Surface( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - color = surfaceColor, - shape = RoundedCornerShape(16.dp) - ) { - ProfileNavigationItem( - icon = Icons.Outlined.BugReport, - iconBackground = Color(0xFFFB8C00), // orange - title = "View Logs", - subtitle = "Debug profile save operations", - onClick = onNavigateToLogs, + // Public Key Copy Field + ProfileCopyField( + label = "Public Key", + value = accountPublicKey, isDarkTheme = isDarkTheme ) - } - Text( - text = "View detailed logs of profile save operations for debugging.", - fontSize = 12.sp, - color = secondaryTextColor, - modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp), - lineHeight = 16.sp - ) - - Spacer(modifier = Modifier.height(24.dp)) - - // ═════════════════════════════════════════════════════════════ - // οΏ½πŸšͺ LOGOUT SECTION - // ═════════════════════════════════════════════════════════════ - Surface( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - color = surfaceColor, - shape = RoundedCornerShape(16.dp) - ) { - ProfileNavigationItem( - icon = Icons.Outlined.Logout, - iconBackground = if (isDarkTheme) Color(0xFFFF8787) else Color(0xFFEF4444), - title = "Logout", - subtitle = "Sign out of your account", - onClick = onLogout, - isDarkTheme = isDarkTheme, - hideChevron = true, - textColor = if (isDarkTheme) Color(0xFFFF8787) else Color(0xFFEF4444) + Text( + text = "This is your public key. If you haven't set a @username yet, you can ask a friend to message you using your public key.", + fontSize = 12.sp, + color = secondaryTextColor, + modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp), + lineHeight = 16.sp ) + + Spacer(modifier = Modifier.height(24.dp)) + + // ═════════════════════════════════════════════════════════════ + // πŸ”§ SETTINGS SECTION + // ═════════════════════════════════════════════════════════════ + ProfileSectionTitle(title = "Settings", isDarkTheme = isDarkTheme) + + Surface( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + color = surfaceColor, + shape = RoundedCornerShape(16.dp) + ) { + Column { + ProfileNavigationItem( + icon = Icons.Outlined.Brush, + iconBackground = Color(0xFF6366F1), + title = "Theme", + subtitle = "Customize appearance", + onClick = onNavigateToTheme, + isDarkTheme = isDarkTheme, + showDivider = true + ) + ProfileNavigationItem( + icon = Icons.Outlined.AdminPanelSettings, + iconBackground = Color(0xFF9333EA), + title = "Safety", + subtitle = "Backup and security settings", + onClick = onNavigateToSafety, + isDarkTheme = isDarkTheme + ) + } + } + + Text( + text = "You can learn more about your safety on the safety page, please make sure you are viewing the screen alone before proceeding to the safety page.", + fontSize = 12.sp, + color = secondaryTextColor, + modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp), + lineHeight = 16.sp + ) + + Spacer(modifier = Modifier.height(24.dp)) + + // ═════════════════════════════════════════════════════════════ + // πŸ› DEBUG / LOGS SECTION + // ═════════════════════════════════════════════════════════════ + Surface( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + color = surfaceColor, + shape = RoundedCornerShape(16.dp) + ) { + ProfileNavigationItem( + icon = Icons.Outlined.BugReport, + iconBackground = Color(0xFFFB8C00), + title = "View Logs", + subtitle = "Debug profile save operations", + onClick = onNavigateToLogs, + isDarkTheme = isDarkTheme + ) + } + + Text( + text = "View detailed logs of profile save operations for debugging.", + fontSize = 12.sp, + color = secondaryTextColor, + modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp), + lineHeight = 16.sp + ) + + Spacer(modifier = Modifier.height(24.dp)) + + // ═════════════════════════════════════════════════════════════ + // πŸšͺ LOGOUT SECTION + // ═════════════════════════════════════════════════════════════ + Surface( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + color = surfaceColor, + shape = RoundedCornerShape(16.dp) + ) { + ProfileNavigationItem( + icon = Icons.Outlined.Logout, + iconBackground = if (isDarkTheme) Color(0xFFFF8787) else Color(0xFFEF4444), + title = "Logout", + subtitle = "Sign out of your account", + onClick = onLogout, + isDarkTheme = isDarkTheme, + hideChevron = true, + textColor = if (isDarkTheme) Color(0xFFFF8787) else Color(0xFFEF4444) + ) + } + + Text( + text = "Logging out of your account. After logging out, you will be redirected to the password entry page.", + fontSize = 12.sp, + color = secondaryTextColor, + modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp), + lineHeight = 16.sp + ) + + Spacer(modifier = Modifier.height(32.dp)) } - - Text( - text = "Logging out of your account. After logging out, you will be redirected to the password entry page.", - fontSize = 12.sp, - color = secondaryTextColor, - modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp), - lineHeight = 16.sp - ) - - Spacer(modifier = Modifier.height(32.dp)) } - // Fixed back button at top + // ═════════════════════════════════════════════════════════════ + // 🎨 COLLAPSING HEADER - Telegram style + // ═════════════════════════════════════════════════════════════ + CollapsingProfileHeader( + name = editedName.ifBlank { accountPublicKey.take(10) }, + username = editedUsername, + publicKey = accountPublicKey, + avatarColors = avatarColors, + collapseProgress = collapseProgress, + onBack = onBack, + hasChanges = hasChanges, + onSave = { + viewModel.saveProfile( + publicKey = accountPublicKey, + privateKeyHash = accountPrivateKeyHash, + name = editedName, + username = editedUsername + ) + viewModel.updateLocalAccountName(accountPublicKey, editedName) + }, + isDarkTheme = isDarkTheme + ) + } +} + +// ═════════════════════════════════════════════════════════════ +// 🎯 COLLAPSING PROFILE HEADER - Telegram Style Animation +// ═════════════════════════════════════════════════════════════ +@Composable +private fun CollapsingProfileHeader( + name: String, + username: String, + publicKey: String, + avatarColors: AvatarColors, + collapseProgress: Float, + onBack: () -> Unit, + hasChanges: Boolean, + onSave: () -> Unit, + isDarkTheme: Boolean +) { + val density = LocalDensity.current + + // Animated values using lerp + val headerHeight = androidx.compose.ui.unit.lerp( + EXPANDED_HEADER_HEIGHT, + COLLAPSED_HEADER_HEIGHT + STATUS_BAR_HEIGHT, + collapseProgress + ) + + val avatarSize = androidx.compose.ui.unit.lerp( + AVATAR_SIZE_EXPANDED, + AVATAR_SIZE_COLLAPSED, + collapseProgress + ) + + // Avatar position - smooth transition from center to left + val screenWidthDp = with(density) { 360.dp } // approximate + val avatarStartX = (screenWidthDp - AVATAR_SIZE_EXPANDED) / 2 + val avatarEndX = 56.dp // After back button + + val avatarX = androidx.compose.ui.unit.lerp(avatarStartX, avatarEndX, collapseProgress) + val avatarY = androidx.compose.ui.unit.lerp(70.dp, STATUS_BAR_HEIGHT + 10.dp, collapseProgress) + + // Text alpha animations + val expandedContentAlpha = (1f - collapseProgress * 2f).coerceIn(0f, 1f) // Fades out faster + val collapsedContentAlpha = ((collapseProgress - 0.5f) * 2f).coerceIn(0f, 1f) // Fades in at 50% + + // Avatar scale for "drop" effect - shrinks faster at the end + val avatarScaleMultiplier = if (collapseProgress > 0.7f) { + 1f - ((collapseProgress - 0.7f) / 0.3f) * 0.15f + } else 1f + + Box( + modifier = Modifier + .fillMaxWidth() + .height(headerHeight) + .drawBehind { + drawRect(avatarColors.backgroundColor) + } + ) { + // ═══════════════════════════════════════════════════════════ + // πŸ‘€ ANIMATED AVATAR - Telegram "drop" effect + // ═══════════════════════════════════════════════════════════ + Box( + modifier = Modifier + .offset(x = avatarX, y = avatarY) + .size(avatarSize) + .graphicsLayer { + scaleX = avatarScaleMultiplier + scaleY = avatarScaleMultiplier + // Subtle alpha decrease at the very end for smooth collapse + alpha = if (collapseProgress > 0.9f) { + 1f - ((collapseProgress - 0.9f) / 0.1f) * 0.2f + } else 1f + } + .clip(CircleShape) + .background(Color.White.copy(alpha = 0.2f)) + .padding(2.dp) + .clip(CircleShape) + .background(avatarColors.backgroundColor), + contentAlignment = Alignment.Center + ) { + Text( + text = getInitials(name), + fontSize = androidx.compose.ui.unit.lerp(40.sp, 14.sp, collapseProgress), + fontWeight = FontWeight.Bold, + color = avatarColors.textColor + ) + } + + // ═══════════════════════════════════════════════════════════ + // πŸ“ EXPANDED STATE - Name and info below avatar + // ═══════════════════════════════════════════════════════════ + Column( + modifier = Modifier + .fillMaxWidth() + .padding(top = 200.dp) + .graphicsLayer { alpha = expandedContentAlpha }, + horizontalAlignment = Alignment.CenterHorizontally + ) { + // Name + Text( + text = name, + fontSize = 24.sp, + fontWeight = FontWeight.SemiBold, + color = Color.White, + textAlign = TextAlign.Center + ) + + Spacer(modifier = Modifier.height(4.dp)) + + // Username and public key + Row( + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + if (username.isNotBlank()) { + Text( + text = "@$username", + fontSize = 14.sp, + color = Color.White.copy(alpha = 0.8f) + ) + Text( + text = " β€’ ", + fontSize = 14.sp, + color = Color.White.copy(alpha = 0.8f) + ) + } + Text( + text = "${publicKey.take(3)}...${publicKey.takeLast(3)}", + fontSize = 14.sp, + color = Color.White.copy(alpha = 0.8f) + ) + } + } + + // ═══════════════════════════════════════════════════════════ + // πŸ“ COLLAPSED STATE - Toolbar with name next to avatar + // ═══════════════════════════════════════════════════════════ + Row( + modifier = Modifier + .fillMaxWidth() + .statusBarsPadding() + .height(COLLAPSED_HEADER_HEIGHT) + .padding(start = 100.dp) // Space for back button + avatar + .graphicsLayer { alpha = collapsedContentAlpha }, + verticalAlignment = Alignment.CenterVertically + ) { + Column { + Text( + text = name, + fontSize = 18.sp, + fontWeight = FontWeight.SemiBold, + color = Color.White, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Text( + text = "online", + fontSize = 13.sp, + color = Color.White.copy(alpha = 0.7f) + ) + } + } + + // ═══════════════════════════════════════════════════════════ + // πŸ”™ BACK BUTTON - Always visible + // ═══════════════════════════════════════════════════════════ IconButton( onClick = onBack, modifier = Modifier - .align(Alignment.TopStart) .statusBarsPadding() .padding(4.dp) ) { @@ -361,7 +586,9 @@ fun ProfileScreen( ) } - // Fixed save button (if changes) + // ═══════════════════════════════════════════════════════════ + // πŸ’Ύ SAVE BUTTON (if changes) + // ═══════════════════════════════════════════════════════════ AnimatedVisibility( visible = hasChanges, enter = fadeIn() + expandHorizontally(), @@ -371,10 +598,7 @@ fun ProfileScreen( .statusBarsPadding() .padding(4.dp) ) { - TextButton(onClick = { - onSaveProfile(editedName, editedUsername) - hasChanges = false - }) { + TextButton(onClick = onSave) { Text( text = "Save", color = Color.White, @@ -386,7 +610,7 @@ fun ProfileScreen( } // ═════════════════════════════════════════════════════════════ -// πŸ“¦ PROFILE CARD COMPONENT - Large Avatar Telegram Style +// πŸ“¦ PROFILE CARD COMPONENT - Legacy (kept for OtherProfileScreen) // ═════════════════════════════════════════════════════════════ @Composable fun ProfileCard( @@ -649,7 +873,7 @@ private fun ProfileCopyField( Text( text = "Copied!", fontSize = 14.sp, - color = Color(0xFF22C55E), // green + color = Color(0xFF22C55E), fontWeight = FontWeight.Medium ) } else {