马良AI写作初始化仓库

This commit is contained in:
邓滨杰
2025-09-10 00:07:52 +08:00
parent 3c06bb1a03
commit 39c0f8840f
1309 changed files with 318528 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,482 @@
import 'package:equatable/equatable.dart';
abstract class SettingGenerationBlocEvent extends Equatable {
const SettingGenerationBlocEvent();
@override
List<Object?> get props => [];
}
/// 加载可用策略
class LoadStrategiesEvent extends SettingGenerationBlocEvent {
final String? novelId;
final String? userId;
const LoadStrategiesEvent({
this.novelId,
this.userId,
});
@override
List<Object?> get props => [novelId, userId];
}
/// 加载历史记录
class LoadHistoriesEvent extends SettingGenerationBlocEvent {
final String novelId;
final String userId;
final int page;
final int size;
const LoadHistoriesEvent({
required this.novelId,
required this.userId,
this.page = 0,
this.size = 20,
});
@override
List<Object?> get props => [novelId, userId, page, size];
}
/// 从小说设定创建编辑会话
class StartSessionFromNovelEvent extends SettingGenerationBlocEvent {
final String novelId;
final String editReason;
final String modelConfigId;
final bool createNewSnapshot;
const StartSessionFromNovelEvent({
required this.novelId,
required this.editReason,
required this.modelConfigId,
required this.createNewSnapshot,
});
@override
List<Object?> get props => [novelId, editReason, modelConfigId, createNewSnapshot];
}
/// 开始生成设定
class StartGenerationEvent extends SettingGenerationBlocEvent {
final String initialPrompt;
final String promptTemplateId;
final String? novelId;
final String modelConfigId;
final String? userId;
// 文本阶段公共模型透传(仅记录,不改变文本阶段默认使用私有模型)
final bool? usePublicTextModel;
final String? textPhasePublicProvider;
final String? textPhasePublicModelId;
const StartGenerationEvent({
required this.initialPrompt,
required this.promptTemplateId,
this.novelId,
required this.modelConfigId,
this.userId,
this.usePublicTextModel,
this.textPhasePublicProvider,
this.textPhasePublicModelId,
});
@override
List<Object?> get props => [
initialPrompt,
promptTemplateId,
novelId,
modelConfigId,
userId,
usePublicTextModel,
textPhasePublicProvider,
textPhasePublicModelId,
];
}
/// 基于当前会话进行整体调整生成
class AdjustGenerationEvent extends SettingGenerationBlocEvent {
final String sessionId;
final String adjustmentPrompt;
final String modelConfigId;
final String? promptTemplateId;
const AdjustGenerationEvent({
required this.sessionId,
required this.adjustmentPrompt,
required this.modelConfigId,
this.promptTemplateId,
});
@override
List<Object?> get props => [sessionId, adjustmentPrompt, modelConfigId, promptTemplateId];
}
/// 修改节点
class UpdateNodeEvent extends SettingGenerationBlocEvent {
final String nodeId;
final String modificationPrompt;
final String modelConfigId;
final String scope; // 'self' | 'self_and_children' | 'children_only'
const UpdateNodeEvent({
required this.nodeId,
required this.modificationPrompt,
required this.modelConfigId,
this.scope = 'self',
});
@override
List<Object?> get props => [
nodeId,
modificationPrompt,
modelConfigId,
scope,
];
}
/// 选择节点
class SelectNodeEvent extends SettingGenerationBlocEvent {
final String? nodeId;
const SelectNodeEvent(this.nodeId);
@override
List<Object?> get props => [nodeId];
}
/// 切换视图模式
class ToggleViewModeEvent extends SettingGenerationBlocEvent {
final String viewMode; // 'compact' | 'detailed'
const ToggleViewModeEvent(this.viewMode);
@override
List<Object?> get props => [viewMode];
}
/// 应用待处理的更改
class ApplyPendingChangesEvent extends SettingGenerationBlocEvent {
const ApplyPendingChangesEvent();
}
/// 取消待处理的更改
class CancelPendingChangesEvent extends SettingGenerationBlocEvent {
const CancelPendingChangesEvent();
}
/// 撤销节点更改
class UndoNodeChangeEvent extends SettingGenerationBlocEvent {
final String nodeId;
const UndoNodeChangeEvent(this.nodeId);
@override
List<Object?> get props => [nodeId];
}
/// 保存生成的设定
class SaveGeneratedSettingsEvent extends SettingGenerationBlocEvent {
final String? novelId; // 改为可空,支持独立快照
final bool updateExisting; // 是否更新现有历史记录
final String? targetHistoryId; // 目标历史记录ID
const SaveGeneratedSettingsEvent(
this.novelId, {
this.updateExisting = false,
this.targetHistoryId,
});
@override
List<Object?> get props => [novelId, updateExisting, targetHistoryId];
}
/// 创建新会话
class CreateNewSessionEvent extends SettingGenerationBlocEvent {
const CreateNewSessionEvent();
}
/// 选择会话
class SelectSessionEvent extends SettingGenerationBlocEvent {
final String sessionId;
final bool isHistorySession;
const SelectSessionEvent(
this.sessionId, {
this.isHistorySession = false,
});
@override
List<Object?> get props => [sessionId, isHistorySession];
}
/// 从历史记录创建编辑会话
class CreateSessionFromHistoryEvent extends SettingGenerationBlocEvent {
final String historyId;
final String userId;
final String editReason;
final String modelConfigId;
const CreateSessionFromHistoryEvent({
required this.historyId,
required this.userId,
this.editReason = '从历史记录编辑',
required this.modelConfigId,
});
@override
List<Object?> get props => [historyId, userId, editReason, modelConfigId];
}
/// 更新调整提示词
class UpdateAdjustmentPromptEvent extends SettingGenerationBlocEvent {
final String prompt;
const UpdateAdjustmentPromptEvent(this.prompt);
@override
List<Object?> get props => [prompt];
}
/// 重置状态事件
class ResetEvent extends SettingGenerationBlocEvent {
const ResetEvent();
}
/// 重试事件(从错误状态恢复)
class RetryEvent extends SettingGenerationBlocEvent {
const RetryEvent();
}
/// 开始渲染节点事件
class StartNodeRenderEvent extends SettingGenerationBlocEvent {
final String nodeId;
const StartNodeRenderEvent(this.nodeId);
@override
List<Object?> get props => [nodeId];
}
/// 完成节点渲染事件
class CompleteNodeRenderEvent extends SettingGenerationBlocEvent {
final String nodeId;
const CompleteNodeRenderEvent(this.nodeId);
@override
List<Object?> get props => [nodeId];
}
/// 处理渲染队列事件
class ProcessRenderQueueEvent extends SettingGenerationBlocEvent {
const ProcessRenderQueueEvent();
@override
List<Object?> get props => [];
}
/// 更新节点内容事件
class UpdateNodeContentEvent extends SettingGenerationBlocEvent {
final String nodeId;
final String content;
const UpdateNodeContentEvent({
required this.nodeId,
required this.content,
});
@override
List<Object?> get props => [nodeId, content];
}
/// 获取会话状态事件
class GetSessionStatusEvent extends SettingGenerationBlocEvent {
final String sessionId;
const GetSessionStatusEvent(this.sessionId);
@override
List<Object?> get props => [sessionId];
}
/// 取消会话事件
class CancelSessionEvent extends SettingGenerationBlocEvent {
final String sessionId;
const CancelSessionEvent(this.sessionId);
@override
List<Object?> get props => [sessionId];
}
// ==================== NOVEL_COMPOSE 事件族 ====================
/// 启动:只生成大纲
class StartComposeOutlineEvent extends SettingGenerationBlocEvent {
final String? novelId;
final String userId;
final String modelConfigId;
final bool? isPublicModel;
final String? publicModelConfigId;
final String? settingSessionId; // 方案A后端拉取会话转换
final Map<String, dynamic>? contextSelections; // 直接透传已选上下文(可选)
final String? prompt; // 自由提示词
final String? instructions; // 生成指令
final int chapterCount; // 按章大纲数量(支持黄金三章=3
final Map<String, dynamic> parameters; // 其他采样/模式参数
const StartComposeOutlineEvent({
required this.userId,
required this.modelConfigId,
this.isPublicModel,
this.publicModelConfigId,
this.novelId,
this.settingSessionId,
this.contextSelections,
this.prompt,
this.instructions,
this.chapterCount = 3,
this.parameters = const {},
});
}
/// 启动直接生成章节黄金三章或指定N章
class StartComposeChaptersEvent extends SettingGenerationBlocEvent {
final String? novelId;
final String userId;
final String modelConfigId;
final bool? isPublicModel;
final String? publicModelConfigId;
final String? settingSessionId;
final Map<String, dynamic>? contextSelections;
final String? prompt;
final String? instructions;
final int chapterCount; // 生成章节数
final Map<String, dynamic> parameters;
const StartComposeChaptersEvent({
required this.userId,
required this.modelConfigId,
this.isPublicModel,
this.publicModelConfigId,
this.novelId,
this.settingSessionId,
this.contextSelections,
this.prompt,
this.instructions,
this.chapterCount = 3,
this.parameters = const {},
});
}
/// 启动先大纲后章节outline_plus_chapters
class StartComposeBundleEvent extends SettingGenerationBlocEvent {
final String? novelId;
final String userId;
final String modelConfigId;
final bool? isPublicModel;
final String? publicModelConfigId;
final String? settingSessionId;
final Map<String, dynamic>? contextSelections;
final String? prompt;
final String? instructions;
final int chapterCount; // 需要的大纲/章节数量
final Map<String, dynamic> parameters;
const StartComposeBundleEvent({
required this.userId,
required this.modelConfigId,
this.isPublicModel,
this.publicModelConfigId,
this.novelId,
this.settingSessionId,
this.contextSelections,
this.prompt,
this.instructions,
this.chapterCount = 3,
this.parameters = const {},
});
}
/// 微调:针对已生成的大纲或章节进行整体或定向调整
class RefineComposeEvent extends SettingGenerationBlocEvent {
final String? novelId;
final String userId;
final String modelConfigId;
final String? settingSessionId;
final Map<String, dynamic>? contextSelections;
final String? instructions; // 具体微调指令
final Map<String, dynamic> parameters; // 可包含 chapterIndex、outlineText 等
const RefineComposeEvent({
required this.userId,
required this.modelConfigId,
this.novelId,
this.settingSessionId,
this.contextSelections,
this.instructions,
this.parameters = const {},
});
}
/// 取消写作编排流
class CancelComposeEvent extends SettingGenerationBlocEvent {
final String connectionId; // SSE连接ID或业务自定义ID
const CancelComposeEvent(this.connectionId);
@override
List<Object?> get props => [connectionId];
}
/// 获取用户历史记录事件
class GetUserHistoriesEvent extends SettingGenerationBlocEvent {
final String? novelId;
final int page;
final int size;
const GetUserHistoriesEvent({
this.novelId,
this.page = 0,
this.size = 20,
});
@override
List<Object?> get props => [novelId, page, size];
}
/// 删除历史记录事件
class DeleteHistoryEvent extends SettingGenerationBlocEvent {
final String historyId;
const DeleteHistoryEvent(this.historyId);
@override
List<Object?> get props => [historyId];
}
/// 复制历史记录事件
class CopyHistoryEvent extends SettingGenerationBlocEvent {
final String historyId;
final String copyReason;
const CopyHistoryEvent({
required this.historyId,
required this.copyReason,
});
@override
List<Object?> get props => [historyId, copyReason];
}
/// 恢复历史记录到小说事件
class RestoreHistoryToNovelEvent extends SettingGenerationBlocEvent {
final String historyId;
final String novelId;
const RestoreHistoryToNovelEvent({
required this.historyId,
required this.novelId,
});
@override
List<Object?> get props => [historyId, novelId];
}

