refactor(apps): 主题系统迁移至 ColorScheme + 扩展架构并支持 Dark Mode

This commit is contained in:
qzl
2026-03-27 19:07:39 +08:00
parent ecc1ec6ce4
commit ae29a8209b
146 changed files with 4301 additions and 3200 deletions
+25
View File
@@ -0,0 +1,25 @@
import '../l10n/l10n.dart';
enum AgentStage { routing, execution, memory }
AgentStage? stageFromStepName(String value) {
switch (value) {
case 'router':
return AgentStage.routing;
case 'worker':
return AgentStage.execution;
case 'memory':
return AgentStage.memory;
default:
return null;
}
}
String stageLabel(AgentStage? stage) {
return switch (stage) {
AgentStage.routing => L10n.current.agentStageRouting,
AgentStage.execution => L10n.current.agentStageExecution,
AgentStage.memory => L10n.current.agentStageMemory,
null => L10n.current.agentStageProcessing,
};
}
+122
View File
@@ -0,0 +1,122 @@
enum ChatItemType { message, toolCall, toolResult }
enum MessageSender { user, ai }
enum ToolCallStatus { pending, executing, completed, error }
abstract class ChatListItem {
String get id;
DateTime get timestamp;
ChatItemType get type;
MessageSender get sender;
}
class TextMessageItem extends ChatListItem {
@override
final String id;
final String content;
@override
final DateTime timestamp;
@override
final MessageSender sender;
final bool isStreaming;
final List<Map<String, dynamic>> attachments;
TextMessageItem({
required this.id,
required this.content,
required this.timestamp,
required this.sender,
this.isStreaming = false,
this.attachments = const [],
});
@override
ChatItemType get type => ChatItemType.message;
TextMessageItem copyWith({
String? id,
String? content,
DateTime? timestamp,
MessageSender? sender,
bool? isStreaming,
List<Map<String, dynamic>>? attachments,
}) => TextMessageItem(
id: id ?? this.id,
content: content ?? this.content,
timestamp: timestamp ?? this.timestamp,
sender: sender ?? this.sender,
isStreaming: isStreaming ?? this.isStreaming,
attachments: attachments ?? this.attachments,
);
}
class ToolCallItem extends ChatListItem {
@override
final String id;
final String callId;
final String toolName;
final Map<String, dynamic> args;
final ToolCallStatus status;
final String? errorMessage;
@override
final DateTime timestamp;
@override
final MessageSender sender;
ToolCallItem({
required this.id,
required this.callId,
required this.toolName,
required this.args,
required this.status,
this.errorMessage,
required this.timestamp,
required this.sender,
});
@override
ChatItemType get type => ChatItemType.toolCall;
ToolCallItem copyWith({
String? id,
String? callId,
String? toolName,
Map<String, dynamic>? args,
ToolCallStatus? status,
String? errorMessage,
DateTime? timestamp,
MessageSender? sender,
}) => ToolCallItem(
id: id ?? this.id,
callId: callId ?? this.callId,
toolName: toolName ?? this.toolName,
args: args ?? this.args,
status: status ?? this.status,
errorMessage: errorMessage ?? this.errorMessage,
timestamp: timestamp ?? this.timestamp,
sender: sender ?? this.sender,
);
}
class ToolResultItem extends ChatListItem {
@override
final String id;
final String callId;
final Map<String, dynamic> uiSchema;
@override
final DateTime timestamp;
@override
final MessageSender sender;
ToolResultItem({
required this.id,
required this.callId,
required this.uiSchema,
required this.timestamp,
required this.sender,
});
@override
ChatItemType get type => ChatItemType.toolResult;
}
+31
View File
@@ -0,0 +1,31 @@
import 'package:image_picker/image_picker.dart';
import 'agent_stage.dart';
import 'chat_list_item.dart';
abstract class ChatOrchestratorState {
List<ChatListItem> get items;
bool get isSending;
bool get isWaitingFirstToken;
bool get isStreaming;
bool get isCancelling;
bool get isLoadingHistory;
String? get currentMessageId;
String? get error;
DateTime? get oldestLoadedDate;
bool get hasEarlierHistory;
AgentStage? get currentStage;
bool get isLoading;
}
abstract class ChatOrchestrator {
ChatOrchestratorState get state;
Stream<ChatOrchestratorState> get stream;
Future<void> sendMessage(String content, {List<XFile>? images});
Future<void> loadHistory();
Future<void> loadMoreHistory();
Future<String> transcribeAudioFile(String filePath);
Future<bool> cancelCurrentRun();
void clearError();
}