Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions lib/core/bookmarks/src/providers/local_providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,33 @@ enum BookmarkSortType {
List<Bookmark> filterBookmarks({
required List<Bookmark> bookmarks,
required List<String> selectedTags,
required List<String> excludedTags,
required BookmarkSortType sortType,
String? selectedBooruUrl,
BookmarkShuffleState? shuffleState,
}) {
final tagsList = selectedTags;
final excludeList = excludedTags;

final hasFilters =
selectedBooruUrl != null || tagsList.isNotEmpty || excludeList.isNotEmpty;

// Filter bookmarks based on URL and tags.
final filtered = selectedBooruUrl == null && tagsList.isEmpty
? bookmarks
: bookmarks.where(
final filtered = hasFilters
? bookmarks.where(
(bookmark) =>
(selectedBooruUrl == null ||
bookmark.sourceUrl.contains(selectedBooruUrl)) &&
(tagsList.isEmpty ||
tagsList.every((tag) => bookmark.tags.contains(tag))),
);
tagsList.every((tag) => bookmark.tags.contains(tag))) &&
(excludeList.isEmpty ||
excludeList.every(
(tag) =>
!bookmark.tags.contains(tag) &&
!bookmark.sourceUrl.contains(tag),
)),
)
: bookmarks;

final sorted = filtered
.sorted(
Expand Down
12 changes: 9 additions & 3 deletions lib/core/bookmarks/src/providers/suggestion_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,16 @@ class TagSuggestionsNotifier
);

try {
final tags = tagString.trim().split(' ');
final tag = tags.lastOrNull?.trim();
final segments = tagString.trim().split(' ');
final rawTag = segments.lastOrNull?.trim() ?? '';

if (tag == null || tag.isEmpty) {
// Strip leading - for exclusion tag suggestions
final tag = switch (rawTag) {
String t when t.startsWith('-') => t.substring(1),
_ => rawTag,
};

if (tag.isEmpty) {
state = AsyncValue.data(
currentState.copyWith(
suggestions: const [],
Expand Down
39 changes: 28 additions & 11 deletions lib/core/bookmarks/src/widgets/bookmark_scroll_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,29 @@ class BookmarkScrollView extends ConsumerStatefulWidget {
class _BookmarkScrollViewState extends ConsumerState<BookmarkScrollView> {
final _selectionModeController = SelectionModeController();

List<String> _parseTagsFromText(String text) {
return text.isEmpty
? <String>[]
: text
.trim()
.replaceAll(RegExp(r'\s+'), ' ')
.split(' ')
.where((e) => e.isNotEmpty)
.toList();
({
List<String> include,
List<String> exclude,
})
_parseTagsFromText(String text) {
if (text.isEmpty) {
return (include: <String>[], exclude: <String>[]);
}

final segments = text
.trim()
.replaceAll(RegExp(r'\s+'), ' ')
.split(' ')
.where((e) => e.isNotEmpty)
.toList();

return (
include: segments.where((e) => !e.startsWith('-')).toList(),
exclude: segments
.where((e) => e.startsWith('-'))
.map((e) => e.substring(1))
.toList(),
);
}

@override
Expand All @@ -81,12 +95,15 @@ class _BookmarkScrollViewState extends ConsumerState<BookmarkScrollView> {
},
fetcher: (page) => TaskEither.Do(
($) async {
final searchTags = _parseTagsFromText(widget.searchController.text);
final (:include, :exclude) = _parseTagsFromText(
widget.searchController.text,
);
final sortType = ref.read(selectedBookmarkSortTypeProvider);
final selectedBooruUrl = ref.read(selectedBooruUrlProvider);
final shuffleState = ref.read(bookmarkShuffleProvider);
final bookmarks = filterBookmarks(
selectedTags: searchTags,
selectedTags: include,
excludedTags: exclude,
bookmarks: await (await ref.read(bookmarkRepoProvider.future))
.getAllBookmarksOrEmpty(
imageUrlResolver: (booruId) =>
Expand Down
8 changes: 6 additions & 2 deletions lib/core/bookmarks/src/widgets/bookmark_search_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,13 @@ class _BookmarkSearchBarState extends ConsumerState<BookmarkSearchBar> {
child: _Overlay(
controller: widget.controller,
onTap: (tag) {
final text = widget.controller.text;
final lastSegment = text.split(' ').last;
final isExcluding = lastSegment.startsWith('-');
final adjustedTag = isExcluding ? '-${tag.tag}' : tag.tag;
widget.controller.text = replaceOrAppendTag(
widget.controller.text,
tag.tag,
text,
adjustedTag,
);
_search();
},
Expand Down