Merge pull request #655 from Schnitzel5/feature/update-category-filter

added option to exclude categories from mass update
This commit is contained in:
Moustapha Kodjo Amadou 2026-01-31 14:55:19 +01:00 committed by GitHub
commit 5727ab497c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 114 additions and 5 deletions

View file

@ -10,6 +10,7 @@ class Category {
bool? forManga;
int? pos;
bool? hide;
bool? shouldUpdate;
@enumerated
late ItemType forItemType;
int? updatedAt;
@ -20,6 +21,7 @@ class Category {
required this.forItemType,
this.pos,
this.hide,
this.shouldUpdate,
this.updatedAt = 0,
});
@ -29,6 +31,7 @@ class Category {
forItemType = ItemType.values[json['forItemType'] ?? 0];
pos = json['pos'];
hide = json['hide'];
shouldUpdate = json['shouldUpdate'];
updatedAt = json['updatedAt'];
}
@ -48,6 +51,7 @@ class Category {
'forItemType': forItemType.index,
'pos': pos,
'hide': hide,
'shouldUpdate': shouldUpdate,
'updatedAt': updatedAt ?? 0,
};
}

View file

@ -27,8 +27,13 @@ const CategorySchema = CollectionSchema(
r'hide': PropertySchema(id: 2, name: r'hide', type: IsarType.bool),
r'name': PropertySchema(id: 3, name: r'name', type: IsarType.string),
r'pos': PropertySchema(id: 4, name: r'pos', type: IsarType.long),
r'updatedAt': PropertySchema(
r'shouldUpdate': PropertySchema(
id: 5,
name: r'shouldUpdate',
type: IsarType.bool,
),
r'updatedAt': PropertySchema(
id: 6,
name: r'updatedAt',
type: IsarType.long,
),
@ -75,7 +80,8 @@ void _categorySerialize(
writer.writeBool(offsets[2], object.hide);
writer.writeString(offsets[3], object.name);
writer.writeLong(offsets[4], object.pos);
writer.writeLong(offsets[5], object.updatedAt);
writer.writeBool(offsets[5], object.shouldUpdate);
writer.writeLong(offsets[6], object.updatedAt);
}
Category _categoryDeserialize(
@ -92,7 +98,8 @@ Category _categoryDeserialize(
id: id,
name: reader.readStringOrNull(offsets[3]),
pos: reader.readLongOrNull(offsets[4]),
updatedAt: reader.readLongOrNull(offsets[5]),
shouldUpdate: reader.readBoolOrNull(offsets[5]),
updatedAt: reader.readLongOrNull(offsets[6]),
);
object.forManga = reader.readBoolOrNull(offsets[1]);
return object;
@ -118,6 +125,8 @@ P _categoryDeserializeProp<P>(
case 4:
return (reader.readLongOrNull(offset)) as P;
case 5:
return (reader.readBoolOrNull(offset)) as P;
case 6:
return (reader.readLongOrNull(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@ -642,6 +651,33 @@ extension CategoryQueryFilter
});
}
QueryBuilder<Category, Category, QAfterFilterCondition> shouldUpdateIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(
const FilterCondition.isNull(property: r'shouldUpdate'),
);
});
}
QueryBuilder<Category, Category, QAfterFilterCondition>
shouldUpdateIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(
const FilterCondition.isNotNull(property: r'shouldUpdate'),
);
});
}
QueryBuilder<Category, Category, QAfterFilterCondition> shouldUpdateEqualTo(
bool? value,
) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(
FilterCondition.equalTo(property: r'shouldUpdate', value: value),
);
});
}
QueryBuilder<Category, Category, QAfterFilterCondition> updatedAtIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(
@ -785,6 +821,18 @@ extension CategoryQuerySortBy on QueryBuilder<Category, Category, QSortBy> {
});
}
QueryBuilder<Category, Category, QAfterSortBy> sortByShouldUpdate() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'shouldUpdate', Sort.asc);
});
}
QueryBuilder<Category, Category, QAfterSortBy> sortByShouldUpdateDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'shouldUpdate', Sort.desc);
});
}
QueryBuilder<Category, Category, QAfterSortBy> sortByUpdatedAt() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'updatedAt', Sort.asc);
@ -872,6 +920,18 @@ extension CategoryQuerySortThenBy
});
}
QueryBuilder<Category, Category, QAfterSortBy> thenByShouldUpdate() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'shouldUpdate', Sort.asc);
});
}
QueryBuilder<Category, Category, QAfterSortBy> thenByShouldUpdateDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'shouldUpdate', Sort.desc);
});
}
QueryBuilder<Category, Category, QAfterSortBy> thenByUpdatedAt() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'updatedAt', Sort.asc);
@ -919,6 +979,12 @@ extension CategoryQueryWhereDistinct
});
}
QueryBuilder<Category, Category, QDistinct> distinctByShouldUpdate() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'shouldUpdate');
});
}
QueryBuilder<Category, Category, QDistinct> distinctByUpdatedAt() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'updatedAt');
@ -964,6 +1030,12 @@ extension CategoryQueryProperty
});
}
QueryBuilder<Category, bool?, QQueryOperations> shouldUpdateProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'shouldUpdate');
});
}
QueryBuilder<Category, int?, QQueryOperations> updatedAtProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'updatedAt');

View file

@ -414,6 +414,23 @@ class _CategoriesTabState extends ConsumerState<CategoriesTab>
icon: const Icon(Icons.mode_edit_outline_outlined),
),
SizedBox(width: 10),
IconButton(
onPressed: () async {
await isar.writeTxn(() async {
category.shouldUpdate =
!(category.shouldUpdate ?? false);
category.updatedAt =
DateTime.now().millisecondsSinceEpoch;
isar.categorys.put(category);
});
},
icon: Icon(
category.shouldUpdate ?? true
? Icons.update_outlined
: Icons.update_disabled_outlined,
),
),
SizedBox(width: 10),
IconButton(
onPressed: () async {
await isar.writeTxn(() async {

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/category.dart';
import 'package:mangayomi/models/changed.dart';
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
import 'package:mangayomi/modules/widgets/base_library_tab_screen.dart';
@ -100,6 +101,12 @@ class _UpdatesScreenState extends BaseLibraryTabScreenState<UpdatesScreen> {
Future<void> _updateLibrary() async {
setState(() => _isLoading = true);
final itemType = getCurrentItemType();
final allowedCategories = isar.categorys
.filter()
.idIsNotNull()
.group((q) => q.shouldUpdateIsNull().or().shouldUpdateEqualTo(true))
.findAllSync()
.map((e) => e.id);
final mangaList = isar.mangas
.filter()
.idIsNotNull()
@ -108,7 +115,16 @@ class _UpdatesScreenState extends BaseLibraryTabScreenState<UpdatesScreen> {
.itemTypeEqualTo(itemType)
.and()
.isLocalArchiveEqualTo(false)
.findAllSync();
.findAllSync()
.where((e) {
for (final category in allowedCategories) {
if (e.categories?.contains(category) ?? false) {
return true;
}
}
return false;
})
.toList();
await updateLibrary(
ref: ref,
context: context,

View file

@ -66,7 +66,7 @@ final class GetHtmlContentProvider
}
}
String _$getHtmlContentHash() => r'dbce709ba154704c7e9d1465bdc21c926a42a723';
String _$getHtmlContentHash() => r'ef15133ac4066d556a03b42addf01be916e529bc';
final class GetHtmlContentFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<(String, EpubNovel?)>, Chapter> {