feat: 优化 Agent 运行时与聊天设置体验

This commit is contained in:
qzl
2026-03-16 18:32:09 +08:00
parent 3f79cf0df7
commit 5a34616287
41 changed files with 2603 additions and 1263 deletions
@@ -10,6 +10,7 @@ import '../../../../core/api/api_exception.dart';
import '../../../../core/di/injection.dart';
import '../../../../core/theme/design_tokens.dart';
import '../../../chat/data/models/chat_list_item.dart';
import '../../../chat/presentation/bloc/agent_stage.dart';
import '../../../chat/presentation/bloc/chat_bloc.dart';
import '../../../messages/data/inbox_api.dart';
import '../../data/voice_recorder.dart';
@@ -49,6 +50,14 @@ const homeEmptyStateAmbientKey = ValueKey('home_empty_state_ambient');
const _chatBgColor = AppColors.slate50;
const _userBubbleColor = AppColors.blue50;
/// 录制状态颜色
const _recordingCancelTopColor = AppColors.warningBackground;
const _recordingCancelBottomColor = AppColors.red400;
const _recordingCancelLabelColor = AppColors.red600;
const _recordingActiveTopColor = AppColors.blue50;
const _recordingActiveBottomColor = AppColors.blue400;
const _recordingActiveLabelColor = AppColors.white;
class HomeScreen extends StatefulWidget {
final VoiceRecorder? voiceRecorder;
final Future<String> Function(String filePath)? onTranscribeAudio;
@@ -258,12 +267,7 @@ class _HomeScreenState extends State<HomeScreen>
}
Widget _buildWaitingIndicator({required AgentStage? currentStage}) {
final label = switch (currentStage) {
AgentStage.intent => '意图识别中',
AgentStage.execution => '任务执行中',
AgentStage.report => '结果总结中',
null => '正在思考...',
};
final label = stageLabel(currentStage);
return Padding(
padding: const EdgeInsets.fromLTRB(
_defaultPadding,
@@ -490,12 +494,12 @@ class _HomeScreenState extends State<HomeScreen>
Widget _buildToolCallItem(ToolCallItem item) {
final (statusText, statusColor, statusIcon) = switch (item.status) {
ToolCallStatus.pending => (
'准备中...',
'工具准备中',
AppColors.slate500,
LucideIcons.clock,
),
ToolCallStatus.executing => (
'执行中...',
'任务执行中',
AppColors.blue600,
LucideIcons.loader,
),
@@ -512,27 +516,51 @@ class _HomeScreenState extends State<HomeScreen>
};
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
width: double.infinity,
padding: const EdgeInsets.all(AppSpacing.md),
decoration: BoxDecoration(
color: AppColors.blue50,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColors.slate300),
color: AppColors.surfaceInfoLight,
borderRadius: BorderRadius.circular(AppRadius.lg),
border: Border.all(color: AppColors.borderTertiary),
),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(statusIcon, size: 16, color: statusColor),
const SizedBox(width: AppSpacing.sm),
Text(
item.toolName,
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: AppColors.slate700,
Container(
width: 28,
height: 28,
decoration: BoxDecoration(
color: AppColors.white,
borderRadius: BorderRadius.circular(AppRadius.full),
border: Border.all(color: AppColors.borderTertiary),
),
child: Icon(statusIcon, size: 14, color: statusColor),
),
const SizedBox(width: AppSpacing.sm),
Text(statusText, style: TextStyle(fontSize: 12, color: statusColor)),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.toolName,
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w700,
color: AppColors.slate800,
),
),
const SizedBox(height: AppSpacing.xs),
Text(
statusText,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: statusColor,
),
),
],
),
),
],
),
);
@@ -819,16 +847,17 @@ class _HomeScreenState extends State<HomeScreen>
}
Widget _buildRecordingGestureOverlay() {
final topColor = _isCancelGestureActive
? AppColors.warningBackground
: AppColors.blue50;
final bottomColor = _isCancelGestureActive
? AppColors.red400
: AppColors.blue400;
final labelColor = _isCancelGestureActive
? AppColors.red600
: AppColors.white;
final label = _isCancelGestureActive ? '松手取消' : '松手发送,上移取消';
final isCancel = _isCancelGestureActive;
final topColor = isCancel
? _recordingCancelTopColor
: _recordingActiveTopColor;
final bottomColor = isCancel
? _recordingCancelBottomColor
: _recordingActiveBottomColor;
final labelColor = isCancel
? _recordingCancelLabelColor
: _recordingActiveLabelColor;
final label = isCancel ? '松手取消' : '松手发送,上移取消';
return IgnorePointer(
child: Align(