From f14da0d3a2349422cdc1f3ac31276864a71056b1 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 15 Nov 2025 23:22:07 +0800 Subject: [PATCH] :dizzy: Add tool call calling hint animation --- .../thought/function_calls_section.dart | 94 ++++++++++++------- pubspec.lock | 16 ++++ pubspec.yaml | 1 + 3 files changed, 76 insertions(+), 35 deletions(-) diff --git a/lib/widgets/thought/function_calls_section.dart b/lib/widgets/thought/function_calls_section.dart index 70bf08da..fc3496c0 100644 --- a/lib/widgets/thought/function_calls_section.dart +++ b/lib/widgets/thought/function_calls_section.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -34,7 +35,7 @@ class FunctionCallsSection extends HookWidget { } if (functionCallName.isEmpty) functionCallName = 'unknown'.tr(); - final showSpinner = isStreaming && !isFinish; + final showSpinner = !(isStreaming && !isFinish); final isExpanded = useState(false); @@ -51,11 +52,6 @@ class FunctionCallsSection extends HookWidget { collapsedShape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), - leading: Icon( - Symbols.hardware, - size: 16, - color: Theme.of(context).colorScheme.tertiary, - ), trailing: SizedBox( width: 30, // Specify desired width height: 30, // Specify desired height @@ -70,8 +66,15 @@ class FunctionCallsSection extends HookWidget { : Theme.of(context).colorScheme.tertiaryFixedDim, ), ), + showTrailingIcon: !showSpinner, title: Row( + spacing: 8, children: [ + Icon( + Symbols.hardware, + size: 16, + color: Theme.of(context).colorScheme.tertiary, + ), Expanded( child: Text( 'thoughtFunctionCall'.tr(args: [functionCallName]), @@ -81,12 +84,29 @@ class FunctionCallsSection extends HookWidget { ), ), ), - if (showSpinner) + if (showSpinner) ...[ + AnimateWidgetExtensions( + Text( + 'Calling', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Theme.of(context).colorScheme.primary, + ), + ), + ) + .animate( + autoPlay: true, + onPlay: (c) => c.repeat(reverse: true), + ) + .fade(duration: 1000.ms, begin: 0, end: 1), const SizedBox( - height: 14, - width: 14, - child: CircularProgressIndicator(strokeWidth: 2), - ), + height: 16, + width: 16, + child: CircularProgressIndicator( + strokeWidth: 2, + padding: EdgeInsets.all(3), + ), + ).padding(right: 8), + ], ], ), childrenPadding: const EdgeInsets.symmetric( @@ -137,34 +157,38 @@ class FunctionCallsSection extends HookWidget { ), const Gap(4), if (isResult) - Row( - spacing: 8, - children: [ - Icon(Symbols.update, size: 16), - Expanded( - child: Text( - 'Generated ${utf8.encode(data).length} bytes', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w500, - color: Theme.of(context).colorScheme.onSurface, + Opacity( + opacity: 0.8, + child: Row( + spacing: 8, + children: [ + Icon(Symbols.update, size: 16), + Expanded( + child: Text( + 'Generated ${utf8.encode(data).length} bytes', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w500, + color: Theme.of(context).colorScheme.onSurface, + ), ), ), - ), - SizedBox( - height: 16, - child: IconButton( - iconSize: 16, - icon: const Icon(Symbols.content_copy), - onPressed: () => Clipboard.setData(ClipboardData(text: data)), - tooltip: 'Copy response', - visualDensity: const VisualDensity( - horizontal: -4, - vertical: -4, + SizedBox( + height: 16, + child: IconButton( + iconSize: 16, + icon: const Icon(Symbols.content_copy), + onPressed: + () => Clipboard.setData(ClipboardData(text: data)), + tooltip: 'Copy response', + visualDensity: const VisualDensity( + horizontal: -4, + vertical: -4, + ), ), ), - ), - ], - ).opacity(0.8) + ], + ), + ) else Container( width: double.infinity, diff --git a/pubspec.lock b/pubspec.lock index 466ccb2d..efda9711 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -726,6 +726,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_animate: + dependency: "direct main" + description: + name: flutter_animate + sha256: "7befe2d3252728afb77aecaaea1dec88a89d35b9b1d2eea6d04479e8af9117b5" + url: "https://pub.dev" + source: hosted + version: "4.5.2" flutter_app_update: dependency: "direct main" description: @@ -1075,6 +1083,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + flutter_shaders: + dependency: transitive + description: + name: flutter_shaders + sha256: "34794acadd8275d971e02df03afee3dee0f98dbfb8c4837082ad0034f612a3e2" + url: "https://pub.dev" + source: hosted + version: "0.1.3" flutter_staggered_grid_view: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 785a185f..d01a3b1f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -168,6 +168,7 @@ dependencies: event_bus: ^2.0.1 convert: ^3.1.2 desktop_drop: ^0.7.0 + flutter_animate: ^4.5.0 dev_dependencies: flutter_test: