feat: add expand, queue chip, and account switcher animations

- F4: AnimatedContent with expand/shrink transitions on "Show more" text
- F6: Pulsing alpha animation on queue chip when status is UPLOADING
- F10: Staggered slideInHorizontally + fadeIn entrance for account switcher items
This commit is contained in:
Paweł Orzech 2026-03-19 14:21:12 +01:00
parent 5ab2cbafdc
commit 0713bd912e
No known key found for this signature in database

View file

@ -7,6 +7,7 @@ import android.content.Intent
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
@ -1124,14 +1125,27 @@ fun AccountSwitcherBottomSheet(
modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp)
)
accounts.forEach { account ->
AccountListItem(
account = account,
isActive = account.id == activeAccountId,
onClick = { onAccountSelected(account.id) },
onDelete = { onDeleteAccount(account) },
onRename = { onRenameAccount(account) }
)
accounts.forEachIndexed { index, account ->
var itemVisible by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
delay(SwooshMotion.StaggerDelayMs * index)
itemVisible = true
}
AnimatedVisibility(
visible = itemVisible,
enter = slideInHorizontally(
initialOffsetX = { -it / 4 },
animationSpec = SwooshMotion.gentle()
) + fadeIn(SwooshMotion.quick())
) {
AccountListItem(
account = account,
isActive = account.id == activeAccountId,
onClick = { onAccountSelected(account.id) },
onDelete = { onDeleteAccount(account) },
onRename = { onRenameAccount(account) }
)
}
}
if (accounts.size < 5) {
@ -1475,25 +1489,32 @@ fun PostCardContent(
maxLines = if (expanded) Int.MAX_VALUE else 8
)
} else {
Text(
text = displayText,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurface,
maxLines = if (expanded) Int.MAX_VALUE else 8,
overflow = TextOverflow.Ellipsis
)
}
if (!expanded && post.textContent.length > 280) {
Spacer(modifier = Modifier.height(4.dp))
Text(
text = "Show more",
style = MaterialTheme.typography.labelMedium.copy(fontWeight = FontWeight.Bold),
color = MaterialTheme.colorScheme.primary,
modifier = Modifier
.clickable { expanded = true }
.padding(vertical = 2.dp)
)
AnimatedContent(
targetState = expanded,
transitionSpec = {
(fadeIn(SwooshMotion.quick()) + expandVertically(animationSpec = SwooshMotion.snappy()))
.togetherWith(fadeOut(SwooshMotion.quick()) + shrinkVertically(animationSpec = SwooshMotion.snappy()))
},
label = "expandText"
) { isExpanded ->
Column {
Text(
text = if (isExpanded || post.textContent.length <= 280) post.textContent
else post.textContent.take(280) + "...",
style = MaterialTheme.typography.bodyMedium,
maxLines = if (isExpanded) Int.MAX_VALUE else 8,
overflow = TextOverflow.Ellipsis
)
if (!isExpanded && post.textContent.length > 280) {
TextButton(
onClick = { expanded = true },
contentPadding = PaddingValues(0.dp)
) {
Text("Show more", style = MaterialTheme.typography.labelMedium)
}
}
}
}
}
// Image grid
@ -1595,10 +1616,22 @@ fun PostCardContent(
QueueStatus.FAILED -> "Upload failed"
else -> ""
}
val isUploading = post.queueStatus == QueueStatus.UPLOADING
val infiniteTransition = rememberInfiniteTransition(label = "queuePulse")
val chipAlpha by infiniteTransition.animateFloat(
initialValue = if (isUploading) 0.6f else 1f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(600),
repeatMode = RepeatMode.Reverse
),
label = "uploadPulse"
)
Row(verticalAlignment = Alignment.CenterVertically) {
AssistChip(
onClick = {},
label = { Text(queueLabel, style = MaterialTheme.typography.labelSmall) }
label = { Text(queueLabel, style = MaterialTheme.typography.labelSmall) },
modifier = Modifier.graphicsLayer { alpha = if (isUploading) chipAlpha else 1f }
)
if (post.queueStatus == QueueStatus.QUEUED_PUBLISH || post.queueStatus == QueueStatus.QUEUED_SCHEDULED) {
Spacer(modifier = Modifier.width(8.dp))