💫 Message list fully animated

This commit is contained in:
2025-10-13 00:16:50 +08:00
parent 51b4754182
commit 8d1c145b0b

View File

@@ -561,13 +561,31 @@ class ChatRoomScreen extends HookConsumerWidget {
.abs() > .abs() >
3; 3;
final key = ValueKey('$messageKeyPrefix${message.id}'); // Use a stable animation key that doesn't change during message lifecycle
final animationKey = ValueKey(
'message-anim-${message.nonce ?? message.id}',
);
return chatIdentity.when( return TweenAnimationBuilder<double>(
key: animationKey,
tween: Tween<double>(begin: 0.0, end: 1.0),
duration: Duration(
milliseconds: 400 + (index % 5) * 50,
), // Staggered delay
curve: Curves.easeOutCubic,
builder: (context, animationValue, child) {
return Transform.translate(
offset: Offset(
0,
20 * (1 - animationValue),
), // Slide up from bottom
child: Opacity(opacity: animationValue, child: child),
);
},
child: chatIdentity.when(
skipError: true, skipError: true,
data: data:
(identity) => MessageItem( (identity) => MessageItem(
key: key,
message: message, message: message,
isCurrentUser: identity?.id == message.senderId, isCurrentUser: identity?.id == message.senderId,
onAction: (action) { onAction: (action) {
@@ -605,7 +623,6 @@ class ChatRoomScreen extends HookConsumerWidget {
), ),
loading: loading:
() => MessageItem( () => MessageItem(
key: key,
message: message, message: message,
isCurrentUser: false, isCurrentUser: false,
onAction: null, onAction: null,
@@ -613,7 +630,8 @@ class ChatRoomScreen extends HookConsumerWidget {
showAvatar: false, showAvatar: false,
onJump: (_) {}, onJump: (_) {},
), ),
error: (_, _) => SizedBox.shrink(key: key), error: (_, _) => SizedBox.shrink(),
),
); );
}, },
); );
@@ -692,21 +710,45 @@ class ChatRoomScreen extends HookConsumerWidget {
child: Column( child: Column(
children: [ children: [
Expanded( Expanded(
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
switchInCurve: Curves.easeOutCubic,
switchOutCurve: Curves.easeInCubic,
transitionBuilder: (
Widget child,
Animation<double> animation,
) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.05),
end: Offset.zero,
).animate(animation),
child: FadeTransition(opacity: animation, child: child),
);
},
child: messages.when( child: messages.when(
data: data:
(messageList) => (messageList) =>
messageList.isEmpty messageList.isEmpty
? Center(child: Text('No messages yet'.tr())) ? Center(
key: const ValueKey('empty-messages'),
child: Text('No messages yet'.tr()),
)
: chatMessageListWidget(messageList), : chatMessageListWidget(messageList),
loading: loading:
() => const Center(child: CircularProgressIndicator()), () => const Center(
key: ValueKey('loading-messages'),
child: CircularProgressIndicator(),
),
error: error:
(error, _) => ResponseErrorWidget( (error, _) => ResponseErrorWidget(
key: const ValueKey('error-messages'),
error: error, error: error,
onRetry: () => messagesNotifier.loadInitial(), onRetry: () => messagesNotifier.loadInitial(),
), ),
), ),
), ),
),
chatRoom.when( chatRoom.when(
data: data:
(room) => Column( (room) => Column(