feat: Add reply panel visibility state and optimize dialog confirmation handling

This commit is contained in:
k1ngsterr1
2026-01-15 21:46:51 +05:00
parent 22a17e5fec
commit e7e6d23631
3 changed files with 170 additions and 225 deletions

View File

@@ -573,74 +573,38 @@ fun ChatsListScreen(
dialogToDelete?.let { dialog ->
AlertDialog(
onDismissRequest = { dialogToDelete = null },
icon = {
Icon(
imageVector = Icons.Default.Delete,
contentDescription = null,
tint = PrimaryBlue,
modifier = Modifier.size(32.dp)
)
},
containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
title = {
Text(
text = "Delete conversation?",
fontWeight = FontWeight.SemiBold,
fontSize = 18.sp,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
"Delete Chat",
fontWeight = FontWeight.Bold,
color = textColor
)
},
text = {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
val displayName = dialog.opponentTitle.ifEmpty { dialog.opponentKey.take(8) }
Text(
text = "All messages with $displayName will be permanently deleted. This action cannot be undone.",
fontSize = 15.sp,
color = if (isDarkTheme) Color(0xFFAAAAAA) else Color(0xFF666666),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
TextButton(
onClick = { dialogToDelete = null },
modifier = Modifier.weight(1f)
) {
Text("Cancel", fontWeight = FontWeight.Medium)
}
Spacer(modifier = Modifier.width(8.dp))
TextButton(
onClick = {
scope.launch {
chatsViewModel.deleteDialog(dialog.opponentKey)
dialogToDelete = null
}
},
colors = ButtonDefaults.textButtonColors(
contentColor = Color(0xFFFF3B30)
),
modifier = Modifier.weight(1f)
) {
Text("Delete", fontWeight = FontWeight.SemiBold)
Text(
"Are you sure you want to delete this chat? This action cannot be undone.",
color = secondaryTextColor
)
},
confirmButton = {
TextButton(
onClick = {
val opponentKey = dialog.opponentKey
dialogToDelete = null
scope.launch {
chatsViewModel.deleteDialog(opponentKey)
}
}
) {
Text("Delete", color = Color(0xFFFF3B30))
}
},
confirmButton = {},
dismissButton = {},
containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
shape = RoundedCornerShape(16.dp)
dismissButton = {
TextButton(onClick = { dialogToDelete = null }) {
Text("Cancel", color = PrimaryBlue)
}
}
)
}
@@ -648,75 +612,39 @@ fun ChatsListScreen(
dialogToBlock?.let { dialog ->
AlertDialog(
onDismissRequest = { dialogToBlock = null },
icon = {
Icon(
imageVector = Icons.Default.Block,
contentDescription = null,
tint = Color(0xFFFF6B6B),
modifier = Modifier.size(32.dp)
)
},
containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
title = {
Text(
text = "Block user?",
fontWeight = FontWeight.SemiBold,
fontSize = 18.sp,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
"Block ${dialog.opponentTitle.ifEmpty { "User" }}",
fontWeight = FontWeight.Bold,
color = textColor
)
},
text = {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
val displayName = dialog.opponentTitle.ifEmpty { dialog.opponentKey.take(8) }
Text(
text = "$displayName will no longer be able to send you messages. You can unblock them later.",
fontSize = 15.sp,
color = if (isDarkTheme) Color(0xFFAAAAAA) else Color(0xFF666666),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
TextButton(
onClick = { dialogToBlock = null },
modifier = Modifier.weight(1f)
) {
Text("Cancel", fontWeight = FontWeight.Medium)
}
Spacer(modifier = Modifier.width(8.dp))
TextButton(
onClick = {
scope.launch {
chatsViewModel.blockUser(dialog.opponentKey)
dialogToBlock = null
blocklistUpdateTrigger++
}
},
colors = ButtonDefaults.textButtonColors(
contentColor = Color(0xFFFF3B30)
),
modifier = Modifier.weight(1f)
) {
Text("Block", fontWeight = FontWeight.SemiBold)
Text(
"Are you sure you want to block this user? They won't be able to send you messages.",
color = secondaryTextColor
)
},
confirmButton = {
TextButton(
onClick = {
val opponentKey = dialog.opponentKey
dialogToBlock = null
scope.launch {
chatsViewModel.blockUser(opponentKey)
blocklistUpdateTrigger++
}
}
) {
Text("Block", color = Color(0xFFFF3B30))
}
},
confirmButton = {},
dismissButton = {},
containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
shape = RoundedCornerShape(16.dp)
dismissButton = {
TextButton(onClick = { dialogToBlock = null }) {
Text("Cancel", color = PrimaryBlue)
}
}
)
}
@@ -724,75 +652,39 @@ fun ChatsListScreen(
dialogToUnblock?.let { dialog ->
AlertDialog(
onDismissRequest = { dialogToUnblock = null },
icon = {
Icon(
imageVector = Icons.Default.LockOpen,
contentDescription = null,
tint = Color(0xFF4CAF50),
modifier = Modifier.size(32.dp)
)
},
containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
title = {
Text(
text = "Unblock user?",
fontWeight = FontWeight.SemiBold,
fontSize = 18.sp,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
"Unblock ${dialog.opponentTitle.ifEmpty { "User" }}",
fontWeight = FontWeight.Bold,
color = textColor
)
},
text = {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
val displayName = dialog.opponentTitle.ifEmpty { dialog.opponentKey.take(8) }
Text(
text = "$displayName will be able to send you messages again.",
fontSize = 15.sp,
color = if (isDarkTheme) Color(0xFFAAAAAA) else Color(0xFF666666),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
TextButton(
onClick = { dialogToUnblock = null },
modifier = Modifier.weight(1f)
) {
Text("Cancel", fontWeight = FontWeight.Medium)
}
Spacer(modifier = Modifier.width(8.dp))
TextButton(
onClick = {
scope.launch {
chatsViewModel.unblockUser(dialog.opponentKey)
dialogToUnblock = null
blocklistUpdateTrigger++
}
},
colors = ButtonDefaults.textButtonColors(
contentColor = Color(0xFF4CAF50)
),
modifier = Modifier.weight(1f)
) {
Text("Unblock", fontWeight = FontWeight.SemiBold)
Text(
"Are you sure you want to unblock this user? They will be able to send you messages again.",
color = secondaryTextColor
)
},
confirmButton = {
TextButton(
onClick = {
val opponentKey = dialog.opponentKey
dialogToUnblock = null
scope.launch {
chatsViewModel.unblockUser(opponentKey)
blocklistUpdateTrigger++
}
}
) {
Text("Unblock", color = PrimaryBlue)
}
},
confirmButton = {},
dismissButton = {},
containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
shape = RoundedCornerShape(16.dp)
dismissButton = {
TextButton(onClick = { dialogToUnblock = null }) {
Text("Cancel", color = Color(0xFF8E8E93))
}
}
)
}
} // Close Box

View File

@@ -389,11 +389,23 @@ fun AnimatedRosettaLogo(
)
Box(
modifier = modifier,
modifier = modifier
.graphicsLayer {
// Enable hardware acceleration
compositingStrategy = androidx.compose.ui.graphics.CompositingStrategy.Offscreen
},
contentAlignment = Alignment.Center
) {
// Pre-render all animations to avoid lag
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Box(
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
// Hardware layer for better performance
renderEffect = null
},
contentAlignment = Alignment.Center
) {
// Rosetta icon (page 0) with pulse animation like splash screen
if (currentPage == 0) {
val pulseScale by rememberInfiniteTransition(label = "pulse").animateFloat(
@@ -428,70 +440,108 @@ fun AnimatedRosettaLogo(
}
// Fast page - idea animation (page 1)
ideaComposition?.let { comp ->
val lottieComp = comp as? com.airbnb.lottie.LottieComposition
val progress by animateLottieCompositionAsState(
composition = lottieComp,
iterations = 1,
isPlaying = currentPage == 1
)
if (currentPage == 1) {
LottieAnimation(
// Load adjacent pages for smooth swiping
val shouldLoadIdea = currentPage in 0..2
if (shouldLoadIdea) {
ideaComposition?.let { comp ->
val lottieComp = comp as? com.airbnb.lottie.LottieComposition
val progress by animateLottieCompositionAsState(
composition = lottieComp,
progress = { progress },
modifier = Modifier.fillMaxSize()
iterations = 1,
isPlaying = currentPage == 1,
speed = 1.2f // Faster for smoother perception
)
if (currentPage == 1) {
LottieAnimation(
composition = lottieComp,
progress = { progress },
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
// Hardware acceleration for smooth rendering
compositingStrategy = androidx.compose.ui.graphics.CompositingStrategy.Offscreen
},
maintainOriginalImageBounds = true
)
}
}
}
// Free page - money animation (page 2)
moneyComposition?.let { comp ->
val lottieComp = comp as? com.airbnb.lottie.LottieComposition
val progress by animateLottieCompositionAsState(
composition = lottieComp,
iterations = 1,
isPlaying = currentPage == 2
)
if (currentPage == 2) {
LottieAnimation(
val shouldLoadMoney = currentPage in 1..3
if (shouldLoadMoney) {
moneyComposition?.let { comp ->
val lottieComp = comp as? com.airbnb.lottie.LottieComposition
val progress by animateLottieCompositionAsState(
composition = lottieComp,
progress = { progress },
modifier = Modifier.fillMaxSize()
iterations = 1,
isPlaying = currentPage == 2,
speed = 1.2f
)
if (currentPage == 2) {
LottieAnimation(
composition = lottieComp,
progress = { progress },
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
compositingStrategy = androidx.compose.ui.graphics.CompositingStrategy.Offscreen
},
maintainOriginalImageBounds = true
)
}
}
}
// Secure page - lock animation (page 3)
lockComposition?.let { comp ->
val lottieComp = comp as? com.airbnb.lottie.LottieComposition
val progress by animateLottieCompositionAsState(
composition = lottieComp,
iterations = 1,
isPlaying = currentPage == 3
)
if (currentPage == 3) {
LottieAnimation(
val shouldLoadLock = currentPage in 2..4
if (shouldLoadLock) {
lockComposition?.let { comp ->
val lottieComp = comp as? com.airbnb.lottie.LottieComposition
val progress by animateLottieCompositionAsState(
composition = lottieComp,
progress = { progress },
modifier = Modifier.fillMaxSize()
iterations = 1,
isPlaying = currentPage == 3,
speed = 1.2f
)
if (currentPage == 3) {
LottieAnimation(
composition = lottieComp,
progress = { progress },
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
compositingStrategy = androidx.compose.ui.graphics.CompositingStrategy.Offscreen
},
maintainOriginalImageBounds = true
)
}
}
}
// Private page - book animation (page 4)
bookComposition?.let { comp ->
val lottieComp = comp as? com.airbnb.lottie.LottieComposition
val progress by animateLottieCompositionAsState(
composition = lottieComp,
iterations = 1,
isPlaying = currentPage == 4
)
if (currentPage == 4) {
LottieAnimation(
val shouldLoadBook = currentPage in 3..4
if (shouldLoadBook) {
bookComposition?.let { comp ->
val lottieComp = comp as? com.airbnb.lottie.LottieComposition
val progress by animateLottieCompositionAsState(
composition = lottieComp,
progress = { progress },
modifier = Modifier.fillMaxSize()
iterations = 1,
isPlaying = currentPage == 4,
speed = 1.2f
)
if (currentPage == 4) {
LottieAnimation(
composition = lottieComp,
progress = { progress },
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
compositingStrategy = androidx.compose.ui.graphics.CompositingStrategy.Offscreen
},
maintainOriginalImageBounds = true
)
}
}
}
}