diff --git a/app/src/main/java/com/swoosh/microblog/ui/feed/FeedScreen.kt b/app/src/main/java/com/swoosh/microblog/ui/feed/FeedScreen.kt index f54b4c4..2bb06d8 100644 --- a/app/src/main/java/com/swoosh/microblog/ui/feed/FeedScreen.kt +++ b/app/src/main/java/com/swoosh/microblog/ui/feed/FeedScreen.kt @@ -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))