search method
Future<List<UDocSearchHit> >
search(
- String query, {
- UDocSearchOptions options = const UDocSearchOptions(),
Implementation
Future<List<UDocSearchHit>> search(String query, {UDocSearchOptions options = const UDocSearchOptions()}) async {
final UEpubBook? book = _book;
final String trimmed = query.trim();
if (book == null || trimmed.isEmpty) {
clearSearch();
return const <UDocSearchHit>[];
}
final int token = ++_searchToken;
emit(value.copyWith(searchQuery: trimmed, isSearching: true, searchHits: const <UDocSearchHit>[], searchHitIndex: -1));
final String needle = options.normalizePersian ? UDocText.forSearch(trimmed) : trimmed.toLowerCase();
final List<UDocSearchHit> hits = <UDocSearchHit>[];
for (int index = 0; index < book.chapterCount; index++) {
if (token != _searchToken || isDisposed) return hits;
final UEpubChapter chapter = await this.chapter(index);
if (chapter.text.isEmpty) continue;
final UDocNormalizedText normalized = options.normalizePersian
? UDocNormalizedText.build(chapter.text)
: UDocNormalizedText(chapter.text.toLowerCase(), List<int>.generate(chapter.text.length, (int i) => i));
for (final int position in UDocText.findAll(normalized.text, needle, wholeWord: options.wholeWord)) {
final int start = normalized.sourceAt(position);
final int end = normalized.sourceAt(position + needle.length - 1) + 1;
final int snippetStart = start - 48 < 0 ? 0 : start - 48;
final int snippetEnd = end + 48 > chapter.text.length ? chapter.text.length : end + 48;
hits.add(
UDocSearchHit(pageIndex: index, start: start, end: end, snippet: chapter.text.substring(snippetStart, snippetEnd).replaceAll("\n", " "), rects: const <Rect>[], matchIndex: hits.length),
);
if (hits.length >= options.maxHits) break;
}
liveHits.value = List<UDocSearchHit>.from(hits);
if (hits.length >= options.maxHits) break;
}
if (token != _searchToken || isDisposed) return hits;
emit(value.copyWith(searchHits: hits, isSearching: false, searchHitIndex: hits.isEmpty ? -1 : 0));
return hits;
}