马良AI写作初始化仓库
This commit is contained in:
996
AINoval/lib/blocs/preset/preset_bloc.dart
Normal file
996
AINoval/lib/blocs/preset/preset_bloc.dart
Normal file
@@ -0,0 +1,996 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:ainoval/blocs/preset/preset_event.dart';
|
||||
import 'package:ainoval/blocs/preset/preset_state.dart';
|
||||
import 'package:ainoval/services/api_service/repositories/preset_aggregation_repository.dart';
|
||||
import 'package:ainoval/services/api_service/repositories/ai_preset_repository.dart';
|
||||
import 'package:ainoval/models/preset_models.dart';
|
||||
import 'package:ainoval/utils/logger.dart';
|
||||
|
||||
/// 预设管理BLoC
|
||||
/// 负责处理预设相关的业务逻辑和状态管理
|
||||
class PresetBloc extends Bloc<PresetEvent, PresetState> {
|
||||
static const String _tag = 'PresetBloc';
|
||||
|
||||
final PresetAggregationRepository _aggregationRepository;
|
||||
final AIPresetRepository _presetRepository;
|
||||
|
||||
PresetBloc({
|
||||
required PresetAggregationRepository aggregationRepository,
|
||||
required AIPresetRepository presetRepository,
|
||||
}) : _aggregationRepository = aggregationRepository,
|
||||
_presetRepository = presetRepository,
|
||||
super(const PresetState.initial()) {
|
||||
on<LoadUserPresetOverview>(_onLoadUserPresetOverview);
|
||||
on<LoadPresetPackage>(_onLoadPresetPackage);
|
||||
on<LoadBatchPresetPackages>(_onLoadBatchPresetPackages);
|
||||
on<LoadGroupedPresets>(_onLoadGroupedPresets);
|
||||
on<LoadAllPresetData>(_onLoadAllPresetData);
|
||||
on<AddPresetToCache>(_onAddPresetToCache);
|
||||
on<SelectPreset>(_onSelectPreset);
|
||||
on<CreatePreset>(_onCreatePreset);
|
||||
on<OverwritePreset>(_onOverwritePreset);
|
||||
on<UpdatePreset>(_onUpdatePreset);
|
||||
on<DeletePreset>(_onDeletePreset);
|
||||
on<DuplicatePreset>(_onDuplicatePreset);
|
||||
on<TogglePresetFavorite>(_onTogglePresetFavorite);
|
||||
on<TogglePresetQuickAccess>(_onTogglePresetQuickAccess);
|
||||
on<SearchPresets>(_onSearchPresets);
|
||||
on<ClearPresetSearch>(_onClearPresetSearch);
|
||||
on<RefreshPresetData>(_onRefreshPresetData);
|
||||
on<WarmupPresetCache>(_onWarmupPresetCache);
|
||||
}
|
||||
|
||||
/// 加载用户预设概览
|
||||
Future<void> _onLoadUserPresetOverview(
|
||||
LoadUserPresetOverview event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
final overview = await _aggregationRepository.getUserPresetOverview();
|
||||
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
userOverview: overview,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '用户预设概览加载成功');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '加载用户预设概览失败', e);
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: '加载用户预设概览失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 加载预设包
|
||||
Future<void> _onLoadPresetPackage(
|
||||
LoadPresetPackage event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
final package = await _aggregationRepository.getCompletePresetPackage(
|
||||
event.featureType,
|
||||
novelId: event.novelId,
|
||||
);
|
||||
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
currentPackage: package,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '预设包加载成功: ${event.featureType}');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '加载预设包失败: ${event.featureType}', e);
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: '加载预设包失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 加载批量预设包
|
||||
Future<void> _onLoadBatchPresetPackages(
|
||||
LoadBatchPresetPackages event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
final packages = await _aggregationRepository.getBatchPresetPackages(
|
||||
featureTypes: event.featureTypes,
|
||||
novelId: event.novelId,
|
||||
);
|
||||
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
batchPackages: packages,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '批量预设包加载成功: ${packages.length} 个');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '加载批量预设包失败', e);
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: '加载批量预设包失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 加载分组预设
|
||||
Future<void> _onLoadGroupedPresets(
|
||||
LoadGroupedPresets event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
final groupedPresets = await _presetRepository.getUserPresetsByFeatureType(
|
||||
userId: event.userId,
|
||||
);
|
||||
|
||||
// 加载系统预设并合并
|
||||
final systemPresets = await _presetRepository.getSystemPresets();
|
||||
|
||||
// 合并系统预设到分组中
|
||||
final mergedGroupedPresets = Map<String, List<AIPromptPreset>>.from(groupedPresets);
|
||||
for (final preset in systemPresets) {
|
||||
final featureType = preset.aiFeatureType;
|
||||
if (!mergedGroupedPresets.containsKey(featureType)) {
|
||||
mergedGroupedPresets[featureType] = [];
|
||||
}
|
||||
mergedGroupedPresets[featureType]!.insert(0, preset);
|
||||
}
|
||||
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
groupedPresets: mergedGroupedPresets,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '分组预设加载成功: ${mergedGroupedPresets.length} 个分组');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '加载分组预设失败', e);
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: '加载分组预设失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 选择预设
|
||||
Future<void> _onSelectPreset(
|
||||
SelectPreset event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
// 🚀 修复:优先从已加载的聚合数据中查找预设,避免重复请求后端
|
||||
AIPromptPreset? preset;
|
||||
|
||||
if (state.allPresetData != null) {
|
||||
// 从聚合数据的所有预设中查找
|
||||
preset = state.allPresetData!.allPresets
|
||||
.where((p) => p.presetId == event.presetId)
|
||||
.firstOrNull;
|
||||
|
||||
if (preset != null) {
|
||||
AppLogger.i(_tag, '✅ 从聚合数据中找到预设: ${event.presetId}');
|
||||
}
|
||||
}
|
||||
|
||||
// 如果聚合数据中没有找到,尝试从分组预设中查找
|
||||
if (preset == null && state.groupedPresets.isNotEmpty) {
|
||||
for (final presets in state.groupedPresets.values) {
|
||||
preset = presets
|
||||
.where((p) => p.presetId == event.presetId)
|
||||
.firstOrNull;
|
||||
if (preset != null) {
|
||||
AppLogger.i(_tag, '✅ 从分组预设中找到预设: ${event.presetId}');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 最后的回退:如果缓存中都没有,才去后端获取
|
||||
if (preset == null) {
|
||||
AppLogger.w(_tag, '⚠️ 缓存中未找到预设,从后端获取: ${event.presetId}');
|
||||
preset = await _presetRepository.getPresetById(event.presetId);
|
||||
}
|
||||
|
||||
emit(state.copyWith(
|
||||
selectedPreset: preset,
|
||||
errorMessage: null,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '📘 预设选择成功: ${event.presetId}');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '选择预设失败: ${event.presetId}', e);
|
||||
emit(state.copyWith(
|
||||
errorMessage: '选择预设失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 创建预设
|
||||
Future<void> _onCreatePreset(
|
||||
CreatePreset event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
final newPreset = await _presetRepository.createPreset(event.request);
|
||||
|
||||
// 🚀 优化:直接更新本地状态,不重新请求API
|
||||
final updatedGroupedPresets = Map<String, List<AIPromptPreset>>.from(state.groupedPresets);
|
||||
final newFeatureType = newPreset.aiFeatureType;
|
||||
|
||||
// 🚀 修复:处理功能类型格式不一致问题
|
||||
// 先查找是否存在相同功能类型的其他格式键
|
||||
String? existingKey = _findExistingFeatureTypeKey(updatedGroupedPresets, newFeatureType);
|
||||
final targetKey = existingKey ?? newFeatureType;
|
||||
|
||||
if (updatedGroupedPresets.containsKey(targetKey)) {
|
||||
// 将新预设添加到对应功能类型的列表开头
|
||||
updatedGroupedPresets[targetKey] = [newPreset, ...updatedGroupedPresets[targetKey]!];
|
||||
} else {
|
||||
// 如果该功能类型还没有预设,创建新列表
|
||||
updatedGroupedPresets[targetKey] = [newPreset];
|
||||
}
|
||||
|
||||
AppLogger.i(_tag, '📋 预设添加到分组: $targetKey (原始类型: $newFeatureType)');
|
||||
|
||||
// 🚀 新增:同时更新聚合数据缓存
|
||||
final newAllPresetData = state.allPresetData != null
|
||||
? _addPresetToAggregatedData(state.allPresetData!, newPreset)
|
||||
: null;
|
||||
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
selectedPreset: newPreset,
|
||||
groupedPresets: updatedGroupedPresets,
|
||||
allPresetData: newAllPresetData,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '📘 预设创建成功: ${newPreset.presetId}');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '❌ 创建预设失败', e);
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: '创建预设失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 覆盖更新预设(完整对象)
|
||||
Future<void> _onOverwritePreset(
|
||||
OverwritePreset event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
final updatedPreset = await _presetRepository.overwritePreset(event.preset);
|
||||
|
||||
// 🚀 直接更新本地缓存
|
||||
final updatedGroupedPresets = Map<String, List<AIPromptPreset>>.from(state.groupedPresets);
|
||||
final newFeatureType = updatedPreset.aiFeatureType;
|
||||
|
||||
String? existingKey = _findExistingFeatureTypeKey(updatedGroupedPresets, newFeatureType);
|
||||
final targetKey = existingKey ?? newFeatureType;
|
||||
|
||||
if (updatedGroupedPresets.containsKey(targetKey)) {
|
||||
final presetList = updatedGroupedPresets[targetKey]!;
|
||||
final index = presetList.indexWhere((p) => p.presetId == updatedPreset.presetId);
|
||||
if (index != -1) {
|
||||
presetList[index] = updatedPreset;
|
||||
}
|
||||
}
|
||||
|
||||
// 🚀 同时更新聚合数据缓存
|
||||
final newAllPresetData = _replacePresetInAggregatedData(state.allPresetData, updatedPreset);
|
||||
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
selectedPreset: updatedPreset,
|
||||
groupedPresets: updatedGroupedPresets,
|
||||
allPresetData: newAllPresetData,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '📘 预设覆盖更新成功: ${updatedPreset.presetId}');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '❌ 覆盖更新预设失败: ${event.preset.presetId}', e);
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: '覆盖更新预设失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 更新预设
|
||||
Future<void> _onUpdatePreset(
|
||||
UpdatePreset event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
AIPromptPreset updatedPreset;
|
||||
if (event.infoRequest != null) {
|
||||
updatedPreset = await _presetRepository.updatePresetInfo(
|
||||
event.presetId,
|
||||
event.infoRequest!,
|
||||
);
|
||||
} else if (event.promptsRequest != null) {
|
||||
updatedPreset = await _presetRepository.updatePresetPrompts(
|
||||
event.presetId,
|
||||
event.promptsRequest!,
|
||||
);
|
||||
} else {
|
||||
throw Exception('更新请求参数错误');
|
||||
}
|
||||
|
||||
// 🚀 优化:直接更新本地状态,不重新请求API
|
||||
final updatedGroupedPresets = Map<String, List<AIPromptPreset>>.from(state.groupedPresets);
|
||||
final newFeatureType = updatedPreset.aiFeatureType;
|
||||
|
||||
// 🚀 修复:处理功能类型格式不一致问题
|
||||
String? existingKey = _findExistingFeatureTypeKey(updatedGroupedPresets, newFeatureType);
|
||||
final targetKey = existingKey ?? newFeatureType;
|
||||
|
||||
if (updatedGroupedPresets.containsKey(targetKey)) {
|
||||
// 找到并替换对应的预设
|
||||
final presetList = updatedGroupedPresets[targetKey]!;
|
||||
final index = presetList.indexWhere((p) => p.presetId == event.presetId);
|
||||
if (index != -1) {
|
||||
presetList[index] = updatedPreset;
|
||||
AppLogger.i(_tag, '📋 预设更新在分组: $targetKey');
|
||||
}
|
||||
} else {
|
||||
AppLogger.w(_tag, '⚠️ 未找到预设分组进行更新: $targetKey');
|
||||
}
|
||||
|
||||
// 🚀 新增:同时更新聚合数据缓存
|
||||
final newAllPresetData = _replacePresetInAggregatedData(state.allPresetData, updatedPreset);
|
||||
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
selectedPreset: updatedPreset,
|
||||
groupedPresets: updatedGroupedPresets,
|
||||
allPresetData: newAllPresetData,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '📘 预设更新成功: ${event.presetId}');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '❌ 更新预设失败: ${event.presetId}', e);
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: '更新预设失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 删除预设
|
||||
Future<void> _onDeletePreset(
|
||||
DeletePreset event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
await _presetRepository.deletePreset(event.presetId);
|
||||
|
||||
// 🚀 优化:直接更新本地状态,不重新请求API
|
||||
final updatedGroupedPresets = Map<String, List<AIPromptPreset>>.from(state.groupedPresets);
|
||||
|
||||
// 从所有功能类型的列表中移除该预设
|
||||
for (final entry in updatedGroupedPresets.entries.toList()) {
|
||||
final presetList = entry.value;
|
||||
presetList.removeWhere((p) => p.presetId == event.presetId);
|
||||
|
||||
// 如果该功能类型的预设列表为空,移除该分组
|
||||
if (presetList.isEmpty) {
|
||||
updatedGroupedPresets.remove(entry.key);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果删除的是当前选中预设,清除选择
|
||||
final selectedPreset = state.selectedPreset?.presetId == event.presetId ? null : state.selectedPreset;
|
||||
|
||||
// 🚀 新增:同时更新聚合数据缓存
|
||||
final newAllPresetData = _removePresetFromAggregatedData(state.allPresetData, event.presetId);
|
||||
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
selectedPreset: selectedPreset,
|
||||
groupedPresets: updatedGroupedPresets,
|
||||
allPresetData: newAllPresetData,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '📘 预设删除成功: ${event.presetId}');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '❌ 删除预设失败: ${event.presetId}', e);
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: '删除预设失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 🚀 复制预设
|
||||
Future<void> _onDuplicatePreset(
|
||||
DuplicatePreset event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
final duplicatedPreset = await _presetRepository.duplicatePreset(event.presetId, event.request);
|
||||
|
||||
// 🚀 直接更新本地缓存,类似创建预设的逻辑
|
||||
final updatedGroupedPresets = Map<String, List<AIPromptPreset>>.from(state.groupedPresets);
|
||||
final featureType = duplicatedPreset.aiFeatureType;
|
||||
|
||||
if (updatedGroupedPresets.containsKey(featureType)) {
|
||||
// 将复制的预设添加到对应功能类型的列表开头
|
||||
updatedGroupedPresets[featureType] = [duplicatedPreset, ...updatedGroupedPresets[featureType]!];
|
||||
} else {
|
||||
// 如果该功能类型还没有预设,创建新列表
|
||||
updatedGroupedPresets[featureType] = [duplicatedPreset];
|
||||
}
|
||||
|
||||
// 🚀 同时更新聚合数据缓存
|
||||
final newAllPresetData = state.allPresetData != null
|
||||
? _addPresetToAggregatedData(state.allPresetData!, duplicatedPreset)
|
||||
: null;
|
||||
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
selectedPreset: duplicatedPreset,
|
||||
groupedPresets: updatedGroupedPresets,
|
||||
allPresetData: newAllPresetData,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '📘 预设复制成功: ${duplicatedPreset.presetId}');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '❌ 复制预设失败: ${event.presetId}', e);
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: '复制预设失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 切换预设收藏状态
|
||||
Future<void> _onTogglePresetFavorite(
|
||||
TogglePresetFavorite event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
final updatedPreset = await _presetRepository.toggleFavorite(event.presetId);
|
||||
|
||||
// 🚀 优化:直接更新本地状态,不重新请求API
|
||||
final updatedGroupedPresets = Map<String, List<AIPromptPreset>>.from(state.groupedPresets);
|
||||
final newFeatureType = updatedPreset.aiFeatureType;
|
||||
|
||||
// 🚀 修复:处理功能类型格式不一致问题
|
||||
String? existingKey = _findExistingFeatureTypeKey(updatedGroupedPresets, newFeatureType);
|
||||
final targetKey = existingKey ?? newFeatureType;
|
||||
|
||||
if (updatedGroupedPresets.containsKey(targetKey)) {
|
||||
// 找到并替换对应的预设
|
||||
final presetList = updatedGroupedPresets[targetKey]!;
|
||||
final index = presetList.indexWhere((p) => p.presetId == event.presetId);
|
||||
if (index != -1) {
|
||||
presetList[index] = updatedPreset;
|
||||
AppLogger.i(_tag, '📋 预设收藏状态更新在分组: $targetKey');
|
||||
}
|
||||
} else {
|
||||
AppLogger.w(_tag, '⚠️ 未找到预设分组进行收藏状态更新: $targetKey');
|
||||
}
|
||||
|
||||
// 更新选中的预设
|
||||
final selectedPreset = state.selectedPreset?.presetId == event.presetId
|
||||
? updatedPreset
|
||||
: state.selectedPreset;
|
||||
|
||||
// 🚀 新增:同时更新聚合数据缓存
|
||||
final newAllPresetData = _replacePresetInAggregatedData(state.allPresetData, updatedPreset);
|
||||
|
||||
emit(state.copyWith(
|
||||
selectedPreset: selectedPreset,
|
||||
groupedPresets: updatedGroupedPresets,
|
||||
allPresetData: newAllPresetData,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '📘 预设收藏状态切换成功: ${event.presetId}');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '❌ 切换预设收藏状态失败: ${event.presetId}', e);
|
||||
emit(state.copyWith(
|
||||
errorMessage: '切换收藏状态失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 切换预设快捷访问状态
|
||||
Future<void> _onTogglePresetQuickAccess(
|
||||
TogglePresetQuickAccess event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
final updatedPreset = await _presetRepository.toggleQuickAccess(event.presetId);
|
||||
|
||||
// 🚀 优化:直接更新本地状态,不重新请求API
|
||||
final updatedGroupedPresets = Map<String, List<AIPromptPreset>>.from(state.groupedPresets);
|
||||
final newFeatureType = updatedPreset.aiFeatureType;
|
||||
|
||||
// 🚀 修复:处理功能类型格式不一致问题
|
||||
String? existingKey = _findExistingFeatureTypeKey(updatedGroupedPresets, newFeatureType);
|
||||
final targetKey = existingKey ?? newFeatureType;
|
||||
|
||||
if (updatedGroupedPresets.containsKey(targetKey)) {
|
||||
// 找到并替换对应的预设
|
||||
final presetList = updatedGroupedPresets[targetKey]!;
|
||||
final index = presetList.indexWhere((p) => p.presetId == event.presetId);
|
||||
if (index != -1) {
|
||||
presetList[index] = updatedPreset;
|
||||
AppLogger.i(_tag, '📋 预设快捷访问状态更新在分组: $targetKey');
|
||||
}
|
||||
} else {
|
||||
AppLogger.w(_tag, '⚠️ 未找到预设分组进行快捷访问状态更新: $targetKey');
|
||||
}
|
||||
|
||||
// 更新选中的预设
|
||||
final selectedPreset = state.selectedPreset?.presetId == event.presetId
|
||||
? updatedPreset
|
||||
: state.selectedPreset;
|
||||
|
||||
// 🚀 新增:同时更新聚合数据缓存
|
||||
final newAllPresetData = _replacePresetInAggregatedData(state.allPresetData, updatedPreset);
|
||||
|
||||
emit(state.copyWith(
|
||||
selectedPreset: selectedPreset,
|
||||
groupedPresets: updatedGroupedPresets,
|
||||
allPresetData: newAllPresetData,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '📘 预设快捷访问状态切换成功: ${event.presetId}');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '❌ 切换预设快捷访问状态失败: ${event.presetId}', e);
|
||||
emit(state.copyWith(
|
||||
errorMessage: '切换快捷访问状态失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 搜索预设
|
||||
Future<void> _onSearchPresets(
|
||||
SearchPresets event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
final searchParams = PresetSearchParams(
|
||||
keyword: event.query,
|
||||
featureType: event.featureType,
|
||||
tags: event.tags,
|
||||
sortBy: event.sortBy ?? 'recent',
|
||||
);
|
||||
|
||||
final searchResults = await _presetRepository.searchPresets(searchParams);
|
||||
|
||||
emit(state.copyWith(
|
||||
searchResults: searchResults,
|
||||
searchQuery: event.query,
|
||||
errorMessage: null,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '预设搜索完成: ${searchResults.length} 个结果');
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '搜索预设失败', e);
|
||||
emit(state.copyWith(
|
||||
errorMessage: '搜索预设失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 清除搜索
|
||||
Future<void> _onClearPresetSearch(
|
||||
ClearPresetSearch event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
emit(state.copyWith(
|
||||
searchResults: [],
|
||||
searchQuery: '',
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '预设搜索已清除');
|
||||
}
|
||||
|
||||
/// 刷新预设数据
|
||||
Future<void> _onRefreshPresetData(
|
||||
RefreshPresetData event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
// 重新加载所有数据
|
||||
add(const LoadUserPresetOverview());
|
||||
add(const LoadGroupedPresets());
|
||||
|
||||
AppLogger.i(_tag, '预设数据刷新中...');
|
||||
}
|
||||
|
||||
/// 🚀 查找现有分组中相同功能类型的键(已统一格式,现在只做直接匹配)
|
||||
String? _findExistingFeatureTypeKey(Map<String, List<AIPromptPreset>> groupedPresets, String newFeatureType) {
|
||||
// 如果直接存在,返回null(使用新的键)
|
||||
if (groupedPresets.containsKey(newFeatureType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 🚀 已统一为新格式,不再需要映射,直接使用新的功能类型键
|
||||
AppLogger.i(_tag, '📋 使用新的功能类型键: $newFeatureType');
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 🚀 新增预设到本地缓存
|
||||
Future<void> _onAddPresetToCache(
|
||||
AddPresetToCache event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
final newPreset = event.preset;
|
||||
AppLogger.i(_tag, '🚀 添加新预设到本地缓存: ${newPreset.presetName}');
|
||||
|
||||
// 🚀 更新聚合数据缓存
|
||||
if (state.allPresetData != null) {
|
||||
final updatedData = _addPresetToAggregatedData(state.allPresetData!, newPreset);
|
||||
|
||||
// 同时更新分组预设以保持兼容性
|
||||
final updatedGroupedPresets = Map<String, List<AIPromptPreset>>.from(state.groupedPresets);
|
||||
final featureType = newPreset.aiFeatureType;
|
||||
|
||||
if (updatedGroupedPresets.containsKey(featureType)) {
|
||||
// 将新预设添加到列表开头
|
||||
updatedGroupedPresets[featureType] = [newPreset, ...updatedGroupedPresets[featureType]!];
|
||||
} else {
|
||||
// 创建新的功能类型分组
|
||||
updatedGroupedPresets[featureType] = [newPreset];
|
||||
}
|
||||
|
||||
emit(state.copyWith(
|
||||
allPresetData: updatedData,
|
||||
groupedPresets: updatedGroupedPresets,
|
||||
errorMessage: null,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '✅ 预设已添加到本地缓存: ${featureType}');
|
||||
} else {
|
||||
// 如果没有聚合数据,只更新分组预设
|
||||
final updatedGroupedPresets = Map<String, List<AIPromptPreset>>.from(state.groupedPresets);
|
||||
final featureType = newPreset.aiFeatureType;
|
||||
|
||||
if (updatedGroupedPresets.containsKey(featureType)) {
|
||||
updatedGroupedPresets[featureType] = [newPreset, ...updatedGroupedPresets[featureType]!];
|
||||
} else {
|
||||
updatedGroupedPresets[featureType] = [newPreset];
|
||||
}
|
||||
|
||||
emit(state.copyWith(
|
||||
groupedPresets: updatedGroupedPresets,
|
||||
errorMessage: null,
|
||||
));
|
||||
|
||||
AppLogger.w(_tag, '⚠️ 仅更新分组预设,聚合数据不存在');
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '❌ 添加预设到本地缓存失败', e);
|
||||
emit(state.copyWith(
|
||||
errorMessage: '添加预设到缓存失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 🚀 加载所有预设聚合数据
|
||||
Future<void> _onLoadAllPresetData(
|
||||
LoadAllPresetData event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
AppLogger.i(_tag, '🚀 开始加载所有预设聚合数据: novelId=${event.novelId}');
|
||||
|
||||
final allPresetData = await _aggregationRepository.getAllUserPresetData(
|
||||
novelId: event.novelId,
|
||||
);
|
||||
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
allPresetData: allPresetData,
|
||||
// 同时更新其他相关字段以保持兼容性
|
||||
userOverview: allPresetData.overview,
|
||||
groupedPresets: allPresetData.mergedGroupedPresets,
|
||||
batchPackages: allPresetData.packagesByFeatureType,
|
||||
favoritePresets: allPresetData.favoritePresets,
|
||||
quickAccessPresets: allPresetData.quickAccessPresets,
|
||||
recentlyUsedPresets: allPresetData.recentlyUsedPresets,
|
||||
errorMessage: null,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '✅ 所有预设聚合数据加载完成');
|
||||
AppLogger.i(_tag, '📊 数据统计: 系统预设${allPresetData.systemPresets.length}个, 用户预设分组${allPresetData.userPresetsByFeatureType.length}个');
|
||||
AppLogger.i(_tag, '📈 合并分组: ${allPresetData.mergedGroupedPresets.length}个功能类型');
|
||||
allPresetData.mergedGroupedPresets.forEach((featureType, presets) {
|
||||
AppLogger.i(_tag, ' - $featureType: ${presets.length}个预设');
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '❌ 加载所有预设聚合数据失败', e);
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: '加载预设数据失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 预热预设缓存
|
||||
Future<void> _onWarmupPresetCache(
|
||||
WarmupPresetCache event,
|
||||
Emitter<PresetState> emit,
|
||||
) async {
|
||||
try {
|
||||
AppLogger.i(_tag, '开始预热预设缓存...');
|
||||
|
||||
final warmupResult = await _aggregationRepository.warmupCache();
|
||||
|
||||
emit(state.copyWith(
|
||||
warmupResult: warmupResult,
|
||||
errorMessage: null,
|
||||
));
|
||||
|
||||
AppLogger.i(_tag, '预设缓存预热完成: ${warmupResult.success ? "成功" : "失败"}');
|
||||
if (warmupResult.success) {
|
||||
AppLogger.i(_tag, '预热了 ${warmupResult.warmedFeatureTypes} 个功能类型,${warmupResult.warmedPresets} 个预设,耗时 ${warmupResult.durationMs}ms');
|
||||
}
|
||||
} catch (e) {
|
||||
AppLogger.e(_tag, '预设缓存预热失败', e);
|
||||
emit(state.copyWith(
|
||||
errorMessage: '预设缓存预热失败: ${e.toString()}',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 🚀 向聚合缓存中添加新预设
|
||||
AllUserPresetData _addPresetToAggregatedData(AllUserPresetData data, AIPromptPreset newPreset) {
|
||||
final featureType = newPreset.aiFeatureType;
|
||||
|
||||
// 更新用户预设分组
|
||||
final userByFeature = Map<String, List<AIPromptPreset>>.from(data.userPresetsByFeatureType);
|
||||
if (userByFeature.containsKey(featureType)) {
|
||||
// 添加到现有分组的开头
|
||||
userByFeature[featureType] = [newPreset, ...userByFeature[featureType]!];
|
||||
} else {
|
||||
// 创建新的功能类型分组
|
||||
userByFeature[featureType] = [newPreset];
|
||||
}
|
||||
|
||||
// 更新包分组(如果存在)
|
||||
final packages = Map<String, PresetPackage>.from(data.packagesByFeatureType);
|
||||
if (packages.containsKey(featureType)) {
|
||||
final oldPackage = packages[featureType]!;
|
||||
packages[featureType] = PresetPackage(
|
||||
featureType: featureType,
|
||||
systemPresets: oldPackage.systemPresets,
|
||||
userPresets: [newPreset, ...oldPackage.userPresets],
|
||||
favoritePresets: oldPackage.favoritePresets,
|
||||
quickAccessPresets: oldPackage.quickAccessPresets,
|
||||
recentlyUsedPresets: oldPackage.recentlyUsedPresets,
|
||||
totalCount: oldPackage.totalCount + 1,
|
||||
cachedAt: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
// 如果新预设是收藏、快捷访问等特殊状态,也需要更新对应列表
|
||||
final favoritePresets = newPreset.isFavorite
|
||||
? [newPreset, ...data.favoritePresets]
|
||||
: data.favoritePresets;
|
||||
|
||||
final quickAccessPresets = newPreset.showInQuickAccess
|
||||
? [newPreset, ...data.quickAccessPresets]
|
||||
: data.quickAccessPresets;
|
||||
|
||||
// 添加到最近使用列表的开头
|
||||
final recentlyUsedPresets = [newPreset, ...data.recentlyUsedPresets];
|
||||
|
||||
// 更新概览统计
|
||||
final currentStats = data.overview.presetsByFeatureType[featureType];
|
||||
final updatedStats = currentStats != null
|
||||
? PresetTypeStats(
|
||||
systemCount: currentStats.systemCount,
|
||||
userCount: currentStats.userCount + 1,
|
||||
favoriteCount: newPreset.isFavorite ? currentStats.favoriteCount + 1 : currentStats.favoriteCount,
|
||||
recentUsageCount: currentStats.recentUsageCount + 1,
|
||||
)
|
||||
: PresetTypeStats(
|
||||
systemCount: 0,
|
||||
userCount: 1,
|
||||
favoriteCount: newPreset.isFavorite ? 1 : 0,
|
||||
recentUsageCount: 1,
|
||||
);
|
||||
|
||||
final overview = UserPresetOverview(
|
||||
totalPresets: data.overview.totalPresets + 1,
|
||||
systemPresets: data.overview.systemPresets,
|
||||
userPresets: data.overview.userPresets + 1,
|
||||
favoritePresets: favoritePresets.length,
|
||||
presetsByFeatureType: {
|
||||
...data.overview.presetsByFeatureType,
|
||||
featureType: updatedStats,
|
||||
},
|
||||
recentFeatureTypes: _updateRecentFeatureTypes(data.overview.recentFeatureTypes, featureType),
|
||||
popularTags: data.overview.popularTags,
|
||||
generatedAt: DateTime.now(),
|
||||
);
|
||||
|
||||
return AllUserPresetData(
|
||||
userId: data.userId,
|
||||
overview: overview,
|
||||
packagesByFeatureType: packages,
|
||||
systemPresets: data.systemPresets,
|
||||
userPresetsByFeatureType: userByFeature,
|
||||
favoritePresets: favoritePresets,
|
||||
quickAccessPresets: quickAccessPresets,
|
||||
recentlyUsedPresets: recentlyUsedPresets,
|
||||
timestamp: DateTime.now(),
|
||||
cacheDuration: data.cacheDuration,
|
||||
);
|
||||
}
|
||||
|
||||
/// 🚀 更新最近使用的功能类型列表
|
||||
List<String> _updateRecentFeatureTypes(List<String> current, String newFeatureType) {
|
||||
final updated = [newFeatureType];
|
||||
for (final type in current) {
|
||||
if (type != newFeatureType && updated.length < 5) {
|
||||
updated.add(type);
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
/// 🚀 从聚合缓存中删除指定预设
|
||||
AllUserPresetData? _removePresetFromAggregatedData(AllUserPresetData? data, String presetId) {
|
||||
if (data == null) return null;
|
||||
|
||||
bool found = false;
|
||||
|
||||
// 从系统预设列表中移除
|
||||
final system = data.systemPresets.where((p) => p.presetId != presetId).toList();
|
||||
if (system.length != data.systemPresets.length) found = true;
|
||||
|
||||
// 从用户预设分组中移除
|
||||
final userByFeature = <String, List<AIPromptPreset>>{};
|
||||
data.userPresetsByFeatureType.forEach((k, list) {
|
||||
final filtered = list.where((p) => p.presetId != presetId).toList();
|
||||
if (filtered.isNotEmpty) {
|
||||
userByFeature[k] = filtered;
|
||||
}
|
||||
if (filtered.length != list.length) found = true;
|
||||
});
|
||||
|
||||
// 从收藏/快捷/最近列表中移除
|
||||
final fav = data.favoritePresets.where((p) => p.presetId != presetId).toList();
|
||||
final quick = data.quickAccessPresets.where((p) => p.presetId != presetId).toList();
|
||||
final recent = data.recentlyUsedPresets.where((p) => p.presetId != presetId).toList();
|
||||
|
||||
if (!found) return data; // 未找到则直接返回原数据
|
||||
|
||||
// 更新包分组
|
||||
final packages = Map<String, PresetPackage>.from(data.packagesByFeatureType);
|
||||
packages.forEach((featureType, package) {
|
||||
final filteredUser = package.userPresets.where((p) => p.presetId != presetId).toList();
|
||||
final filteredSystem = package.systemPresets.where((p) => p.presetId != presetId).toList();
|
||||
|
||||
if (filteredUser.length != package.userPresets.length ||
|
||||
filteredSystem.length != package.systemPresets.length) {
|
||||
packages[featureType] = PresetPackage(
|
||||
featureType: featureType,
|
||||
systemPresets: filteredSystem,
|
||||
userPresets: filteredUser,
|
||||
favoritePresets: package.favoritePresets.where((p) => p.presetId != presetId).toList(),
|
||||
quickAccessPresets: package.quickAccessPresets.where((p) => p.presetId != presetId).toList(),
|
||||
recentlyUsedPresets: package.recentlyUsedPresets.where((p) => p.presetId != presetId).toList(),
|
||||
totalCount: filteredUser.length + filteredSystem.length,
|
||||
cachedAt: DateTime.now(),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// 更新概览统计
|
||||
final overview = UserPresetOverview(
|
||||
totalPresets: data.overview.totalPresets - 1,
|
||||
systemPresets: system.length,
|
||||
userPresets: userByFeature.values.fold(0, (sum, list) => sum + list.length),
|
||||
favoritePresets: fav.length,
|
||||
presetsByFeatureType: data.overview.presetsByFeatureType, // 保持不变,可选优化
|
||||
recentFeatureTypes: data.overview.recentFeatureTypes,
|
||||
popularTags: data.overview.popularTags,
|
||||
generatedAt: DateTime.now(),
|
||||
);
|
||||
|
||||
return AllUserPresetData(
|
||||
userId: data.userId,
|
||||
overview: overview,
|
||||
packagesByFeatureType: packages,
|
||||
systemPresets: system,
|
||||
userPresetsByFeatureType: userByFeature,
|
||||
favoritePresets: fav,
|
||||
quickAccessPresets: quick,
|
||||
recentlyUsedPresets: recent,
|
||||
timestamp: DateTime.now(),
|
||||
cacheDuration: data.cacheDuration,
|
||||
);
|
||||
}
|
||||
|
||||
/// 🚀 在聚合缓存中替换指定预设
|
||||
AllUserPresetData? _replacePresetInAggregatedData(AllUserPresetData? data, AIPromptPreset updated) {
|
||||
if (data == null) return null;
|
||||
|
||||
bool replaced = false;
|
||||
|
||||
// 更新系统预设列表
|
||||
List<AIPromptPreset> system = data.systemPresets
|
||||
.map((p) => p.presetId == updated.presetId ? updated : p)
|
||||
.toList();
|
||||
if (!replaced) replaced = system.any((p) => p.presetId == updated.presetId);
|
||||
|
||||
// 更新用户预设分组
|
||||
final userByFeature = <String, List<AIPromptPreset>>{};
|
||||
data.userPresetsByFeatureType.forEach((k, list) {
|
||||
userByFeature[k] = list.map((p) => p.presetId == updated.presetId ? updated : p).toList();
|
||||
if (!replaced) {
|
||||
replaced = list.any((p) => p.presetId == updated.presetId);
|
||||
}
|
||||
});
|
||||
|
||||
// 更新收藏/快捷/最近
|
||||
List<AIPromptPreset> _mapList(List<AIPromptPreset> src) =>
|
||||
src.map((p) => p.presetId == updated.presetId ? updated : p).toList();
|
||||
final fav = _mapList(data.favoritePresets);
|
||||
final quick = _mapList(data.quickAccessPresets);
|
||||
final recent = _mapList(data.recentlyUsedPresets);
|
||||
|
||||
// 如果所有列表都未包含,则根据预设类型追加到正确列表
|
||||
if (!replaced) {
|
||||
if (updated.isSystem) {
|
||||
system.add(updated);
|
||||
} else {
|
||||
userByFeature.putIfAbsent(updated.aiFeatureType, () => []);
|
||||
userByFeature[updated.aiFeatureType]!.add(updated);
|
||||
}
|
||||
// 快捷访问
|
||||
if (updated.showInQuickAccess && !quick.any((p) => p.presetId == updated.presetId)) {
|
||||
quick.insert(0, updated);
|
||||
}
|
||||
// 收藏
|
||||
if (updated.isFavorite && !fav.any((p) => p.presetId == updated.presetId)) {
|
||||
fav.insert(0, updated);
|
||||
}
|
||||
// 最近使用无需处理
|
||||
}
|
||||
|
||||
return AllUserPresetData(
|
||||
userId: data.userId,
|
||||
overview: data.overview,
|
||||
packagesByFeatureType: data.packagesByFeatureType,
|
||||
systemPresets: system,
|
||||
userPresetsByFeatureType: userByFeature,
|
||||
favoritePresets: fav,
|
||||
quickAccessPresets: quick,
|
||||
recentlyUsedPresets: recent,
|
||||
timestamp: DateTime.now(), // 🔧 修复:更新为当前时间戳
|
||||
cacheDuration: data.cacheDuration,
|
||||
);
|
||||
}
|
||||
}
|
||||
272
AINoval/lib/blocs/preset/preset_event.dart
Normal file
272
AINoval/lib/blocs/preset/preset_event.dart
Normal file
@@ -0,0 +1,272 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:ainoval/models/preset_models.dart';
|
||||
|
||||
/// 预设管理事件基类
|
||||
abstract class PresetEvent extends Equatable {
|
||||
const PresetEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
/// 加载用户预设概览
|
||||
class LoadUserPresetOverview extends PresetEvent {
|
||||
const LoadUserPresetOverview();
|
||||
}
|
||||
|
||||
/// 加载预设包
|
||||
class LoadPresetPackage extends PresetEvent {
|
||||
final String featureType;
|
||||
final String? novelId;
|
||||
|
||||
const LoadPresetPackage({
|
||||
required this.featureType,
|
||||
this.novelId,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [featureType, novelId];
|
||||
}
|
||||
|
||||
/// 加载批量预设包
|
||||
class LoadBatchPresetPackages extends PresetEvent {
|
||||
final List<String>? featureTypes;
|
||||
final String? novelId;
|
||||
|
||||
const LoadBatchPresetPackages({
|
||||
this.featureTypes,
|
||||
this.novelId,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [featureTypes, novelId];
|
||||
}
|
||||
|
||||
/// 加载分组预设
|
||||
class LoadGroupedPresets extends PresetEvent {
|
||||
final String? userId;
|
||||
|
||||
const LoadGroupedPresets({this.userId});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [userId];
|
||||
}
|
||||
|
||||
/// 选择预设
|
||||
class SelectPreset extends PresetEvent {
|
||||
final String presetId;
|
||||
|
||||
const SelectPreset({required this.presetId});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [presetId];
|
||||
}
|
||||
|
||||
/// 创建预设
|
||||
class CreatePreset extends PresetEvent {
|
||||
final CreatePresetRequest request;
|
||||
|
||||
const CreatePreset({required this.request});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [request];
|
||||
}
|
||||
|
||||
/// 覆盖更新预设(完整对象)
|
||||
class OverwritePreset extends PresetEvent {
|
||||
final AIPromptPreset preset;
|
||||
|
||||
const OverwritePreset({required this.preset});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [preset];
|
||||
}
|
||||
|
||||
/// 更新预设
|
||||
class UpdatePreset extends PresetEvent {
|
||||
final String presetId;
|
||||
final UpdatePresetInfoRequest? infoRequest;
|
||||
final UpdatePresetPromptsRequest? promptsRequest;
|
||||
|
||||
const UpdatePreset({
|
||||
required this.presetId,
|
||||
this.infoRequest,
|
||||
this.promptsRequest,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [presetId, infoRequest, promptsRequest];
|
||||
}
|
||||
|
||||
/// 删除预设
|
||||
class DeletePreset extends PresetEvent {
|
||||
final String presetId;
|
||||
|
||||
const DeletePreset({required this.presetId});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [presetId];
|
||||
}
|
||||
|
||||
/// 复制预设
|
||||
class DuplicatePreset extends PresetEvent {
|
||||
final String presetId;
|
||||
final DuplicatePresetRequest request;
|
||||
|
||||
const DuplicatePreset({
|
||||
required this.presetId,
|
||||
required this.request,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [presetId, request];
|
||||
}
|
||||
|
||||
/// 切换预设收藏状态
|
||||
class TogglePresetFavorite extends PresetEvent {
|
||||
final String presetId;
|
||||
|
||||
const TogglePresetFavorite({required this.presetId});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [presetId];
|
||||
}
|
||||
|
||||
/// 切换预设快捷访问状态
|
||||
class TogglePresetQuickAccess extends PresetEvent {
|
||||
final String presetId;
|
||||
|
||||
const TogglePresetQuickAccess({required this.presetId});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [presetId];
|
||||
}
|
||||
|
||||
/// 记录预设使用
|
||||
class RecordPresetUsage extends PresetEvent {
|
||||
final String presetId;
|
||||
|
||||
const RecordPresetUsage({required this.presetId});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [presetId];
|
||||
}
|
||||
|
||||
/// 搜索预设
|
||||
class SearchPresets extends PresetEvent {
|
||||
final String query;
|
||||
final String? featureType;
|
||||
final List<String>? tags;
|
||||
final String? sortBy;
|
||||
|
||||
const SearchPresets({
|
||||
required this.query,
|
||||
this.featureType,
|
||||
this.tags,
|
||||
this.sortBy,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [query, featureType, tags, sortBy];
|
||||
}
|
||||
|
||||
/// 清除预设搜索
|
||||
class ClearPresetSearch extends PresetEvent {
|
||||
const ClearPresetSearch();
|
||||
}
|
||||
|
||||
/// 获取预设统计信息
|
||||
class LoadPresetStatistics extends PresetEvent {
|
||||
const LoadPresetStatistics();
|
||||
}
|
||||
|
||||
/// 获取收藏预设
|
||||
class LoadFavoritePresets extends PresetEvent {
|
||||
final String? novelId;
|
||||
final String? featureType;
|
||||
|
||||
const LoadFavoritePresets({
|
||||
this.novelId,
|
||||
this.featureType,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [novelId, featureType];
|
||||
}
|
||||
|
||||
/// 获取最近使用预设
|
||||
class LoadRecentlyUsedPresets extends PresetEvent {
|
||||
final int limit;
|
||||
final String? novelId;
|
||||
final String? featureType;
|
||||
|
||||
const LoadRecentlyUsedPresets({
|
||||
this.limit = 10,
|
||||
this.novelId,
|
||||
this.featureType,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [limit, novelId, featureType];
|
||||
}
|
||||
|
||||
/// 获取快捷访问预设
|
||||
class LoadQuickAccessPresets extends PresetEvent {
|
||||
final String? featureType;
|
||||
final String? novelId;
|
||||
|
||||
const LoadQuickAccessPresets({
|
||||
this.featureType,
|
||||
this.novelId,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [featureType, novelId];
|
||||
}
|
||||
|
||||
/// 刷新预设数据
|
||||
class RefreshPresetData extends PresetEvent {
|
||||
const RefreshPresetData();
|
||||
}
|
||||
|
||||
/// 预热缓存
|
||||
class WarmupPresetCache extends PresetEvent {
|
||||
const WarmupPresetCache();
|
||||
}
|
||||
|
||||
/// 获取缓存统计
|
||||
class LoadCacheStats extends PresetEvent {
|
||||
const LoadCacheStats();
|
||||
}
|
||||
|
||||
/// 清除缓存
|
||||
class ClearPresetCache extends PresetEvent {
|
||||
const ClearPresetCache();
|
||||
}
|
||||
|
||||
/// 健康检查
|
||||
class PresetHealthCheck extends PresetEvent {
|
||||
const PresetHealthCheck();
|
||||
}
|
||||
|
||||
/// 🚀 加载所有预设聚合数据
|
||||
/// 一次性加载用户的所有预设相关数据,避免多次API调用
|
||||
class LoadAllPresetData extends PresetEvent {
|
||||
final String? novelId;
|
||||
|
||||
const LoadAllPresetData({this.novelId});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [novelId];
|
||||
}
|
||||
|
||||
/// 🚀 新增预设到本地缓存
|
||||
/// 创建预设成功后直接添加到本地缓存,避免重新加载
|
||||
class AddPresetToCache extends PresetEvent {
|
||||
final AIPromptPreset preset;
|
||||
|
||||
const AddPresetToCache({required this.preset});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [preset];
|
||||
}
|
||||
240
AINoval/lib/blocs/preset/preset_state.dart
Normal file
240
AINoval/lib/blocs/preset/preset_state.dart
Normal file
@@ -0,0 +1,240 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:ainoval/models/preset_models.dart';
|
||||
|
||||
/// 预设管理状态
|
||||
class PresetState extends Equatable {
|
||||
/// 是否正在加载
|
||||
final bool isLoading;
|
||||
|
||||
/// 错误信息
|
||||
final String? errorMessage;
|
||||
|
||||
/// 用户预设概览
|
||||
final UserPresetOverview? userOverview;
|
||||
|
||||
/// 当前预设包
|
||||
final PresetPackage? currentPackage;
|
||||
|
||||
/// 批量预设包
|
||||
final Map<String, PresetPackage> batchPackages;
|
||||
|
||||
/// 按功能类型分组的预设
|
||||
final Map<String, List<AIPromptPreset>> groupedPresets;
|
||||
|
||||
/// 当前选中的预设
|
||||
final AIPromptPreset? selectedPreset;
|
||||
|
||||
/// 搜索结果
|
||||
final List<AIPromptPreset> searchResults;
|
||||
|
||||
/// 搜索查询
|
||||
final String searchQuery;
|
||||
|
||||
/// 预设统计信息
|
||||
final PresetStatistics? statistics;
|
||||
|
||||
/// 收藏预设列表
|
||||
final List<AIPromptPreset> favoritePresets;
|
||||
|
||||
/// 最近使用预设列表
|
||||
final List<AIPromptPreset> recentlyUsedPresets;
|
||||
|
||||
/// 快捷访问预设列表
|
||||
final List<AIPromptPreset> quickAccessPresets;
|
||||
|
||||
/// 缓存预热结果
|
||||
final CacheWarmupResult? warmupResult;
|
||||
|
||||
/// 缓存统计信息
|
||||
final AggregationCacheStats? cacheStats;
|
||||
|
||||
/// 健康检查结果
|
||||
final Map<String, dynamic>? healthStatus;
|
||||
|
||||
/// 🚀 所有预设聚合数据
|
||||
final AllUserPresetData? allPresetData;
|
||||
|
||||
const PresetState({
|
||||
this.isLoading = false,
|
||||
this.errorMessage,
|
||||
this.userOverview,
|
||||
this.currentPackage,
|
||||
this.batchPackages = const {},
|
||||
this.groupedPresets = const {},
|
||||
this.selectedPreset,
|
||||
this.searchResults = const [],
|
||||
this.searchQuery = '',
|
||||
this.statistics,
|
||||
this.favoritePresets = const [],
|
||||
this.recentlyUsedPresets = const [],
|
||||
this.quickAccessPresets = const [],
|
||||
this.warmupResult,
|
||||
this.cacheStats,
|
||||
this.healthStatus,
|
||||
this.allPresetData,
|
||||
});
|
||||
|
||||
/// 初始状态
|
||||
const PresetState.initial() : this();
|
||||
|
||||
/// 加载状态
|
||||
PresetState.loading() : this(isLoading: true);
|
||||
|
||||
/// 错误状态
|
||||
PresetState.error(String message) : this(errorMessage: message);
|
||||
|
||||
/// 复制状态并更新指定字段
|
||||
PresetState copyWith({
|
||||
bool? isLoading,
|
||||
String? errorMessage,
|
||||
UserPresetOverview? userOverview,
|
||||
PresetPackage? currentPackage,
|
||||
Map<String, PresetPackage>? batchPackages,
|
||||
Map<String, List<AIPromptPreset>>? groupedPresets,
|
||||
AIPromptPreset? selectedPreset,
|
||||
List<AIPromptPreset>? searchResults,
|
||||
String? searchQuery,
|
||||
PresetStatistics? statistics,
|
||||
List<AIPromptPreset>? favoritePresets,
|
||||
List<AIPromptPreset>? recentlyUsedPresets,
|
||||
List<AIPromptPreset>? quickAccessPresets,
|
||||
CacheWarmupResult? warmupResult,
|
||||
AggregationCacheStats? cacheStats,
|
||||
Map<String, dynamic>? healthStatus,
|
||||
AllUserPresetData? allPresetData,
|
||||
}) {
|
||||
return PresetState(
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
errorMessage: errorMessage,
|
||||
userOverview: userOverview ?? this.userOverview,
|
||||
currentPackage: currentPackage ?? this.currentPackage,
|
||||
batchPackages: batchPackages ?? this.batchPackages,
|
||||
groupedPresets: groupedPresets ?? this.groupedPresets,
|
||||
selectedPreset: selectedPreset,
|
||||
searchResults: searchResults ?? this.searchResults,
|
||||
searchQuery: searchQuery ?? this.searchQuery,
|
||||
statistics: statistics ?? this.statistics,
|
||||
favoritePresets: favoritePresets ?? this.favoritePresets,
|
||||
recentlyUsedPresets: recentlyUsedPresets ?? this.recentlyUsedPresets,
|
||||
quickAccessPresets: quickAccessPresets ?? this.quickAccessPresets,
|
||||
warmupResult: warmupResult ?? this.warmupResult,
|
||||
cacheStats: cacheStats ?? this.cacheStats,
|
||||
healthStatus: healthStatus ?? this.healthStatus,
|
||||
allPresetData: allPresetData ?? this.allPresetData,
|
||||
);
|
||||
}
|
||||
|
||||
/// 是否有数据
|
||||
bool get hasData {
|
||||
return userOverview != null ||
|
||||
currentPackage != null ||
|
||||
batchPackages.isNotEmpty ||
|
||||
groupedPresets.isNotEmpty ||
|
||||
searchResults.isNotEmpty;
|
||||
}
|
||||
|
||||
/// 是否有错误
|
||||
bool get hasError => errorMessage != null;
|
||||
|
||||
/// 是否有选中的预设
|
||||
bool get hasSelectedPreset => selectedPreset != null;
|
||||
|
||||
/// 是否正在搜索
|
||||
bool get isSearching => searchQuery.isNotEmpty;
|
||||
|
||||
/// 获取所有预设的总数
|
||||
int get totalPresetCount {
|
||||
return groupedPresets.values.fold(0, (sum, presets) => sum + presets.length);
|
||||
}
|
||||
|
||||
/// 获取用户预设数量
|
||||
int get userPresetCount {
|
||||
return groupedPresets.values
|
||||
.expand((presets) => presets)
|
||||
.where((preset) => !preset.isSystem)
|
||||
.length;
|
||||
}
|
||||
|
||||
/// 获取系统预设数量
|
||||
int get systemPresetCount {
|
||||
return groupedPresets.values
|
||||
.expand((presets) => presets)
|
||||
.where((preset) => preset.isSystem)
|
||||
.length;
|
||||
}
|
||||
|
||||
/// 获取收藏预设数量
|
||||
int get favoritePresetCount {
|
||||
return groupedPresets.values
|
||||
.expand((presets) => presets)
|
||||
.where((preset) => preset.isFavorite)
|
||||
.length;
|
||||
}
|
||||
|
||||
/// 获取快捷访问预设数量
|
||||
int get quickAccessPresetCount {
|
||||
return groupedPresets.values
|
||||
.expand((presets) => presets)
|
||||
.where((preset) => preset.showInQuickAccess)
|
||||
.length;
|
||||
}
|
||||
|
||||
/// 获取指定功能类型的预设列表
|
||||
List<AIPromptPreset> getPresetsByFeatureType(String featureType) {
|
||||
return groupedPresets[featureType] ?? [];
|
||||
}
|
||||
|
||||
/// 获取所有预设的平铺列表
|
||||
List<AIPromptPreset> get allPresets {
|
||||
return groupedPresets.values.expand((presets) => presets).toList();
|
||||
}
|
||||
|
||||
/// 🚀 获取合并后的分组预设(系统预设+用户预设,按功能分组)
|
||||
/// 优先使用allPresetData中的合并数据,如果没有则使用旧的groupedPresets
|
||||
Map<String, List<AIPromptPreset>> get mergedGroupedPresets {
|
||||
if (allPresetData != null) {
|
||||
return allPresetData!.mergedGroupedPresets;
|
||||
}
|
||||
return groupedPresets;
|
||||
}
|
||||
|
||||
/// 是否已加载聚合数据
|
||||
bool get hasAllPresetData => allPresetData != null;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
isLoading,
|
||||
errorMessage,
|
||||
userOverview,
|
||||
currentPackage,
|
||||
batchPackages,
|
||||
groupedPresets,
|
||||
selectedPreset,
|
||||
searchResults,
|
||||
searchQuery,
|
||||
statistics,
|
||||
favoritePresets,
|
||||
recentlyUsedPresets,
|
||||
quickAccessPresets,
|
||||
warmupResult,
|
||||
cacheStats,
|
||||
healthStatus,
|
||||
allPresetData,
|
||||
];
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''PresetState(
|
||||
isLoading: $isLoading,
|
||||
hasError: $hasError,
|
||||
hasData: $hasData,
|
||||
totalPresets: $totalPresetCount,
|
||||
userPresets: $userPresetCount,
|
||||
systemPresets: $systemPresetCount,
|
||||
favoritePresets: $favoritePresetCount,
|
||||
quickAccessPresets: $quickAccessPresetCount,
|
||||
selectedPreset: ${selectedPreset?.presetName ?? 'null'},
|
||||
searchQuery: '$searchQuery',
|
||||
)''';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user