View File

@@ -0,0 +1,536 @@
import 'package:equatable/equatable.dart';
import '../../models/setting_generation_session.dart';
import '../../models/setting_node.dart';
import '../../models/setting_generation_event.dart' as event_model;
import '../../models/compose_preview.dart';
import '../../models/strategy_template_info.dart';
import '../../utils/setting_node_utils.dart'; // 导入工具类
abstract class SettingGenerationState extends Equatable {
const SettingGenerationState();
@override
List<Object?> get props => [];
}
/// 初始状态
class SettingGenerationInitial extends SettingGenerationState {
const SettingGenerationInitial();
}
/// 加载中
class SettingGenerationLoading extends SettingGenerationState {
final String? message;
const SettingGenerationLoading({this.message});
@override
List<Object?> get props => [message];
}
/// 策略已加载
class StrategiesLoaded extends SettingGenerationState {
final List<StrategyTemplateInfo> strategies;
const StrategiesLoaded(this.strategies);
@override
List<Object?> get props => [strategies];
}
/// 待机状态(准备开始生成)
class SettingGenerationReady extends SettingGenerationState {
final List<StrategyTemplateInfo> strategies;
final List<SettingGenerationSession> sessions;
final String? activeSessionId;
final String adjustmentPrompt;
final String viewMode;
const SettingGenerationReady({
required this.strategies,
this.sessions = const [],
this.activeSessionId,
this.adjustmentPrompt = '',
this.viewMode = 'compact',
});
@override
List<Object?> get props => [
strategies,
sessions,
activeSessionId,
adjustmentPrompt,
viewMode,
];
SettingGenerationReady copyWith({
List<StrategyTemplateInfo>? strategies,
List<SettingGenerationSession>? sessions,
String? activeSessionId,
String? adjustmentPrompt,
String? viewMode,
}) {
return SettingGenerationReady(
strategies: strategies ?? this.strategies,
sessions: sessions ?? this.sessions,
activeSessionId: activeSessionId ?? this.activeSessionId,
adjustmentPrompt: adjustmentPrompt ?? this.adjustmentPrompt,
viewMode: viewMode ?? this.viewMode,
);
}
}
/// 节点渲染状态枚举
enum NodeRenderState {
pending, // 待渲染(在队列中)
rendering, // 正在渲染(动画中)
rendered, // 已渲染完成
}
/// 节点渲染信息
class NodeRenderInfo {
final String nodeId;
final NodeRenderState state;
final DateTime? renderStartTime;
final Duration? renderDuration;
const NodeRenderInfo({
required this.nodeId,
required this.state,
this.renderStartTime,
this.renderDuration,
});
NodeRenderInfo copyWith({
NodeRenderState? state,
DateTime? renderStartTime,
Duration? renderDuration,
}) {
return NodeRenderInfo(
nodeId: nodeId,
state: state ?? this.state,
renderStartTime: renderStartTime ?? this.renderStartTime,
renderDuration: renderDuration ?? this.renderDuration,
);
}
}
/// 生成中
class SettingGenerationInProgress extends SettingGenerationState {
final List<StrategyTemplateInfo> strategies;
final List<SettingGenerationSession> sessions;
final String activeSessionId;
final SettingGenerationSession activeSession;
final String? selectedNodeId;
final String viewMode;
final String adjustmentPrompt;
final Map<String, SettingNode> pendingChanges;
final Set<String> highlightedNodeIds;
final Map<String, List<SettingNode>> editHistory;
final List<event_model.SettingGenerationEvent> events;
final bool isGenerating;
final String? currentOperation;
// 新增:写作编排流的预览缓存(仅前端展示,不落库)
final List<ComposeChapterPreview> composePreview;
// 新增的渲染状态管理字段
final Map<String, NodeRenderInfo> nodeRenderStates;
final List<String> renderQueue;
final Set<String> renderedNodeIds;
final List<event_model.NodeCreatedEvent> pendingNodes;
// 粘性警告(例如余额不足提醒),不会被后续普通事件覆盖
final String? stickyWarning;
const SettingGenerationInProgress({
required this.strategies,
required this.sessions,
required this.activeSessionId,
required this.activeSession,
this.selectedNodeId,
this.viewMode = 'compact',
this.adjustmentPrompt = '',
this.pendingChanges = const {},
this.highlightedNodeIds = const {},
this.editHistory = const {},
this.isGenerating = false,
this.currentOperation,
this.composePreview = const [],
this.events = const [],
this.nodeRenderStates = const {},
this.renderQueue = const [],
this.renderedNodeIds = const {},
this.pendingNodes = const [],
this.stickyWarning,
});
@override
List<Object?> get props => [
strategies,
sessions,
activeSessionId,
activeSession,
selectedNodeId,
viewMode,
adjustmentPrompt,
pendingChanges,
highlightedNodeIds,
editHistory,
isGenerating,
currentOperation,
composePreview,
events,
nodeRenderStates,
renderQueue,
renderedNodeIds,
stickyWarning,
];
SettingGenerationInProgress copyWith({
List<StrategyTemplateInfo>? strategies,
List<SettingGenerationSession>? sessions,
String? activeSessionId,
SettingGenerationSession? activeSession,
String? selectedNodeId,
String? viewMode,
String? adjustmentPrompt,
Map<String, SettingNode>? pendingChanges,
Set<String>? highlightedNodeIds,
Map<String, List<SettingNode>>? editHistory,
bool? isGenerating,
String? currentOperation,
List<ComposeChapterPreview>? composePreview,
List<event_model.SettingGenerationEvent>? events,
Map<String, NodeRenderInfo>? nodeRenderStates,
List<String>? renderQueue,
Set<String>? renderedNodeIds,
List<event_model.NodeCreatedEvent>? pendingNodes,
String? stickyWarning,
}) {
return SettingGenerationInProgress(
strategies: strategies ?? this.strategies,
sessions: sessions ?? this.sessions,
activeSessionId: activeSessionId ?? this.activeSessionId,
activeSession: activeSession ?? this.activeSession,
selectedNodeId: selectedNodeId ?? this.selectedNodeId,
viewMode: viewMode ?? this.viewMode,
adjustmentPrompt: adjustmentPrompt ?? this.adjustmentPrompt,
pendingChanges: pendingChanges ?? this.pendingChanges,
highlightedNodeIds: highlightedNodeIds ?? this.highlightedNodeIds,
editHistory: editHistory ?? this.editHistory,
isGenerating: isGenerating ?? this.isGenerating,
currentOperation: currentOperation ?? this.currentOperation,
composePreview: composePreview ?? this.composePreview,
events: events ?? this.events,
nodeRenderStates: nodeRenderStates ?? this.nodeRenderStates,
renderQueue: renderQueue ?? this.renderQueue,
renderedNodeIds: renderedNodeIds ?? this.renderedNodeIds,
pendingNodes: pendingNodes ?? this.pendingNodes,
stickyWarning: stickyWarning ?? this.stickyWarning,
);
}
/// 获取当前选中的节点
SettingNode? get selectedNode {
if (selectedNodeId == null) return null;
return SettingNodeUtils.findNodeInTree(activeSession.rootNodes, selectedNodeId!);
}
/// 获取可以渲染的节点列表(父节点为空或已渲染)
List<String> get renderableNodeIds {
return SettingNodeUtils.getRenderableNodeIds(
activeSession.rootNodes,
renderQueue,
renderedNodeIds,
);
}
}
/// 生成完成
class SettingGenerationCompleted extends SettingGenerationState {
final List<StrategyTemplateInfo> strategies;
final List<SettingGenerationSession> sessions;
final String activeSessionId;
final SettingGenerationSession activeSession;
final String? selectedNodeId;
final String viewMode;
final String adjustmentPrompt;
final Map<String, SettingNode> pendingChanges;
final Set<String> highlightedNodeIds;
final Map<String, List<SettingNode>> editHistory;
final List<event_model.SettingGenerationEvent> events;
final String message;
// 新增的渲染状态管理字段
final Map<String, NodeRenderInfo> nodeRenderStates;
final Set<String> renderedNodeIds;
final String? stickyWarning;
const SettingGenerationCompleted({
required this.strategies,
required this.sessions,
required this.activeSessionId,
required this.activeSession,
this.selectedNodeId,
this.viewMode = 'compact',
this.adjustmentPrompt = '',
this.pendingChanges = const {},
this.highlightedNodeIds = const {},
this.editHistory = const {},
this.events = const [],
required this.message,
this.nodeRenderStates = const {},
this.renderedNodeIds = const {},
this.stickyWarning,
});
@override
List<Object?> get props => [
strategies,
sessions,
activeSessionId,
activeSession,
selectedNodeId,
viewMode,
adjustmentPrompt,
pendingChanges,
highlightedNodeIds,
editHistory,
events,
message,
nodeRenderStates,
renderedNodeIds,
stickyWarning,
];
SettingGenerationCompleted copyWith({
List<StrategyTemplateInfo>? strategies,
List<SettingGenerationSession>? sessions,
String? activeSessionId,
SettingGenerationSession? activeSession,
String? selectedNodeId,
String? viewMode,
String? adjustmentPrompt,
Map<String, SettingNode>? pendingChanges,
Set<String>? highlightedNodeIds,
Map<String, List<SettingNode>>? editHistory,
List<event_model.SettingGenerationEvent>? events,
String? message,
Map<String, NodeRenderInfo>? nodeRenderStates,
Set<String>? renderedNodeIds,
String? stickyWarning,
}) {
return SettingGenerationCompleted(
strategies: strategies ?? this.strategies,
sessions: sessions ?? this.sessions,
activeSessionId: activeSessionId ?? this.activeSessionId,
activeSession: activeSession ?? this.activeSession,
selectedNodeId: selectedNodeId ?? this.selectedNodeId,
viewMode: viewMode ?? this.viewMode,
adjustmentPrompt: adjustmentPrompt ?? this.adjustmentPrompt,
pendingChanges: pendingChanges ?? this.pendingChanges,
highlightedNodeIds: highlightedNodeIds ?? this.highlightedNodeIds,
editHistory: editHistory ?? this.editHistory,
events: events ?? this.events,
message: message ?? this.message,
nodeRenderStates: nodeRenderStates ?? this.nodeRenderStates,
renderedNodeIds: renderedNodeIds ?? this.renderedNodeIds,
stickyWarning: stickyWarning ?? this.stickyWarning,
);
}
/// 获取当前选中的节点
SettingNode? get selectedNode {
if (selectedNodeId == null) return null;
return SettingNodeUtils.findNodeInTree(activeSession.rootNodes, selectedNodeId!);
}
}
/// 节点修改中状态(专门用于节点修改,避免整个设定树重新渲染)
class SettingGenerationNodeUpdating extends SettingGenerationState {
final List<StrategyTemplateInfo> strategies;
final List<SettingGenerationSession> sessions;
final String activeSessionId;
final SettingGenerationSession activeSession;
final String? selectedNodeId;
final String viewMode;
final String adjustmentPrompt;
final Map<String, SettingNode> pendingChanges;
final Set<String> highlightedNodeIds;
final Map<String, List<SettingNode>> editHistory;
final List<event_model.SettingGenerationEvent> events;
final String message;
// 节点修改特有字段
final String updatingNodeId; // 正在修改的节点ID
final String modificationPrompt; // 修改提示词
final String scope; // 修改范围
final bool isUpdating; // 是否正在更新中
// 渲染状态管理字段
final Map<String, NodeRenderInfo> nodeRenderStates;
final Set<String> renderedNodeIds;
const SettingGenerationNodeUpdating({
required this.strategies,
required this.sessions,
required this.activeSessionId,
required this.activeSession,
this.selectedNodeId,
this.viewMode = 'compact',
this.adjustmentPrompt = '',
this.pendingChanges = const {},
this.highlightedNodeIds = const {},
this.editHistory = const {},
this.events = const [],
this.message = '',
required this.updatingNodeId,
this.modificationPrompt = '',
this.scope = 'self',
this.isUpdating = false,
this.nodeRenderStates = const {},
this.renderedNodeIds = const {},
});
@override
List<Object?> get props => [
strategies,
sessions,
activeSessionId,
activeSession,
selectedNodeId,
viewMode,
adjustmentPrompt,
pendingChanges,
highlightedNodeIds,
editHistory,
events,
message,
updatingNodeId,
modificationPrompt,
scope,
isUpdating,
nodeRenderStates,
renderedNodeIds,
];
SettingGenerationNodeUpdating copyWith({
List<StrategyTemplateInfo>? strategies,
List<SettingGenerationSession>? sessions,
String? activeSessionId,
SettingGenerationSession? activeSession,
String? selectedNodeId,
String? viewMode,
String? adjustmentPrompt,
Map<String, SettingNode>? pendingChanges,
Set<String>? highlightedNodeIds,
Map<String, List<SettingNode>>? editHistory,
List<event_model.SettingGenerationEvent>? events,
String? message,
String? updatingNodeId,
String? modificationPrompt,
String? scope,
bool? isUpdating,
Map<String, NodeRenderInfo>? nodeRenderStates,
Set<String>? renderedNodeIds,
}) {
return SettingGenerationNodeUpdating(
strategies: strategies ?? this.strategies,
sessions: sessions ?? this.sessions,
activeSessionId: activeSessionId ?? this.activeSessionId,
activeSession: activeSession ?? this.activeSession,
selectedNodeId: selectedNodeId ?? this.selectedNodeId,
viewMode: viewMode ?? this.viewMode,
adjustmentPrompt: adjustmentPrompt ?? this.adjustmentPrompt,
pendingChanges: pendingChanges ?? this.pendingChanges,
highlightedNodeIds: highlightedNodeIds ?? this.highlightedNodeIds,
editHistory: editHistory ?? this.editHistory,
events: events ?? this.events,
message: message ?? this.message,
updatingNodeId: updatingNodeId ?? this.updatingNodeId,
modificationPrompt: modificationPrompt ?? this.modificationPrompt,
scope: scope ?? this.scope,
isUpdating: isUpdating ?? this.isUpdating,
nodeRenderStates: nodeRenderStates ?? this.nodeRenderStates,
renderedNodeIds: renderedNodeIds ?? this.renderedNodeIds,
);
}
/// 获取当前选中的节点
SettingNode? get selectedNode {
if (selectedNodeId == null) return null;
return SettingNodeUtils.findNodeInTree(activeSession.rootNodes, selectedNodeId!);
}
/// 获取正在修改的节点
SettingNode? get updatingNode {
return SettingNodeUtils.findNodeInTree(activeSession.rootNodes, updatingNodeId);
}
}
/// 保存成功
class SettingGenerationSaved extends SettingGenerationState {
final List<String> savedSettingIds;
final String message;
// 新增保留会话列表和当前活跃会话ID避免UI刷新
final List<SettingGenerationSession> sessions;
final String? activeSessionId;
const SettingGenerationSaved({
required this.savedSettingIds,
this.message = '设定已成功保存',
this.sessions = const [],
this.activeSessionId,
});
@override
List<Object?> get props => [savedSettingIds, message, sessions, activeSessionId];
}
/// 错误状态
class SettingGenerationError extends SettingGenerationState {
final String message;
final dynamic error;
final StackTrace? stackTrace;
final bool isRecoverable;
// 新增:保留会话列表和当前活跃会话 ID避免 UI 在错误时丢失历史记录
final List<SettingGenerationSession> sessions;
final String? activeSessionId;
const SettingGenerationError({
required this.message,
this.error,
this.stackTrace,
this.isRecoverable = true,
this.sessions = const [],
this.activeSessionId,
});
@override
List<Object?> get props => [
message,
error,
stackTrace,
isRecoverable,
sessions,
activeSessionId,
];
SettingGenerationError copyWith({
String? message,
dynamic error,
StackTrace? stackTrace,
bool? isRecoverable,
List<SettingGenerationSession>? sessions,
String? activeSessionId,
}) {
return SettingGenerationError(
message: message ?? this.message,
error: error ?? this.error,
stackTrace: stackTrace ?? this.stackTrace,
isRecoverable: isRecoverable ?? this.isRecoverable,
sessions: sessions ?? this.sessions,
activeSessionId: activeSessionId ?? this.activeSessionId,
);
}
}