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() { Widget _buildTypingIndicator() {
final theme = context.conduitTheme; 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); final dotColor = theme.textSecondary.withValues(alpha: 0.75);
const double dotSize = 8.0; const double dotSize = 8.0;
final min = AnimationValues.typingIndicatorScale; const double dotSpacing = 6.0;
const int numberOfDots = 3;
final dot = // Create three dots with staggered animations
Container( final dots = List.generate(numberOfDots, (index) {
width: dotSize, final delay = Duration(milliseconds: 150 * index);
height: dotSize,
decoration: BoxDecoration(
color: dotColor,
shape: BoxShape.circle,
),
)
.animate(onPlay: (controller) => controller.repeat())
.scale(
duration: AnimationDuration.typingIndicator,
curve: AnimationCurves.typingIndicator,
begin: Offset(min, min),
end: const Offset(1, 1),
)
.then(delay: AnimationDelay.typingDelay)
.scale(
duration: AnimationDuration.typingIndicator,
curve: AnimationCurves.typingIndicator,
begin: const Offset(1, 1),
end: Offset(min, min),
);
return Column( return Container(
crossAxisAlignment: CrossAxisAlignment.start, width: dotSize,
children: [ height: dotSize,
const SizedBox(height: Spacing.md), decoration: BoxDecoration(color: dotColor, shape: BoxShape.circle),
Padding( )
padding: const EdgeInsets.only(left: 4, bottom: 4), .animate(onPlay: (controller) => controller.repeat())
child: Container( .then(delay: delay)
decoration: BoxDecoration( .fadeIn(
gradient: gradient, duration: const Duration(milliseconds: 300),
borderRadius: BorderRadius.circular(16), curve: Curves.easeOut,
), )
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), .scale(
child: SizedBox( duration: const Duration(milliseconds: 600),
height: dotSize * 2, curve: Curves.easeInOut,
width: dotSize * 2, begin: const Offset(0.4, 0.4),
child: Stack( end: const Offset(1, 1),
alignment: Alignment.center, )
children: [ .then()
Container( .scale(
width: dotSize * 2, duration: const Duration(milliseconds: 600),
height: dotSize * 2, curve: Curves.easeInOut,
decoration: BoxDecoration( begin: const Offset(1.2, 1.2),
color: haloColor, end: const Offset(0.5, 0.5),
shape: BoxShape.circle, );
), });
),
dot, return Padding(
], padding: const EdgeInsets.symmetric(vertical: Spacing.sm),
), child: Row(
), mainAxisSize: MainAxisSize.min,
), children: [
), // 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),
],
),
); );
} }