- 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,无需修改
152 lines
4.3 KiB
Dart
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();
|
|
}
|
|
}
|
|
}
|