refactor: improve typing indicator in assistant message widget

- Replaced the previous gradient-based typing indicator with a more dynamic three-dot animation.
- Simplified the animation logic for the typing indicator, enhancing visual feedback and responsiveness.
- Adjusted the layout to ensure proper spacing and prevent clipping during animations.
- Cleaned up the code for better readability and maintainability.
This commit is contained in:
cogwheel0
2025-10-01 01:50:36 +05:30
parent 5a4021aaa9
commit 3faac9f16b

View File

@@ -970,77 +970,57 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
Widget _buildTypingIndicator() {
final theme = context.conduitTheme;
final gradient = LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
theme.surfaceBackground.withValues(alpha: 0.0),
theme.surfaceContainer.withValues(alpha: 0.9),
],
);
final haloColor = theme.textSecondary.withValues(alpha: 0.18);
final dotColor = theme.textSecondary.withValues(alpha: 0.75);
const double dotSize = 8.0;
final min = AnimationValues.typingIndicatorScale;
const double dotSpacing = 6.0;
const int numberOfDots = 3;
final dot =
Container(
// Create three dots with staggered animations
final dots = List.generate(numberOfDots, (index) {
final delay = Duration(milliseconds: 150 * index);
return Container(
width: dotSize,
height: dotSize,
decoration: BoxDecoration(
color: dotColor,
shape: BoxShape.circle,
),
decoration: BoxDecoration(color: dotColor, shape: BoxShape.circle),
)
.animate(onPlay: (controller) => controller.repeat())
.then(delay: delay)
.fadeIn(
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
)
.scale(
duration: AnimationDuration.typingIndicator,
curve: AnimationCurves.typingIndicator,
begin: Offset(min, min),
duration: const Duration(milliseconds: 600),
curve: Curves.easeInOut,
begin: const Offset(0.4, 0.4),
end: const Offset(1, 1),
)
.then(delay: AnimationDelay.typingDelay)
.then()
.scale(
duration: AnimationDuration.typingIndicator,
curve: AnimationCurves.typingIndicator,
begin: const Offset(1, 1),
end: Offset(min, min),
duration: const Duration(milliseconds: 600),
curve: Curves.easeInOut,
begin: const Offset(1.2, 1.2),
end: const Offset(0.5, 0.5),
);
});
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
return Padding(
padding: const EdgeInsets.symmetric(vertical: Spacing.sm),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: Spacing.md),
Padding(
padding: const EdgeInsets.only(left: 4, bottom: 4),
child: Container(
decoration: BoxDecoration(
gradient: gradient,
borderRadius: BorderRadius.circular(16),
),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: SizedBox(
height: dotSize * 2,
width: dotSize * 2,
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: dotSize * 2,
height: dotSize * 2,
decoration: BoxDecoration(
color: haloColor,
shape: BoxShape.circle,
),
),
dot,
// Add left padding to prevent clipping when dots scale up
const SizedBox(width: dotSize * 0.2),
for (int i = 0; i < numberOfDots; i++) ...[
dots[i],
if (i < numberOfDots - 1) const SizedBox(width: dotSpacing),
],
// Add right padding to prevent clipping when dots scale up
const SizedBox(width: dotSize * 0.2),
],
),
),
),
),
],
);
}