From e9eac107f23ddfddf11ebb89358ae96226e3f83a Mon Sep 17 00:00:00 2001 From: k1ngsterr1 Date: Fri, 9 Jan 2026 01:58:56 +0500 Subject: [PATCH] feat: Add public key handling for avatar display and enhance paste functionality in seed phrase confirmation --- .../com/rosetta/messenger/MainActivity.kt | 2 + .../ui/auth/ConfirmSeedPhraseScreen.kt | 53 +++-- .../messenger/ui/chats/ChatsListScreen.kt | 215 +++++++++++------- 3 files changed, 167 insertions(+), 103 deletions(-) diff --git a/app/src/main/java/com/rosetta/messenger/MainActivity.kt b/app/src/main/java/com/rosetta/messenger/MainActivity.kt index 505c446..1be6feb 100644 --- a/app/src/main/java/com/rosetta/messenger/MainActivity.kt +++ b/app/src/main/java/com/rosetta/messenger/MainActivity.kt @@ -205,11 +205,13 @@ fun MainScreen( val accountPhone = account?.publicKey?.take(16)?.let { "+${it.take(1)} ${it.substring(1, 4)} ${it.substring(4, 7)}${it.substring(7)}" } ?: "+7 775 9932587" + val accountPublicKey = account?.publicKey ?: "04c266b98ae5" ChatsListScreen( isDarkTheme = isDarkTheme, accountName = accountName, accountPhone = accountPhone, + accountPublicKey = accountPublicKey, onToggleTheme = onToggleTheme, onProfileClick = { // TODO: Navigate to profile diff --git a/app/src/main/java/com/rosetta/messenger/ui/auth/ConfirmSeedPhraseScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/auth/ConfirmSeedPhraseScreen.kt index 80e05d8..441c190 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/auth/ConfirmSeedPhraseScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/auth/ConfirmSeedPhraseScreen.kt @@ -140,30 +140,11 @@ fun ConfirmSeedPhraseScreen( modifier = Modifier .fillMaxWidth() .padding(4.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween + verticalAlignment = Alignment.CenterVertically ) { IconButton(onClick = onBack) { Icon(Icons.Default.ArrowBack, "Back", tint = textColor) } - - // Paste button - OutlinedButton( - onClick = handlePaste, - modifier = Modifier.height(40.dp), - colors = ButtonDefaults.outlinedButtonColors( - contentColor = PrimaryBlue - ), - border = BorderStroke(1.dp, PrimaryBlue) - ) { - Icon( - Icons.Default.ContentPaste, - contentDescription = "Paste", - modifier = Modifier.size(18.dp) - ) - Spacer(modifier = Modifier.width(6.dp)) - Text("Paste", fontSize = 14.sp) - } } Column( @@ -318,6 +299,38 @@ fun ConfirmSeedPhraseScreen( } } + Spacer(modifier = Modifier.height(20.dp)) + + // Paste button + AnimatedVisibility( + visible = visible, + enter = fadeIn(tween(500, delayMillis = 400)) + ) { + OutlinedButton( + onClick = handlePaste, + modifier = Modifier + .fillMaxWidth() + .height(48.dp), + colors = ButtonDefaults.outlinedButtonColors( + contentColor = PrimaryBlue + ), + border = BorderStroke(1.dp, PrimaryBlue), + shape = RoundedCornerShape(12.dp) + ) { + Icon( + Icons.Default.ContentPaste, + contentDescription = "Paste", + modifier = Modifier.size(20.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = "Paste from Clipboard", + fontSize = 16.sp, + fontWeight = FontWeight.Medium + ) + } + } + // Error message AnimatedVisibility( visible = showError, diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt index 422bad9..8e46b0c 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt @@ -112,6 +112,11 @@ fun getInitials(name: String): String { } } +// Get avatar text from public key (first 2 chars) +fun getAvatarText(publicKey: String): String { + return publicKey.take(2).uppercase() +} + // Drawer menu item data class DrawerMenuItem( val icon: ImageVector, @@ -126,6 +131,7 @@ fun ChatsListScreen( isDarkTheme: Boolean, accountName: String, accountPhone: String, + accountPublicKey: String, onToggleTheme: () -> Unit, onProfileClick: () -> Unit, onNewGroupClick: () -> Unit, @@ -242,6 +248,10 @@ fun ChatsListScreen( var titleClickCount by remember { mutableStateOf(0) } var lastClickTime by remember { mutableStateOf(0L) } + // Search state + var isSearchExpanded by remember { mutableStateOf(false) } + var searchQuery by remember { mutableStateOf("") } + var visible by remember { mutableStateOf(false) } LaunchedEffect(Unit) { @@ -401,19 +411,20 @@ fun ChatsListScreen( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.Top ) { - // Avatar with initials + // Avatar with public key + val avatarColors = getAvatarColor(accountName, isDarkTheme) Box( modifier = Modifier .size(64.dp) .clip(CircleShape) - .background(PrimaryBlue), + .background(avatarColors.backgroundColor), contentAlignment = Alignment.Center ) { Text( - text = getInitials(accountName), + text = getAvatarText(accountPublicKey), fontSize = 24.sp, fontWeight = FontWeight.Bold, - color = Color.White + color = avatarColors.textColor ) } @@ -556,91 +567,129 @@ fun ChatsListScreen( } }, title = { - // Stories / Title area - Triple click to open dev console - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.clickable { - val currentTime = System.currentTimeMillis() - if (currentTime - lastClickTime < 500) { - titleClickCount++ - if (titleClickCount >= 3) { - showDevConsole = true - titleClickCount = 0 - } - } else { - titleClickCount = 1 - } - lastClickTime = currentTime - } - ) { - // User story avatar placeholder - Box( - modifier = Modifier - .size(36.dp) - .clip(CircleShape) - .background( - brush = androidx.compose.ui.graphics.Brush.linearGradient( - colors = listOf( - Color(0xFF405DE6), - Color(0xFFC13584), - Color(0xFFFD1D1D) - ) - ) - ) - .padding(2.dp) - .clip(CircleShape) - .background(backgroundColor), - contentAlignment = Alignment.Center - ) { - val avatarColors = getAvatarColor(accountName, isDarkTheme) - Box( - modifier = Modifier - .size(30.dp) - .clip(CircleShape) - .background(avatarColors.backgroundColor), - contentAlignment = Alignment.Center + // Search field or Stories / Title area + AnimatedContent( + targetState = isSearchExpanded, + transitionSpec = { + fadeIn(tween(200)) togetherWith fadeOut(tween(200)) + }, + label = "searchAnimation" + ) { expanded -> + if (expanded) { + // Search TextField + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() ) { - Text( - text = getInitials(accountName), - fontSize = 12.sp, - fontWeight = FontWeight.Bold, - color = avatarColors.textColor + IconButton( + onClick = { + isSearchExpanded = false + searchQuery = "" + } + ) { + Icon( + Icons.Default.ArrowBack, + contentDescription = "Close search", + tint = textColor + ) + } + TextField( + value = searchQuery, + onValueChange = { searchQuery = it }, + placeholder = { + Text( + "Search...", + color = secondaryTextColor + ) + }, + colors = TextFieldDefaults.colors( + focusedContainerColor = Color.Transparent, + unfocusedContainerColor = Color.Transparent, + focusedTextColor = textColor, + unfocusedTextColor = textColor, + cursorColor = textColor, + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent + ), + singleLine = true, + modifier = Modifier.weight(1f) ) } - } - - Spacer(modifier = Modifier.width(12.dp)) - - // Title with connection status - Column { - Text( - "Rosetta", - fontWeight = FontWeight.Bold, - fontSize = 20.sp - ) - if (protocolState != ProtocolState.AUTHENTICATED) { - Text( - text = when (protocolState) { - ProtocolState.DISCONNECTED -> "Connecting..." - ProtocolState.CONNECTING -> "Connecting..." - ProtocolState.CONNECTED -> "Authenticating..." - ProtocolState.HANDSHAKING -> "Authenticating..." - ProtocolState.AUTHENTICATED -> "" - }, - fontSize = 12.sp, - color = secondaryTextColor - ) + } else { + // Triple click to open dev console + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.clickable { + val currentTime = System.currentTimeMillis() + if (currentTime - lastClickTime < 500) { + titleClickCount++ + if (titleClickCount >= 3) { + showDevConsole = true + titleClickCount = 0 + } + } else { + titleClickCount = 1 + } + lastClickTime = currentTime + } + ) { + // User avatar + val avatarColors = getAvatarColor(accountName, isDarkTheme) + Box( + modifier = Modifier + .size(36.dp) + .clip(CircleShape) + .background(avatarColors.backgroundColor), + contentAlignment = Alignment.Center + ) { + Text( + text = getAvatarText(accountPublicKey), + fontSize = 14.sp, + fontWeight = FontWeight.Bold, + color = avatarColors.textColor + ) + } + + Spacer(modifier = Modifier.width(12.dp)) + + // Title with connection status + Column { + Text( + "Rosetta", + fontWeight = FontWeight.Bold, + fontSize = 20.sp + ) + if (protocolState != ProtocolState.AUTHENTICATED) { + Text( + text = when (protocolState) { + ProtocolState.DISCONNECTED -> "Connecting..." + ProtocolState.CONNECTING -> "Connecting..." + ProtocolState.CONNECTED -> "Authenticating..." + ProtocolState.HANDSHAKING -> "Authenticating..." + ProtocolState.AUTHENTICATED -> "" + }, + fontSize = 12.sp, + color = secondaryTextColor + ) + } + } } } } }, actions = { - IconButton(onClick = onSearchClick) { - Icon( - Icons.Default.Search, - contentDescription = "Search", - tint = textColor - ) + if (!isSearchExpanded) { + IconButton( + onClick = { + isSearchExpanded = true + } + ) { + Icon( + Icons.Default.Search, + contentDescription = "Search", + tint = textColor + ) + } } }, colors = TopAppBarDefaults.topAppBarColors( @@ -833,7 +882,7 @@ fun ChatItem( val dividerColor = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE8E8E8) val avatarColors = getAvatarColor(chat.name, isDarkTheme) - val initials = getInitials(chat.name) + val avatarText = getAvatarText(chat.publicKey) Column { Row( @@ -852,7 +901,7 @@ fun ChatItem( contentAlignment = Alignment.Center ) { Text( - text = initials, + text = avatarText, fontSize = 20.sp, fontWeight = FontWeight.SemiBold, color = avatarColors.textColor