feat: add image, link, schedule, and error animations in composer

This commit is contained in:
Paweł Orzech 2026-03-19 14:23:25 +01:00
parent 0713bd912e
commit 188c62f076
No known key found for this signature in database

View file

@ -3,6 +3,8 @@ package com.swoosh.microblog.ui.composer
import android.net.Uri import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridCells
@ -37,6 +39,8 @@ import coil.compose.AsyncImage
import com.swoosh.microblog.data.HashtagParser import com.swoosh.microblog.data.HashtagParser
import com.swoosh.microblog.data.model.FeedPost import com.swoosh.microblog.data.model.FeedPost
import com.swoosh.microblog.data.model.PostStats import com.swoosh.microblog.data.model.PostStats
import com.swoosh.microblog.ui.animation.SwooshMotion
import com.swoosh.microblog.ui.components.PulsingPlaceholder
import com.swoosh.microblog.ui.preview.HtmlPreviewWebView import com.swoosh.microblog.ui.preview.HtmlPreviewWebView
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.ZoneId import java.time.ZoneId
@ -274,7 +278,12 @@ fun ComposerScreen(
} }
// Image grid preview (multi-image) // Image grid preview (multi-image)
if (state.imageUris.isNotEmpty()) { AnimatedVisibility(
visible = state.imageUris.isNotEmpty(),
enter = scaleIn(initialScale = 0f, animationSpec = SwooshMotion.bouncy()) + fadeIn(SwooshMotion.quick()),
exit = scaleOut(animationSpec = SwooshMotion.quick()) + fadeOut(SwooshMotion.quick())
) {
Column {
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
ImageGridPreview( ImageGridPreview(
imageUris = state.imageUris, imageUris = state.imageUris,
@ -310,14 +319,26 @@ fun ComposerScreen(
) )
} }
} }
// Link preview
if (state.isLoadingLink) {
Spacer(modifier = Modifier.height(12.dp))
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
} }
if (state.linkPreview != null) { // Link preview
AnimatedVisibility(
visible = state.isLoadingLink,
enter = fadeIn(SwooshMotion.quick()),
exit = fadeOut(SwooshMotion.quick())
) {
Column {
Spacer(modifier = Modifier.height(12.dp))
PulsingPlaceholder(height = 80.dp)
}
}
AnimatedVisibility(
visible = state.linkPreview != null && !state.isLoadingLink,
enter = slideInVertically(initialOffsetY = { it / 2 }, animationSpec = SwooshMotion.gentle()) + fadeIn(SwooshMotion.quick()),
exit = fadeOut(SwooshMotion.quick())
) {
Column {
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
OutlinedCard(modifier = Modifier.fillMaxWidth()) { OutlinedCard(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(12.dp)) { Column(modifier = Modifier.padding(12.dp)) {
@ -358,9 +379,15 @@ fun ComposerScreen(
} }
} }
} }
}
// Scheduled time display // Scheduled time display
if (state.scheduledAt != null) { AnimatedVisibility(
visible = state.scheduledAt != null,
enter = scaleIn(animationSpec = SwooshMotion.bouncy()) + fadeIn(SwooshMotion.quick()),
exit = scaleOut(animationSpec = SwooshMotion.quick()) + fadeOut(SwooshMotion.quick())
) {
Column {
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
AssistChip( AssistChip(
onClick = { showDatePicker = true }, onClick = { showDatePicker = true },
@ -376,6 +403,7 @@ fun ComposerScreen(
} }
) )
} }
}
// Feature toggle // Feature toggle
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
@ -404,7 +432,12 @@ fun ComposerScreen(
) )
} }
if (state.error != null) { AnimatedVisibility(
visible = state.error != null,
enter = slideInHorizontally(initialOffsetX = { -it / 4 }, animationSpec = SwooshMotion.snappy()) + fadeIn(SwooshMotion.quick()),
exit = fadeOut(SwooshMotion.quick())
) {
Column {
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
Text( Text(
text = state.error!!, text = state.error!!,
@ -412,6 +445,7 @@ fun ComposerScreen(
style = MaterialTheme.typography.bodySmall style = MaterialTheme.typography.bodySmall
) )
} }
}
Spacer(modifier = Modifier.height(24.dp)) Spacer(modifier = Modifier.height(24.dp))
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))