// 搜索 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 { final JournalRepository _journalRepo; /// 内存搜索历史(最多 10 条) final List _searchHistory = []; SearchBloc({required JournalRepository journalRepository}) : _journalRepo = journalRepository, super(const SearchInitial()) { on(_onSearchByMood); on(_onSearchByTag); on(_onSearchByKeyword); on(_onSearchClear); on(_onSearchTabChanged); } /// 按心情筛选日记 Future _onSearchByMood( SearchByMood event, Emitter 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 _onSearchByTag( SearchByTag event, Emitter 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 _onSearchByKeyword( SearchByKeyword event, Emitter 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 emit, ) { emit(SearchLoaded(searchHistory: List.unmodifiable(_searchHistory))); } /// 切换结果分类 tab void _onSearchTabChanged( SearchTabChanged event, Emitter 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(); } } }