♻️ Updated the thought rendering

This commit is contained in:
2025-11-15 22:16:29 +08:00
parent a9c8f49797
commit 35f4d7d885
3 changed files with 203 additions and 237 deletions

View File

@@ -2,46 +2,30 @@ import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gap/gap.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
import 'package:island/models/thought.dart';
class FunctionCallsSection extends StatefulWidget {
class FunctionCallsSection extends HookWidget {
const FunctionCallsSection({
super.key,
required this.isFinish,
required this.isStreaming,
required this.streamingFunctionCalls,
this.thought,
required this.functionCallData,
});
final bool isFinish;
final bool isStreaming;
final List<String> streamingFunctionCalls;
final SnThinkingThought? thought;
@override
State<FunctionCallsSection> createState() => _FunctionCallsSectionState();
}
class _FunctionCallsSectionState extends State<FunctionCallsSection> {
bool _isExpanded = false;
bool get _hasFunctionCalls {
if (widget.isStreaming) {
return widget.streamingFunctionCalls.isNotEmpty;
} else {
return widget.thought!.parts.isNotEmpty &&
widget.thought!.parts.any(
(part) => part.type == ThinkingMessagePartType.functionCall,
);
}
}
final String? functionCallData;
@override
Widget build(BuildContext context) {
if (!_hasFunctionCalls) {
return const SizedBox.shrink();
}
final isExpanded = useState(false);
var functionCallName =
jsonDecode(functionCallData ?? '{}')?['name'] as String?;
if (functionCallName?.isEmpty ?? true) functionCallName = 'unknown'.tr();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -56,7 +40,7 @@ class _FunctionCallsSectionState extends State<FunctionCallsSection> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () => setState(() => _isExpanded = !_isExpanded),
onTap: () => isExpanded.value = !isExpanded.value,
child: Row(
children: [
Icon(
@@ -67,7 +51,9 @@ class _FunctionCallsSectionState extends State<FunctionCallsSection> {
const Gap(4),
Expanded(
child: Text(
'thoughtFunctionCall'.tr(),
isFinish
? 'thoughtFunctionCallFinish'.tr(args: [])
: 'thoughtFunctionCallBegin'.tr(args: []),
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.tertiary,
@@ -75,81 +61,44 @@ class _FunctionCallsSectionState extends State<FunctionCallsSection> {
),
),
Icon(
_isExpanded ? Symbols.expand_more : Symbols.expand_less,
isExpanded.value
? Symbols.expand_more
: Symbols.expand_less,
size: 16,
color: Theme.of(context).colorScheme.tertiary,
),
],
),
),
Visibility(visible: _isExpanded, child: const Gap(4)),
Visibility(visible: isExpanded.value, child: const Gap(4)),
Visibility(
visible: _isExpanded,
visible: isExpanded.value,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (widget.isStreaming) ...[
...widget.streamingFunctionCalls.map(
(call) => Container(
width: double.infinity,
padding: const EdgeInsets.all(8),
margin: const EdgeInsets.only(bottom: 4),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: Theme.of(
context,
).colorScheme.outline.withOpacity(0.3),
width: 1,
),
),
child: SelectableText(
call,
style: GoogleFonts.robotoMono(
fontSize: 11,
color: Theme.of(context).colorScheme.onSurface,
height: 1.3,
),
),
Container(
width: double.infinity,
padding: const EdgeInsets.all(8),
margin: const EdgeInsets.only(bottom: 4),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: Theme.of(
context,
).colorScheme.outline.withOpacity(0.3),
width: 1,
),
),
] else ...[
...widget.thought!.parts
.where(
(part) =>
part.type ==
ThinkingMessagePartType.functionCall,
)
.map(
(part) => Container(
width: double.infinity,
padding: const EdgeInsets.all(8),
margin: const EdgeInsets.only(bottom: 4),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: Theme.of(
context,
).colorScheme.outline.withOpacity(0.3),
width: 1,
),
),
child: SelectableText(
JsonEncoder.withIndent(
' ',
).convert(part.functionCall?.toJson() ?? {}),
style: GoogleFonts.robotoMono(
fontSize: 11,
color:
Theme.of(context).colorScheme.onSurface,
height: 1.3,
),
),
),
),
],
child: SelectableText(
functionCallData!,
style: GoogleFonts.robotoMono(
fontSize: 11,
color: Theme.of(context).colorScheme.onSurface,
height: 1.3,
),
),
),
],
),
),