Added a checkbox "ignoreFiltersOnSearch" to the library search, so when checked, the whole library will be searched, not just the filtered library (Downloaded, Unwatched/Unread, Started, Bookmarked)

+ added some comments
This commit is contained in:
Enbiya Olgun 2025-04-26 05:03:06 +02:00
parent 1f118184ba
commit 71a6358452
28 changed files with 213 additions and 125 deletions

View file

@ -8,6 +8,7 @@
"open_random_entry": "فتح مدخل عشوائي",
"import": "استيراد",
"filter": "مرشح",
"ignore_filters": "تجاهل مرشح",
"downloaded": "تم التحميل",
"unread": "غير مقروء",
"started": "بدأ",

View file

@ -8,6 +8,7 @@
"open_random_entry": "Zufälligen Eintrag öffnen",
"import": "Importieren",
"filter": "Filter",
"ignore_filters": "Filter ignorieren",
"downloaded": "Heruntergeladen",
"unread": "Ungelesen",
"unwatched": "Nicht angeschaut",

View file

@ -8,6 +8,7 @@
"open_random_entry": "Open random entry",
"import": "Import",
"filter": "Filter",
"ignore_filters": "Ignore Filters",
"downloaded": "Downloaded",
"unread": "Unread",
"unwatched": "Unwatched",

View file

@ -8,6 +8,7 @@
"open_random_entry": "Abrir entrada aleatoria",
"import": "Importar",
"filter": "Filtrar",
"ignore_filters": "Ignorar filtros",
"downloaded": "Descargado",
"unread": "Sin leer",
"started": "Comenzado",

View file

@ -8,6 +8,7 @@
"open_random_entry": "Abrir entrada aleatoria",
"import": "Importar",
"filter": "Filtrar",
"ignore_filters": "Ignorar filtros",
"downloaded": "Descargado",
"unread": "Sin leer",
"started": "Comenzado",

View file

@ -8,6 +8,7 @@
"open_random_entry": "Ouvrir une entrée au hasard",
"import": "Importer",
"filter": "Filtre",
"ignore_filters": "Ignorer les filtres",
"downloaded": "Téléchargé",
"unread": "Non lus",
"started": "Commencé",

View file

@ -8,6 +8,7 @@
"open_random_entry": "Buka Entri Acak",
"import": "Impor",
"filter": "Filter",
"ignore_filters": "Abaikan filter",
"downloaded": "Telah Diunduh",
"unread": "Belum Dibaca",
"started": "Dimulai",

View file

@ -8,6 +8,7 @@
"open_random_entry": "Apri voce casuale",
"import": "Importa",
"filter": "Filtro",
"ignore_filters": "Ignora filtri",
"downloaded": "Scaricato",
"unread": "Non letto",
"started": "Iniziato",

View file

@ -8,6 +8,7 @@
"open_random_entry": "Abrir entrada aleatória",
"import": "Importar",
"filter": "Filtro",
"ignore_filters": "Ignorar filtros",
"downloaded": "Baixados",
"unread": "Não lidos",
"started": "Iniciados",

View file

@ -8,6 +8,7 @@
"open_random_entry": "Abrir entrada aleatória",
"import": "Importar",
"filter": "Filtro",
"ignore_filters": "Ignorar filtros",
"downloaded": "Baixado",
"unread": "Não lido",
"started": "Iniciado",

View file

@ -8,6 +8,7 @@
"open_random_entry": "Открыть случайную запись",
"import": "Импорт",
"filter": "Фильтр",
"ignore_filters": "Игнорировать фильтры",
"downloaded": "Загружено",
"unread": "Непрочитанное",
"started": "Начато",

View file

@ -8,6 +8,7 @@
"open_random_entry": "สุ่มอ่าน",
"import": "นำเข้า",
"filter": "ตัวกรอง",
"ignore_filters": "ไม่สนใจตัวกรอง",
"downloaded": "ดาวน์โหลดแล้ว",
"unread": "ยังไม่อ่าน",
"started": "เริ่มแล้ว",

