Files
nj/app/lib/features/search/bloc/search_bloc.dart
iven e57c3427a4 fix(app): 18 处 catch(e) 添加 debugPrint 异常日志
- parent_bloc: 6 处 (LoadChildren/BindChild/ViewJournals/ExportData/DeleteData/UnbindChild)
- search_bloc: 3 处 (SearchByMood/SearchByTag/SearchByKeyword)
- achievement_bloc: 1 处 (_fetchAchievements)
- sticker_bloc: 2 处 (_fetchPacks/fetchStickersInPack)
- template_bloc: 1 处 (_fetchTemplates)
- mood_bloc: 1 处 (_loadStats)
- home_bloc: 1 处 (_onLoadData)
- calendar_bloc: 1 处 (_onMonthChanged)
- sync_engine: 1 处 (trySync)
- weekly_page: 已有 debugPrint,无需修改
2026-06-02 23:21:16 +08:00

152 lines
4.3 KiB
Dart

// 搜索 BLoC — 关键词+标签+心情筛选日记
//
// 状态机: SearchInitial → SearchLoading → SearchLoaded/SearchError
// 支持关键词搜索、标签筛选、心情筛选、结果分类 tab。
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../data/models/journal_entry.dart';
import '../../../data/repositories/journal_repository.dart';
part 'search_event.dart';
part 'search_state.dart';
/// 搜索 BLoC
class SearchBloc extends Bloc<SearchEvent, SearchState> {
final JournalRepository _journalRepo;
/// 内存搜索历史(最多 10 条)
final List<String> _searchHistory = [];
SearchBloc({required JournalRepository journalRepository})
: _journalRepo = journalRepository,
super(const SearchInitial()) {
on<SearchByMood>(_onSearchByMood);
on<SearchByTag>(_onSearchByTag);
on<SearchByKeyword>(_onSearchByKeyword);
on<SearchClear>(_onSearchClear);
on<SearchTabChanged>(_onSearchTabChanged);
}
/// 按心情筛选日记
Future<void> _onSearchByMood(
SearchByMood event,
Emitter<SearchState> emit,
) async {
emit(const SearchLoading());
try {
if (event.mood == null) {
emit(SearchLoaded(searchHistory: List.unmodifiable(_searchHistory)));
return;
}
final results = await _journalRepo.getJournals(
mood: event.mood!.value,
page: 1,
pageSize: 50,
);
emit(SearchLoaded(
results: results,
activeMood: event.mood!.value,
searchHistory: List.unmodifiable(_searchHistory),
));
} catch (e) {
debugPrint('SearchBloc._onSearchByMood 失败: $e');
emit(const SearchError('搜索失败,请重试'));
}
}
/// 按标签筛选日记
Future<void> _onSearchByTag(
SearchByTag event,
Emitter<SearchState> emit,
) async {
emit(const SearchLoading());
try {
_addToHistory(event.tag);
final results = await _journalRepo.getJournals(
tag: event.tag,
page: 1,
pageSize: 50,
);
emit(SearchLoaded(
results: results,
activeTag: event.tag,
searchHistory: List.unmodifiable(_searchHistory),
));
} catch (e) {
debugPrint('SearchBloc._onSearchByTag 失败: $e');
emit(const SearchError('搜索失败,请重试'));
}
}
/// 关键词搜索 — 在标题中匹配关键词
Future<void> _onSearchByKeyword(
SearchByKeyword event,
Emitter<SearchState> emit,
) async {
final keyword = event.keyword.trim();
if (keyword.isEmpty) {
emit(SearchLoaded(searchHistory: List.unmodifiable(_searchHistory)));
return;
}
emit(const SearchLoading());
try {
_addToHistory(keyword);
// 获取所有日记并在客户端按关键词过滤
final allJournals = await _journalRepo.getJournals(
page: 1,
pageSize: 200,
);
final lowerKeyword = keyword.toLowerCase();
final results = allJournals.where((j) {
final titleMatch = j.title.toLowerCase().contains(lowerKeyword);
final excerptMatch = (j.contentExcerpt ?? '')
.toLowerCase()
.contains(lowerKeyword);
final tagMatch =
j.tags.any((t) => t.toLowerCase().contains(lowerKeyword));
return titleMatch || excerptMatch || tagMatch;
}).toList();
emit(SearchLoaded(
results: results,
activeKeyword: keyword,
searchHistory: List.unmodifiable(_searchHistory),
));
} catch (e) {
debugPrint('SearchBloc._onSearchByKeyword 失败: $e');
emit(const SearchError('搜索失败,请重试'));
}
}
/// 清除搜索结果
void _onSearchClear(
SearchClear event,
Emitter<SearchState> emit,
) {
emit(SearchLoaded(searchHistory: List.unmodifiable(_searchHistory)));
}
/// 切换结果分类 tab
void _onSearchTabChanged(
SearchTabChanged event,
Emitter<SearchState> emit,
) {
final current = state;
if (current is SearchLoaded) {
emit(current.copyWith(activeTab: event.tab));
}
}
/// 添加到搜索历史(去重,最多 10 条)
void _addToHistory(String keyword) {
_searchHistory.remove(keyword);
_searchHistory.insert(0, keyword);
if (_searchHistory.length > 10) {
_searchHistory.removeLast();
}
}
}