feat: Simplify animations across multiple screens by replacing slide transitions with fade animations for improved user experience

This commit is contained in:
2026-01-18 17:26:04 +05:00
parent 89e5f3cfa2
commit 61995e9286
16 changed files with 506 additions and 399 deletions

View File

@@ -159,10 +159,7 @@ fun ConfirmSeedPhraseScreen(
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(250)) + slideInVertically(
initialOffsetY = { -40 },
animationSpec = tween(250)
)
enter = fadeIn(tween(300))
) {
Text(
text = "Confirm Backup",
@@ -176,10 +173,7 @@ fun ConfirmSeedPhraseScreen(
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(500, delayMillis = 100)) + slideInVertically(
initialOffsetY = { -20 },
animationSpec = tween(500, delayMillis = 100)
)
enter = fadeIn(tween(400, delayMillis = 100))
) {
Text(
text = "Enter words #${wordsToConfirm[0].first + 1}, #${wordsToConfirm[1].first + 1}, #${wordsToConfirm[2].first + 1}, #${wordsToConfirm[3].first + 1}\nto confirm you've backed up your phrase.",
@@ -354,10 +348,7 @@ fun ConfirmSeedPhraseScreen(
// Continue Button
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(500, delayMillis = 600)) + slideInVertically(
initialOffsetY = { 50 },
animationSpec = tween(500, delayMillis = 600)
)
enter = fadeIn(tween(400, delayMillis = 600))
) {
Button(
onClick = {
@@ -408,10 +399,7 @@ private fun AnimatedConfirmWordItem(
) {
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(400, delayMillis = delay)) + slideInHorizontally(
initialOffsetX = { if (number <= 6) -50 else 50 },
animationSpec = tween(400, delayMillis = delay)
)
enter = fadeIn(tween(400, delayMillis = delay))
) {
if (isInput) {
ConfirmWordInputItem(

View File

@@ -78,10 +78,7 @@ fun ImportSeedPhraseScreen(
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(250)) + slideInVertically(
initialOffsetY = { -40 },
animationSpec = tween(250)
)
enter = fadeIn(tween(300))
) {
Text(
text = "Import Account",
@@ -95,10 +92,7 @@ fun ImportSeedPhraseScreen(
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(500, delayMillis = 100)) + slideInVertically(
initialOffsetY = { -20 },
animationSpec = tween(500, delayMillis = 100)
)
enter = fadeIn(tween(400, delayMillis = 100))
) {
Text(
text = "Enter your 12-word recovery phrase\nto restore your account.",
@@ -243,10 +237,7 @@ fun ImportSeedPhraseScreen(
// Import button
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(500, delayMillis = 600)) + slideInVertically(
initialOffsetY = { 50 },
animationSpec = tween(500, delayMillis = 600)
)
enter = fadeIn(tween(400, delayMillis = 600))
) {
Button(
onClick = {
@@ -302,10 +293,7 @@ private fun AnimatedWordInputItem(
) {
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(400, delayMillis = delay)) + slideInHorizontally(
initialOffsetX = { if (number <= 6) -50 else 50 },
animationSpec = tween(400, delayMillis = delay)
)
enter = fadeIn(tween(400, delayMillis = delay))
) {
WordInputItem(
number = number,

View File

@@ -80,10 +80,7 @@ fun SeedPhraseScreen(
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(250)) + slideInVertically(
initialOffsetY = { -40 },
animationSpec = tween(250)
)
enter = fadeIn(tween(300))
) {
Text(
text = "Your Recovery Phrase",
@@ -97,10 +94,7 @@ fun SeedPhraseScreen(
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(500, delayMillis = 100)) + slideInVertically(
initialOffsetY = { -20 },
animationSpec = tween(500, delayMillis = 100)
)
enter = fadeIn(tween(400, delayMillis = 100))
) {
Text(
text = "Write down these 12 words in order.\nYou'll need them to restore your account.",
@@ -213,10 +207,7 @@ fun SeedPhraseScreen(
// Continue button
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(500, delayMillis = 700)) + slideInVertically(
initialOffsetY = { 50 },
animationSpec = tween(500, delayMillis = 700)
)
enter = fadeIn(tween(400, delayMillis = 700))
) {
Button(
onClick = { onConfirm(seedPhrase) },
@@ -313,10 +304,7 @@ private fun AnimatedWordItem(
) {
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(400, delayMillis = delay)) + slideInHorizontally(
initialOffsetX = { if (number <= 6) -50 else 50 },
animationSpec = tween(400, delayMillis = delay)
)
enter = fadeIn(tween(400, delayMillis = delay))
) {
WordItem(
number = number,

View File

@@ -103,10 +103,7 @@ fun SelectAccountScreen(
// Header
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(250)) + slideInVertically(
initialOffsetY = { -40 },
animationSpec = tween(250)
)
enter = fadeIn(tween(300))
) {
Column {
Row {
@@ -269,10 +266,7 @@ private fun AccountListItem(
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(200)) + slideInHorizontally(
initialOffsetX = { 50 },
animationSpec = tween(200)
)
enter = fadeIn(tween(300))
) {
Card(
modifier = Modifier
@@ -378,10 +372,7 @@ private fun AddAccountButton(
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(200)) + slideInHorizontally(
initialOffsetX = { -50 },
animationSpec = tween(200)
)
enter = fadeIn(tween(300))
) {
Card(
modifier = Modifier

View File

@@ -178,12 +178,7 @@ fun SetPasswordScreen(
AnimatedVisibility(
visible = visible,
enter =
fadeIn(tween(500, delayMillis = 100)) +
slideInVertically(
initialOffsetY = { -20 },
animationSpec = tween(500, delayMillis = 100)
)
enter = fadeIn(tween(400, delayMillis = 100))
) {
Text(
text = "Protect Your Account",
@@ -214,12 +209,7 @@ fun SetPasswordScreen(
// Password Field
AnimatedVisibility(
visible = visible,
enter =
fadeIn(tween(500, delayMillis = 300)) +
slideInVertically(
initialOffsetY = { 50 },
animationSpec = tween(500, delayMillis = 300)
)
enter = fadeIn(tween(400, delayMillis = 300))
) {
OutlinedTextField(
value = password,
@@ -270,12 +260,7 @@ fun SetPasswordScreen(
Spacer(modifier = Modifier.height(8.dp))
AnimatedVisibility(
visible = visible,
enter =
fadeIn(tween(400, delayMillis = 350)) +
slideInHorizontally(
initialOffsetX = { -30 },
animationSpec = tween(400, delayMillis = 350)
)
enter = fadeIn(tween(400, delayMillis = 350))
) {
Column(modifier = Modifier.fillMaxWidth()) {
Row(
@@ -345,12 +330,7 @@ fun SetPasswordScreen(
// Confirm Password Field
AnimatedVisibility(
visible = visible,
enter =
fadeIn(tween(500, delayMillis = 400)) +
slideInVertically(
initialOffsetY = { 50 },
animationSpec = tween(500, delayMillis = 400)
)
enter = fadeIn(tween(400, delayMillis = 400))
) {
OutlinedTextField(
value = confirmPassword,
@@ -407,12 +387,7 @@ fun SetPasswordScreen(
Spacer(modifier = Modifier.height(8.dp))
AnimatedVisibility(
visible = visible,
enter =
fadeIn(tween(400, delayMillis = 450)) +
slideInHorizontally(
initialOffsetX = { -30 },
animationSpec = tween(400, delayMillis = 450)
)
enter = fadeIn(tween(400, delayMillis = 450))
) {
Row(
modifier = Modifier.fillMaxWidth(),
@@ -459,20 +434,8 @@ fun SetPasswordScreen(
// Info - hide when keyboard is visible
AnimatedVisibility(
visible = visible && !isKeyboardVisible,
enter =
fadeIn(tween(200)) +
slideInVertically(
initialOffsetY = { 30 },
animationSpec = tween(200)
) +
scaleIn(initialScale = 0.9f, animationSpec = tween(200)),
exit =
fadeOut(tween(150)) +
slideOutVertically(
targetOffsetY = { 30 },
animationSpec = tween(150)
) +
scaleOut(targetScale = 0.9f, animationSpec = tween(150))
enter = fadeIn(tween(300)),
exit = fadeOut(tween(200))
) {
Row(
modifier =
@@ -504,12 +467,7 @@ fun SetPasswordScreen(
// Create Account Button
AnimatedVisibility(
visible = visible,
enter =
fadeIn(tween(500, delayMillis = 600)) +
slideInVertically(
initialOffsetY = { 50 },
animationSpec = tween(500, delayMillis = 600)
)
enter = fadeIn(tween(400, delayMillis = 600))
) {
Button(
onClick = {

View File

@@ -38,6 +38,7 @@ import com.rosetta.messenger.data.AccountManager
import com.rosetta.messenger.data.DecryptedAccount
import com.rosetta.messenger.data.EncryptedAccount
import com.rosetta.messenger.network.ProtocolManager
import com.rosetta.messenger.network.ProtocolState
import com.rosetta.messenger.ui.chats.getAvatarColor
import com.rosetta.messenger.ui.chats.getAvatarText
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
@@ -195,12 +196,7 @@ fun UnlockScreen(
// Title
AnimatedVisibility(
visible = visible,
enter =
fadeIn(tween(600, delayMillis = 200)) +
slideInVertically(
initialOffsetY = { 30 },
animationSpec = tween(600, delayMillis = 200)
)
enter = fadeIn(tween(400, delayMillis = 200))
) {
Text(
text = "Welcome Back",
@@ -226,12 +222,7 @@ fun UnlockScreen(
// Account Selector Card
AnimatedVisibility(
visible = visible,
enter =
fadeIn(tween(600, delayMillis = 350)) +
slideInVertically(
initialOffsetY = { 50 },
animationSpec = tween(600, delayMillis = 350)
)
enter = fadeIn(tween(400, delayMillis = 350))
) {
Column {
// Account selector dropdown
@@ -511,12 +502,7 @@ fun UnlockScreen(
// Password Field
AnimatedVisibility(
visible = visible && !isDropdownExpanded,
enter =
fadeIn(tween(600, delayMillis = 400)) +
slideInVertically(
initialOffsetY = { 50 },
animationSpec = tween(600, delayMillis = 400)
)
enter = fadeIn(tween(400, delayMillis = 400))
) {
OutlinedTextField(
value = password,
@@ -566,8 +552,8 @@ fun UnlockScreen(
// Error message
AnimatedVisibility(
visible = error != null,
enter = fadeIn() + slideInVertically { -10 },
exit = fadeOut()
enter = fadeIn(tween(200)),
exit = fadeOut(tween(150))
) {
Spacer(modifier = Modifier.height(8.dp))
Text(text = error ?: "", fontSize = 14.sp, color = Color(0xFFE53935))
@@ -578,12 +564,7 @@ fun UnlockScreen(
// Unlock Button
AnimatedVisibility(
visible = visible && !isDropdownExpanded,
enter =
fadeIn(tween(600, delayMillis = 500)) +
slideInVertically(
initialOffsetY = { 50 },
animationSpec = tween(600, delayMillis = 500)
)
enter = fadeIn(tween(400, delayMillis = 500))
) {
Button(
onClick = {
@@ -636,13 +617,37 @@ fun UnlockScreen(
name = account.name
)
android.util.Log.d("UnlockScreen", "🔐 Starting connection and authentication...")
android.util.Log.d("UnlockScreen", " PublicKey: ${account.publicKey.take(16)}...")
android.util.Log.d("UnlockScreen", " PrivateKeyHash: ${privateKeyHash.take(16)}...")
// Connect to server and authenticate
ProtocolManager.connect()
// Give WebSocket time to connect before authenticating
kotlinx.coroutines.delay(500)
// 🔥 Ждем пока websocket подключится (CONNECTED state)
var waitAttempts = 0
while (ProtocolManager.state.value == ProtocolState.DISCONNECTED && waitAttempts < 50) {
kotlinx.coroutines.delay(100)
waitAttempts++
}
android.util.Log.d("UnlockScreen", "🔌 Connection state after wait: ${ProtocolManager.state.value}")
if (ProtocolManager.state.value == ProtocolState.DISCONNECTED) {
error = "Failed to connect to server"
isUnlocking = false
return@launch
}
// Еще немного ждем для стабильности
kotlinx.coroutines.delay(300)
android.util.Log.d("UnlockScreen", "🔐 Starting authentication...")
ProtocolManager.authenticate(account.publicKey, privateKeyHash)
accountManager.setCurrentAccount(account.publicKey)
android.util.Log.d("UnlockScreen", "✅ Unlock complete, calling onUnlocked callback")
onUnlocked(decryptedAccount)
} catch (e: Exception) {
error = "Failed to unlock: \${e.message}"
@@ -684,12 +689,7 @@ fun UnlockScreen(
// Create New Account button
AnimatedVisibility(
visible = visible && !isDropdownExpanded,
enter =
fadeIn(tween(600, delayMillis = 600)) +
slideInVertically(
initialOffsetY = { 50 },
animationSpec = tween(600, delayMillis = 600)
)
enter = fadeIn(tween(400, delayMillis = 600))
) {
TextButton(onClick = onSwitchAccount) {
Icon(

View File

@@ -115,12 +115,7 @@ fun WelcomeScreen(
// Title
AnimatedVisibility(
visible = visible,
enter =
fadeIn(tween(600, delayMillis = 200)) +
slideInVertically(
initialOffsetY = { 50 },
animationSpec = tween(600, delayMillis = 200)
)
enter = fadeIn(tween(400, delayMillis = 200))
) {
Text(
text = "Your Keys,\nYour Messages",
@@ -137,12 +132,7 @@ fun WelcomeScreen(
// Subtitle
AnimatedVisibility(
visible = visible,
enter =
fadeIn(tween(600, delayMillis = 300)) +
slideInVertically(
initialOffsetY = { 50 },
animationSpec = tween(600, delayMillis = 300)
)
enter = fadeIn(tween(400, delayMillis = 300))
) {
Text(
text = "Secure messaging with\ncryptographic keys",
@@ -188,12 +178,7 @@ fun WelcomeScreen(
// Create Seed Button
AnimatedVisibility(
visible = visible,
enter =
fadeIn(tween(600, delayMillis = 500)) +
slideInVertically(
initialOffsetY = { 100 },
animationSpec = tween(600, delayMillis = 500)
)
enter = fadeIn(tween(400, delayMillis = 500))
) {
Button(
onClick = onCreateSeed,
@@ -229,12 +214,7 @@ fun WelcomeScreen(
// Import Seed Button
AnimatedVisibility(
visible = visible,
enter =
fadeIn(tween(600, delayMillis = 600)) +
slideInVertically(
initialOffsetY = { 100 },
animationSpec = tween(600, delayMillis = 600)
)
enter = fadeIn(tween(400, delayMillis = 600))
) {
TextButton(
onClick = onImportSeed,