View file

@ -8,6 +8,7 @@
"open_random_entry": "Rastgele Giriş Aç",
"import": "İçe Aktar",
"filter": "Filtre",
"ignore_filters": "Filtreleri yok say",
"downloaded": "İndirildi",
"unread": "Okunmamış",
"started": "Başladı",

View file

@ -8,6 +8,7 @@
"open_random_entry": "随机打开条目",
"import": "导入",
"filter": "筛选",
"ignore_filters": "忽略筛选",
"downloaded": "已下载",
"unread": "未读",
"started": "已开始",

View file

@ -165,6 +165,12 @@ abstract class AppLocalizations {
/// **'Filter'**
String get filter;
/// No description provided for @ignore_filters.
///
/// In en, this message translates to:
/// **'Ignore Filters'**
String get ignore_filters;
/// No description provided for @downloaded.
///
/// In en, this message translates to:

View file

@ -32,6 +32,9 @@ class AppLocalizationsAr extends AppLocalizations {
@override
String get filter => 'مرشح';
@override
String get ignore_filters => 'تجاهل مرشح';
@override
String get downloaded => 'تم التحميل';

View file

@ -32,6 +32,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get filter => 'Filter';
@override
String get ignore_filters => 'Filter ignorieren';
@override
String get downloaded => 'Heruntergeladen';

View file

@ -32,6 +32,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get filter => 'Filter';
@override
String get ignore_filters => 'Ignore Filters';
@override
String get downloaded => 'Downloaded';

View file

@ -32,6 +32,9 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get filter => 'Filtrar';
@override
String get ignore_filters => 'Ignorar filtros';
@override
String get downloaded => 'Descargado';
@ -1466,6 +1469,9 @@ class AppLocalizationsEs419 extends AppLocalizationsEs {
@override
String get filter => 'Filtrar';
@override
String get ignore_filters => 'Ignorar filtros';
@override
String get downloaded => 'Descargado';

View file

@ -32,6 +32,9 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get filter => 'Filtre';
@override
String get ignore_filters => 'Ignorer les filtres';
@override
String get downloaded => 'Téléchargé';

View file

@ -32,6 +32,9 @@ class AppLocalizationsId extends AppLocalizations {
@override
String get filter => 'Filter';
@override
String get ignore_filters => 'Abaikan filter';
@override
String get downloaded => 'Telah Diunduh';

View file

@ -32,6 +32,9 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get filter => 'Filtro';
@override
String get ignore_filters => 'Ignora filtri';
@override
String get downloaded => 'Scaricato';

View file

@ -32,6 +32,9 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get filter => 'Filtro';
@override
String get ignore_filters => 'Ignorar filtros';
@override
String get downloaded => 'Baixados';
@ -1466,6 +1469,9 @@ class AppLocalizationsPtBr extends AppLocalizationsPt {
@override
String get filter => 'Filtro';
@override
String get ignore_filters => 'Ignorar filtros';
@override
String get downloaded => 'Baixado';

View file

@ -32,6 +32,9 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get filter => 'Фильтр';
@override
String get ignore_filters => 'Игнорировать фильтры';
@override
String get downloaded => 'Загружено';

View file

@ -32,6 +32,9 @@ class AppLocalizationsTh extends AppLocalizations {
@override
String get filter => 'ตัวกรอง';
@override
String get ignore_filters => 'ไม่สนใจตัวกรอง';
@override
String get downloaded => 'ดาวน์โหลดแล้ว';

View file

@ -32,6 +32,9 @@ class AppLocalizationsTr extends AppLocalizations {
@override
String get filter => 'Filtre';
@override
String get ignore_filters => 'Filtreleri yok say';
@override
String get downloaded => 'İndirildi';

View file

@ -32,6 +32,9 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get filter => '筛选';
@override
String get ignore_filters => '忽略筛选';
@override
String get downloaded => '已下载';

View file

@ -1013,6 +1013,21 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
);
}
bool matchesSearchQuery(Manga manga, String query) {
final keywords = query
.toLowerCase()
.split(',')
.map((k) => k.trim())
.where((k) => k.isNotEmpty);
return keywords.any(
(keyword) =>
(manga.name?.toLowerCase().contains(keyword) ?? false) ||
(manga.source?.toLowerCase().contains(keyword) ?? false) ||
(manga.genre?.any((g) => g.toLowerCase().contains(keyword)) ?? false),
);
}
List<Manga> _filterAndSortManga({
required List<Manga> data,
required int downloadFilterType,
@ -1022,133 +1037,126 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required int sortType,
}) {
List<Manga>? mangas;
mangas =
data
.where((element) {
List list = [];
if (downloadFilterType == 1) {
for (var chap in element.chapters) {
final modelChapDownload =
isar.downloads.filter().idEqualTo(chap.id).findAllSync();
if (modelChapDownload.isNotEmpty &&
modelChapDownload.first.isDownload == true) {
list.add(true);
}
}
return list.isNotEmpty;
} else if (downloadFilterType == 2) {
for (var chap in element.chapters) {
final modelChapDownload =
isar.downloads.filter().idEqualTo(chap.id).findAllSync();
if (!(modelChapDownload.isNotEmpty &&
modelChapDownload.first.isDownload == true)) {
list.add(true);
}
}
return list.length == element.chapters.length;
}
return true;
})
.where((element) {
List list = [];
if (unreadFilterType == 1 || startedFilterType == 1) {
for (var chap in element.chapters) {
if (!chap.isRead!) {
list.add(true);
}
}
return list.isNotEmpty;
} else if (unreadFilterType == 2 || startedFilterType == 2) {
final searchQuery = _textEditingController.text;
// Skip all filters, just do search
if (searchQuery.isNotEmpty && ignoreFiltersOnSearch) {
mangas =
data
.where((element) => matchesSearchQuery(element, searchQuery))
.toList();
} else {
// Apply filters + search
mangas =
data
.where((element) {
// Filter by download
List list = [];
for (var chap in element.chapters) {
if (chap.isRead!) {
list.add(true);
}
}
return list.length == element.chapters.length;
}
return true;
})
.where((element) {
List list = [];
if (bookmarkedFilterType == 1) {
for (var chap in element.chapters) {
if (chap.isBookmarked!) {
list.add(true);
}
}
return list.isNotEmpty;
} else if (bookmarkedFilterType == 2) {
List list = [];
for (var chap in element.chapters) {
if (!chap.isBookmarked!) {
list.add(true);
}
}
return list.length == element.chapters.length;
}
return true;
})
.where(
(element) =>
_textEditingController.text.isNotEmpty
? _textEditingController.text
.split(",")
.any(
(keyword) =>
element.name!.toLowerCase().contains(
_textEditingController.text.toLowerCase(),
) ||
(element.source != null &&
element.source!.toLowerCase().contains(
_textEditingController.text.toLowerCase(),
)) ||
element.genre!.contains(keyword),
)
: true,
)
.toList();
if (downloadFilterType == 1) {
for (var chap in element.chapters) {
final modelChapDownload =
isar.downloads
.filter()
.idEqualTo(chap.id)
.findAllSync();
if (sortType == 0) {
mangas.sort((a, b) {
return a.name!.compareTo(b.name!);
});
} else if (sortType == 1) {
mangas.sort((a, b) {
return a.lastRead!.compareTo(b.lastRead!);
});
} else if (sortType == 2) {
mangas.sort((a, b) {
return a.lastUpdate?.compareTo(b.lastUpdate ?? 0) ?? 0;
});
} else if (sortType == 3) {
mangas.sort((a, b) {
return a.chapters
.where((element) => !element.isRead!)
.toList()
.length
.compareTo(
b.chapters.where((element) => !element.isRead!).toList().length,
);
});
} else if (sortType == 4) {
mangas.sort((a, b) {
return a.chapters.length.compareTo(b.chapters.length);
});
} else if (sortType == 5) {
mangas.sort((a, b) {
final aChaps = a.chapters;
final bChaps = b.chapters;
return (aChaps.lastOrNull?.dateUpload ?? "").compareTo(
bChaps.lastOrNull?.dateUpload ?? "",
);
});
} else if (sortType == 6) {
mangas.sort((a, b) {
return a.dateAdded?.compareTo(b.dateAdded ?? 0) ?? 0;
});
if (modelChapDownload.isNotEmpty &&
modelChapDownload.first.isDownload == true) {
list.add(true);
}
}
return list.isNotEmpty;
} else if (downloadFilterType == 2) {
for (var chap in element.chapters) {
final modelChapDownload =
isar.downloads
.filter()
.idEqualTo(chap.id)
.findAllSync();
if (!(modelChapDownload.isNotEmpty &&
modelChapDownload.first.isDownload == true)) {
list.add(true);
}
}
return list.length == element.chapters.length;
}
return true;
})
.where((element) {
// Filter by unread or started
List list = [];
if (unreadFilterType == 1 || startedFilterType == 1) {
for (var chap in element.chapters) {
if (!chap.isRead!) {
list.add(true);
}
}
return list.isNotEmpty;
} else if (unreadFilterType == 2 || startedFilterType == 2) {
List list = [];
for (var chap in element.chapters) {
if (chap.isRead!) {
list.add(true);
}
}
return list.length == element.chapters.length;
}
return true;
})
.where((element) {
// Filter by bookmarked
List list = [];
if (bookmarkedFilterType == 1) {
for (var chap in element.chapters) {
if (chap.isBookmarked!) {
list.add(true);
}
}
return list.isNotEmpty;
} else if (bookmarkedFilterType == 2) {
List list = [];
for (var chap in element.chapters) {
if (!chap.isBookmarked!) {
list.add(true);
}
}
return list.length == element.chapters.length;
}
return true;
})
.where(
(element) =>
searchQuery.isNotEmpty
? matchesSearchQuery(element, searchQuery)
: true,
)
.toList();
}
// Sorting the data based on selected sort type
mangas.sort((a, b) {
switch (sortType) {
case 0:
return a.name!.compareTo(b.name!);
case 1:
return a.lastRead!.compareTo(b.lastRead!);
case 2:
return a.lastUpdate?.compareTo(b.lastUpdate ?? 0) ?? 0;
case 3:
return a.chapters
.where((e) => !e.isRead!)
.length
.compareTo(b.chapters.where((e) => !e.isRead!).length);
case 4:
return a.chapters.length.compareTo(b.chapters.length);
case 5:
return (a.chapters.lastOrNull?.dateUpload ?? "").compareTo(
b.chapters.lastOrNull?.dateUpload ?? "",
);
case 6:
return a.dateAdded?.compareTo(b.dateAdded ?? 0) ?? 0;
default:
return 0;
}
});
return mangas;
}
@ -1188,7 +1196,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
);
final entries =
data.where((e) => !(e.hide ?? false)).toList();
data
.where((e) => !(e.hide ?? false))
.toList();
if (entries.isEmpty) {
return Text(l10n.library_no_category_exist);
}
@ -2043,6 +2053,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
return l10n.date_added;
}
bool ignoreFiltersOnSearch = false;
PreferredSize _appBar(
bool isNotFiltering,
bool showNumbersOfItems,
@ -2202,6 +2213,21 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
},
icon: const Icon(Icons.search),
),
if (_isSearch)
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(l10n.ignore_filters),
Checkbox(
value: ignoreFiltersOnSearch,
onChanged: (val) {
setState(() {
ignoreFiltersOnSearch = val ?? false;
});
},
),
],
),
IconButton(
splashRadius: 20,
onPressed: () {