rename feed to update and make some arrangements

This commit is contained in:
kodjomoustapha 2024-09-17 10:37:40 +01:00
parent bb1423969d
commit ee9e2a76cb
18 changed files with 663 additions and 637 deletions

View file

@ -3,7 +3,6 @@
"library": "Library",
"updates": "Updates",
"history": "History",
"feed": "Feed",
"browse": "Browse",
"more": "More",
"open_random_entry": "Open random entry",
@ -40,7 +39,7 @@
"no_recent_updates": "No recent updates",
"remove_everything": "Remove everything",
"remove_everything_msg": "Are you sure? All history will be lost",
"remove_all_feed_msg": "Are you sure? The whole feed will be cleared",
"remove_all_update_msg": "Are you sure? The whole update will be cleared",
"ok": "OK",
"cancel": "Cancel",
"remove": "Remove",

View file

@ -1,10 +1,10 @@
import 'package:isar/isar.dart';
import 'package:mangayomi/models/chapter.dart';
part 'feed.g.dart';
part 'update.g.dart';
@collection
@Name("Feed")
class Feed {
@Name("Update")
class Update {
Id? id;
int? mangaId;
@ -15,14 +15,14 @@ class Feed {
String? date;
Feed({
Update({
this.id = Isar.autoIncrement,
required this.mangaId,
required this.chapterName,
required this.date,
});
Feed.fromJson(Map<String, dynamic> json) {
Update.fromJson(Map<String, dynamic> json) {
id = json['id'];
mangaId = json['mangaId'];
chapterName = json['chapterName'];

View file

@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'feed.dart';
part of 'update.dart';
// **************************************************************************
// IsarCollectionGenerator
@ -9,13 +9,13 @@ part of 'feed.dart';
// coverage:ignore-file
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
extension GetFeedCollection on Isar {
IsarCollection<Feed> get feeds => this.collection();
extension GetUpdateCollection on Isar {
IsarCollection<Update> get updates => this.collection();
}
const FeedSchema = CollectionSchema(
name: r'Feed',
id: 8879644747771893978,
const UpdateSchema = CollectionSchema(
name: r'Update',
id: -8192355249181452821,
properties: {
r'chapterName': PropertySchema(
id: 0,
@ -33,29 +33,29 @@ const FeedSchema = CollectionSchema(
type: IsarType.long,
)
},
estimateSize: _feedEstimateSize,
serialize: _feedSerialize,
deserialize: _feedDeserialize,
deserializeProp: _feedDeserializeProp,
estimateSize: _updateEstimateSize,
serialize: _updateSerialize,
deserialize: _updateDeserialize,
deserializeProp: _updateDeserializeProp,
idName: r'id',
indexes: {},
links: {
r'chapter': LinkSchema(
id: 8037684855892205613,
id: -7524967726288995715,
name: r'chapter',
target: r'Chapter',
single: true,
)
},
embeddedSchemas: {},
getId: _feedGetId,
getLinks: _feedGetLinks,
attach: _feedAttach,
getId: _updateGetId,
getLinks: _updateGetLinks,
attach: _updateAttach,
version: '3.1.0+1',
);
int _feedEstimateSize(
Feed object,
int _updateEstimateSize(
Update object,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
@ -75,8 +75,8 @@ int _feedEstimateSize(
return bytesCount;
}
void _feedSerialize(
Feed object,
void _updateSerialize(
Update object,
IsarWriter writer,
List<int> offsets,
Map<Type, List<int>> allOffsets,
@ -86,13 +86,13 @@ void _feedSerialize(
writer.writeLong(offsets[2], object.mangaId);
}
Feed _feedDeserialize(
Update _updateDeserialize(
Id id,
IsarReader reader,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
final object = Feed(
final object = Update(
chapterName: reader.readStringOrNull(offsets[0]),
date: reader.readStringOrNull(offsets[1]),
id: id,
@ -101,7 +101,7 @@ Feed _feedDeserialize(
return object;
}
P _feedDeserializeProp<P>(
P _updateDeserializeProp<P>(
IsarReader reader,
int propertyId,
int offset,
@ -119,29 +119,29 @@ P _feedDeserializeProp<P>(
}
}
Id _feedGetId(Feed object) {
Id _updateGetId(Update object) {
return object.id ?? Isar.autoIncrement;
}
List<IsarLinkBase<dynamic>> _feedGetLinks(Feed object) {
List<IsarLinkBase<dynamic>> _updateGetLinks(Update object) {
return [object.chapter];
}
void _feedAttach(IsarCollection<dynamic> col, Id id, Feed object) {
void _updateAttach(IsarCollection<dynamic> col, Id id, Update object) {
object.id = id;
object.chapter.attach(col, col.isar.collection<Chapter>(), r'chapter', id);
}
extension FeedQueryWhereSort on QueryBuilder<Feed, Feed, QWhere> {
QueryBuilder<Feed, Feed, QAfterWhere> anyId() {
extension UpdateQueryWhereSort on QueryBuilder<Update, Update, QWhere> {
QueryBuilder<Update, Update, QAfterWhere> anyId() {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(const IdWhereClause.any());
});
}
}
extension FeedQueryWhere on QueryBuilder<Feed, Feed, QWhereClause> {
QueryBuilder<Feed, Feed, QAfterWhereClause> idEqualTo(Id id) {
extension UpdateQueryWhere on QueryBuilder<Update, Update, QWhereClause> {
QueryBuilder<Update, Update, QAfterWhereClause> idEqualTo(Id id) {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(IdWhereClause.between(
lower: id,
@ -150,7 +150,7 @@ extension FeedQueryWhere on QueryBuilder<Feed, Feed, QWhereClause> {
});
}
QueryBuilder<Feed, Feed, QAfterWhereClause> idNotEqualTo(Id id) {
QueryBuilder<Update, Update, QAfterWhereClause> idNotEqualTo(Id id) {
return QueryBuilder.apply(this, (query) {
if (query.whereSort == Sort.asc) {
return query
@ -172,7 +172,7 @@ extension FeedQueryWhere on QueryBuilder<Feed, Feed, QWhereClause> {
});
}
QueryBuilder<Feed, Feed, QAfterWhereClause> idGreaterThan(Id id,
QueryBuilder<Update, Update, QAfterWhereClause> idGreaterThan(Id id,
{bool include = false}) {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(
@ -181,7 +181,7 @@ extension FeedQueryWhere on QueryBuilder<Feed, Feed, QWhereClause> {
});
}
QueryBuilder<Feed, Feed, QAfterWhereClause> idLessThan(Id id,
QueryBuilder<Update, Update, QAfterWhereClause> idLessThan(Id id,
{bool include = false}) {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(
@ -190,7 +190,7 @@ extension FeedQueryWhere on QueryBuilder<Feed, Feed, QWhereClause> {
});
}
QueryBuilder<Feed, Feed, QAfterWhereClause> idBetween(
QueryBuilder<Update, Update, QAfterWhereClause> idBetween(
Id lowerId,
Id upperId, {
bool includeLower = true,
@ -207,8 +207,8 @@ extension FeedQueryWhere on QueryBuilder<Feed, Feed, QWhereClause> {
}
}
extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterNameIsNull() {
extension UpdateQueryFilter on QueryBuilder<Update, Update, QFilterCondition> {
QueryBuilder<Update, Update, QAfterFilterCondition> chapterNameIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'chapterName',
@ -216,7 +216,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterNameIsNotNull() {
QueryBuilder<Update, Update, QAfterFilterCondition> chapterNameIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'chapterName',
@ -224,7 +224,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterNameEqualTo(
QueryBuilder<Update, Update, QAfterFilterCondition> chapterNameEqualTo(
String? value, {
bool caseSensitive = true,
}) {
@ -237,7 +237,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterNameGreaterThan(
QueryBuilder<Update, Update, QAfterFilterCondition> chapterNameGreaterThan(
String? value, {
bool include = false,
bool caseSensitive = true,
@ -252,7 +252,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterNameLessThan(
QueryBuilder<Update, Update, QAfterFilterCondition> chapterNameLessThan(
String? value, {
bool include = false,
bool caseSensitive = true,
@ -267,7 +267,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterNameBetween(
QueryBuilder<Update, Update, QAfterFilterCondition> chapterNameBetween(
String? lower,
String? upper, {
bool includeLower = true,
@ -286,7 +286,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterNameStartsWith(
QueryBuilder<Update, Update, QAfterFilterCondition> chapterNameStartsWith(
String value, {
bool caseSensitive = true,
}) {
@ -299,7 +299,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterNameEndsWith(
QueryBuilder<Update, Update, QAfterFilterCondition> chapterNameEndsWith(
String value, {
bool caseSensitive = true,
}) {
@ -312,7 +312,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterNameContains(
QueryBuilder<Update, Update, QAfterFilterCondition> chapterNameContains(
String value,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
@ -324,7 +324,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterNameMatches(
QueryBuilder<Update, Update, QAfterFilterCondition> chapterNameMatches(
String pattern,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
@ -336,7 +336,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterNameIsEmpty() {
QueryBuilder<Update, Update, QAfterFilterCondition> chapterNameIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'chapterName',
@ -345,7 +345,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterNameIsNotEmpty() {
QueryBuilder<Update, Update, QAfterFilterCondition> chapterNameIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'chapterName',
@ -354,7 +354,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> dateIsNull() {
QueryBuilder<Update, Update, QAfterFilterCondition> dateIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'date',
@ -362,7 +362,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> dateIsNotNull() {
QueryBuilder<Update, Update, QAfterFilterCondition> dateIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'date',
@ -370,7 +370,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> dateEqualTo(
QueryBuilder<Update, Update, QAfterFilterCondition> dateEqualTo(
String? value, {
bool caseSensitive = true,
}) {
@ -383,7 +383,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> dateGreaterThan(
QueryBuilder<Update, Update, QAfterFilterCondition> dateGreaterThan(
String? value, {
bool include = false,
bool caseSensitive = true,
@ -398,7 +398,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> dateLessThan(
QueryBuilder<Update, Update, QAfterFilterCondition> dateLessThan(
String? value, {
bool include = false,
bool caseSensitive = true,
@ -413,7 +413,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> dateBetween(
QueryBuilder<Update, Update, QAfterFilterCondition> dateBetween(
String? lower,
String? upper, {
bool includeLower = true,
@ -432,7 +432,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> dateStartsWith(
QueryBuilder<Update, Update, QAfterFilterCondition> dateStartsWith(
String value, {
bool caseSensitive = true,
}) {
@ -445,7 +445,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> dateEndsWith(
QueryBuilder<Update, Update, QAfterFilterCondition> dateEndsWith(
String value, {
bool caseSensitive = true,
}) {
@ -458,7 +458,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> dateContains(String value,
QueryBuilder<Update, Update, QAfterFilterCondition> dateContains(String value,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
@ -469,7 +469,8 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> dateMatches(String pattern,
QueryBuilder<Update, Update, QAfterFilterCondition> dateMatches(
String pattern,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
@ -480,7 +481,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> dateIsEmpty() {
QueryBuilder<Update, Update, QAfterFilterCondition> dateIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'date',
@ -489,7 +490,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> dateIsNotEmpty() {
QueryBuilder<Update, Update, QAfterFilterCondition> dateIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'date',
@ -498,7 +499,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> idIsNull() {
QueryBuilder<Update, Update, QAfterFilterCondition> idIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'id',
@ -506,7 +507,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> idIsNotNull() {
QueryBuilder<Update, Update, QAfterFilterCondition> idIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'id',
@ -514,7 +515,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> idEqualTo(Id? value) {
QueryBuilder<Update, Update, QAfterFilterCondition> idEqualTo(Id? value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'id',
@ -523,7 +524,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> idGreaterThan(
QueryBuilder<Update, Update, QAfterFilterCondition> idGreaterThan(
Id? value, {
bool include = false,
}) {
@ -536,7 +537,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> idLessThan(
QueryBuilder<Update, Update, QAfterFilterCondition> idLessThan(
Id? value, {
bool include = false,
}) {
@ -549,7 +550,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> idBetween(
QueryBuilder<Update, Update, QAfterFilterCondition> idBetween(
Id? lower,
Id? upper, {
bool includeLower = true,
@ -566,7 +567,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> mangaIdIsNull() {
QueryBuilder<Update, Update, QAfterFilterCondition> mangaIdIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'mangaId',
@ -574,7 +575,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> mangaIdIsNotNull() {
QueryBuilder<Update, Update, QAfterFilterCondition> mangaIdIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'mangaId',
@ -582,7 +583,8 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> mangaIdEqualTo(int? value) {
QueryBuilder<Update, Update, QAfterFilterCondition> mangaIdEqualTo(
int? value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'mangaId',
@ -591,7 +593,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> mangaIdGreaterThan(
QueryBuilder<Update, Update, QAfterFilterCondition> mangaIdGreaterThan(
int? value, {
bool include = false,
}) {
@ -604,7 +606,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> mangaIdLessThan(
QueryBuilder<Update, Update, QAfterFilterCondition> mangaIdLessThan(
int? value, {
bool include = false,
}) {
@ -617,7 +619,7 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> mangaIdBetween(
QueryBuilder<Update, Update, QAfterFilterCondition> mangaIdBetween(
int? lower,
int? upper, {
bool includeLower = true,
@ -635,153 +637,153 @@ extension FeedQueryFilter on QueryBuilder<Feed, Feed, QFilterCondition> {
}
}
extension FeedQueryObject on QueryBuilder<Feed, Feed, QFilterCondition> {}
extension UpdateQueryObject on QueryBuilder<Update, Update, QFilterCondition> {}
extension FeedQueryLinks on QueryBuilder<Feed, Feed, QFilterCondition> {
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapter(
extension UpdateQueryLinks on QueryBuilder<Update, Update, QFilterCondition> {
QueryBuilder<Update, Update, QAfterFilterCondition> chapter(
FilterQuery<Chapter> q) {
return QueryBuilder.apply(this, (query) {
return query.link(q, r'chapter');
});
}
QueryBuilder<Feed, Feed, QAfterFilterCondition> chapterIsNull() {
QueryBuilder<Update, Update, QAfterFilterCondition> chapterIsNull() {
return QueryBuilder.apply(this, (query) {
return query.linkLength(r'chapter', 0, true, 0, true);
});
}
}
extension FeedQuerySortBy on QueryBuilder<Feed, Feed, QSortBy> {
QueryBuilder<Feed, Feed, QAfterSortBy> sortByChapterName() {
extension UpdateQuerySortBy on QueryBuilder<Update, Update, QSortBy> {
QueryBuilder<Update, Update, QAfterSortBy> sortByChapterName() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'chapterName', Sort.asc);
});
}
QueryBuilder<Feed, Feed, QAfterSortBy> sortByChapterNameDesc() {
QueryBuilder<Update, Update, QAfterSortBy> sortByChapterNameDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'chapterName', Sort.desc);
});
}
QueryBuilder<Feed, Feed, QAfterSortBy> sortByDate() {
QueryBuilder<Update, Update, QAfterSortBy> sortByDate() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'date', Sort.asc);
});
}
QueryBuilder<Feed, Feed, QAfterSortBy> sortByDateDesc() {
QueryBuilder<Update, Update, QAfterSortBy> sortByDateDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'date', Sort.desc);
});
}
QueryBuilder<Feed, Feed, QAfterSortBy> sortByMangaId() {
QueryBuilder<Update, Update, QAfterSortBy> sortByMangaId() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'mangaId', Sort.asc);
});
}
QueryBuilder<Feed, Feed, QAfterSortBy> sortByMangaIdDesc() {
QueryBuilder<Update, Update, QAfterSortBy> sortByMangaIdDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'mangaId', Sort.desc);
});
}
}
extension FeedQuerySortThenBy on QueryBuilder<Feed, Feed, QSortThenBy> {
QueryBuilder<Feed, Feed, QAfterSortBy> thenByChapterName() {
extension UpdateQuerySortThenBy on QueryBuilder<Update, Update, QSortThenBy> {
QueryBuilder<Update, Update, QAfterSortBy> thenByChapterName() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'chapterName', Sort.asc);
});
}
QueryBuilder<Feed, Feed, QAfterSortBy> thenByChapterNameDesc() {
QueryBuilder<Update, Update, QAfterSortBy> thenByChapterNameDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'chapterName', Sort.desc);
});
}
QueryBuilder<Feed, Feed, QAfterSortBy> thenByDate() {
QueryBuilder<Update, Update, QAfterSortBy> thenByDate() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'date', Sort.asc);
});
}
QueryBuilder<Feed, Feed, QAfterSortBy> thenByDateDesc() {
QueryBuilder<Update, Update, QAfterSortBy> thenByDateDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'date', Sort.desc);
});
}
QueryBuilder<Feed, Feed, QAfterSortBy> thenById() {
QueryBuilder<Update, Update, QAfterSortBy> thenById() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'id', Sort.asc);
});
}
QueryBuilder<Feed, Feed, QAfterSortBy> thenByIdDesc() {
QueryBuilder<Update, Update, QAfterSortBy> thenByIdDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'id', Sort.desc);
});
}
QueryBuilder<Feed, Feed, QAfterSortBy> thenByMangaId() {
QueryBuilder<Update, Update, QAfterSortBy> thenByMangaId() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'mangaId', Sort.asc);
});
}
QueryBuilder<Feed, Feed, QAfterSortBy> thenByMangaIdDesc() {
QueryBuilder<Update, Update, QAfterSortBy> thenByMangaIdDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'mangaId', Sort.desc);
});
}
}
extension FeedQueryWhereDistinct on QueryBuilder<Feed, Feed, QDistinct> {
QueryBuilder<Feed, Feed, QDistinct> distinctByChapterName(
extension UpdateQueryWhereDistinct on QueryBuilder<Update, Update, QDistinct> {
QueryBuilder<Update, Update, QDistinct> distinctByChapterName(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'chapterName', caseSensitive: caseSensitive);
});
}
QueryBuilder<Feed, Feed, QDistinct> distinctByDate(
QueryBuilder<Update, Update, QDistinct> distinctByDate(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'date', caseSensitive: caseSensitive);
});
}
QueryBuilder<Feed, Feed, QDistinct> distinctByMangaId() {
QueryBuilder<Update, Update, QDistinct> distinctByMangaId() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'mangaId');
});
}
}
extension FeedQueryProperty on QueryBuilder<Feed, Feed, QQueryProperty> {
QueryBuilder<Feed, int, QQueryOperations> idProperty() {
extension UpdateQueryProperty on QueryBuilder<Update, Update, QQueryProperty> {
QueryBuilder<Update, int, QQueryOperations> idProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'id');
});
}
QueryBuilder<Feed, String?, QQueryOperations> chapterNameProperty() {
QueryBuilder<Update, String?, QQueryOperations> chapterNameProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'chapterName');
});
}
QueryBuilder<Feed, String?, QQueryOperations> dateProperty() {
QueryBuilder<Update, String?, QQueryOperations> dateProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'date');
});
}
QueryBuilder<Feed, int?, QQueryOperations> mangaIdProperty() {
QueryBuilder<Update, int?, QQueryOperations> mangaIdProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'mangaId');
});

View file

@ -1,262 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:grouped_list/sliver_grouped_list.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/feed.dart';
import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/modules/feed/widgets/feed_chapter_list_tile_widget.dart';
import 'package:mangayomi/modules/history/providers/isar_providers.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/date.dart';
import 'package:mangayomi/modules/library/widgets/search_text_form_field.dart';
import 'package:mangayomi/modules/widgets/error_text.dart';
import 'package:mangayomi/modules/widgets/progress_center.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
class FeedScreen extends ConsumerStatefulWidget {
const FeedScreen({super.key});
@override
ConsumerState<FeedScreen> createState() => _FeedScreenState();
}
class _FeedScreenState extends ConsumerState<FeedScreen>
with TickerProviderStateMixin {
late TabController _tabBarController;
@override
void initState() {
_tabBarController = TabController(length: 2, vsync: this);
_tabBarController.animateTo(0);
_tabBarController.addListener(() {
setState(() {
_textEditingController.clear();
_isSearch = false;
});
});
super.initState();
}
final _textEditingController = TextEditingController();
bool _isSearch = false;
List<History> entriesData = [];
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
return DefaultTabController(
animationDuration: Duration.zero,
length: 2,
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
title: _isSearch
? null
: Text(
l10n.feed,
style: TextStyle(color: Theme.of(context).hintColor),
),
actions: [
_isSearch
? SeachFormTextField(
onChanged: (value) {
setState(() {});
},
onSuffixPressed: () {
_textEditingController.clear();
setState(() {});
},
onPressed: () {
setState(() {
_isSearch = false;
});
_textEditingController.clear();
},
controller: _textEditingController,
)
: IconButton(
splashRadius: 20,
onPressed: () {
setState(() {
_isSearch = true;
});
},
icon:
Icon(Icons.search, color: Theme.of(context).hintColor)),
IconButton(
splashRadius: 20,
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(
l10n.remove_everything,
),
content: Text(l10n.remove_all_feed_msg),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
TextButton(
onPressed: () {
List<Feed> feeds = isar.feeds
.filter()
.idIsNotNull()
.chapter((q) => q.manga((q) =>
q.isMangaEqualTo(
_tabBarController.index ==
0)))
.findAllSync()
.toList();
isar.writeTxnSync(() {
for (var feed in feeds) {
isar.feeds.deleteSync(feed.id!);
}
});
if (mounted) {
Navigator.pop(context);
}
},
child: Text(l10n.ok)),
],
)
],
);
});
},
icon: Icon(Icons.delete_sweep_outlined,
color: Theme.of(context).hintColor)),
],
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
controller: _tabBarController,
tabs: [
Tab(text: l10n.manga),
Tab(text: l10n.anime),
],
),
),
body: Padding(
padding: const EdgeInsets.only(top: 10),
child: TabBarView(controller: _tabBarController, children: [
FeedTab(
isManga: true,
query: _textEditingController.text,
),
FeedTab(
isManga: false,
query: _textEditingController.text,
)
]),
),
),
);
}
}
class FeedTab extends ConsumerStatefulWidget {
final String query;
final bool isManga;
const FeedTab({required this.isManga, required this.query, super.key});
@override
ConsumerState<FeedTab> createState() => _FeedTabState();
}
class _FeedTabState extends ConsumerState<FeedTab> {
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
final feed = ref.watch(getAllFeedStreamProvider(isManga: widget.isManga));
return Scaffold(
body: feed.when(
data: (data) {
final entries = data
.where((element) => widget.query.isNotEmpty
? element.chapter.value!.manga.value!.name!
.toLowerCase()
.contains(widget.query.toLowerCase())
: true)
.toList();
final lastUpdatedList =
data.map((e) => e.chapter.value!.manga.value!.lastUpdate!).toList();
lastUpdatedList.sort((a, b) => a.compareTo(b));
final lastUpdated = lastUpdatedList.firstOrNull;
if (entries.isNotEmpty) {
return CustomScrollView(
slivers: [
if (lastUpdated != null)
SliverPadding(
padding: const EdgeInsets.only(
left: 10, right: 10, top: 10, bottom: 20),
sliver: SliverList(
delegate: SliverChildListDelegate.fixed([
Text(
l10n.library_last_updated(dateFormat(
lastUpdated.toString(),
ref: ref,
context: context,
showHOURorMINUTE: true)),
style: TextStyle(
fontStyle: FontStyle.italic,
color: context.secondaryColor))
])),
),
SliverGroupedListView<Feed, String>(
elements: entries,
groupBy: (element) => dateFormat(element.date!,
context: context,
ref: ref,
forHistoryValue: true,
useRelativeTimesTamps: false),
groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(bottom: 8, left: 12),
child: Row(
children: [
Text(dateFormat(
null,
context: context,
stringDate: groupByValue,
ref: ref,
)),
],
),
),
itemBuilder: (context, Feed element) {
final chapter = element.chapter.value!;
return FeedChapterListTileWidget(
chapter: chapter, sourceExist: true);
},
itemComparator: (item1, item2) =>
item1.date!.compareTo(item2.date!),
order: GroupedListOrder.DESC,
),
],
);
}
return Center(
child: Text(l10n.no_recent_updates),
);
},
error: (Object error, StackTrace stackTrace) {
return ErrorText(error);
},
loading: () {
return const ProgressCenter();
},
));
}
}

View file

@ -1,7 +1,7 @@
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/feed.dart';
import 'package:mangayomi/models/update.dart';
import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
@ -19,9 +19,9 @@ Stream<List<History>> getAllHistoryStream(GetAllHistoryStreamRef ref,
}
@riverpod
Stream<List<Feed>> getAllFeedStream(GetAllFeedStreamRef ref,
Stream<List<Update>> getAllUpdateStream(GetAllUpdateStreamRef ref,
{required bool isManga}) async* {
yield* isar.feeds
yield* isar.updates
.filter()
.idIsNotNull()
.and()

View file

@ -158,29 +158,30 @@ class _GetAllHistoryStreamProviderElement
bool get isManga => (origin as GetAllHistoryStreamProvider).isManga;
}
String _$getAllFeedStreamHash() => r'3d60bca5377bf6fc2aee36e7bec5b319b2377add';
String _$getAllUpdateStreamHash() =>
r'9f62b36ef0b268ee8c3cc93a10f8963def8dfbb0';
/// See also [getAllFeedStream].
@ProviderFor(getAllFeedStream)
const getAllFeedStreamProvider = GetAllFeedStreamFamily();
/// See also [getAllUpdateStream].
@ProviderFor(getAllUpdateStream)
const getAllUpdateStreamProvider = GetAllUpdateStreamFamily();
/// See also [getAllFeedStream].
class GetAllFeedStreamFamily extends Family<AsyncValue<List<Feed>>> {
/// See also [getAllFeedStream].
const GetAllFeedStreamFamily();
/// See also [getAllUpdateStream].
class GetAllUpdateStreamFamily extends Family<AsyncValue<List<Update>>> {
/// See also [getAllUpdateStream].
const GetAllUpdateStreamFamily();
/// See also [getAllFeedStream].
GetAllFeedStreamProvider call({
/// See also [getAllUpdateStream].
GetAllUpdateStreamProvider call({
required bool isManga,
}) {
return GetAllFeedStreamProvider(
return GetAllUpdateStreamProvider(
isManga: isManga,
);
}
@override
GetAllFeedStreamProvider getProviderOverride(
covariant GetAllFeedStreamProvider provider,
GetAllUpdateStreamProvider getProviderOverride(
covariant GetAllUpdateStreamProvider provider,
) {
return call(
isManga: provider.isManga,
@ -199,32 +200,33 @@ class GetAllFeedStreamFamily extends Family<AsyncValue<List<Feed>>> {
_allTransitiveDependencies;
@override
String? get name => r'getAllFeedStreamProvider';
String? get name => r'getAllUpdateStreamProvider';
}
/// See also [getAllFeedStream].
class GetAllFeedStreamProvider extends AutoDisposeStreamProvider<List<Feed>> {
/// See also [getAllFeedStream].
GetAllFeedStreamProvider({
/// See also [getAllUpdateStream].
class GetAllUpdateStreamProvider
extends AutoDisposeStreamProvider<List<Update>> {
/// See also [getAllUpdateStream].
GetAllUpdateStreamProvider({
required bool isManga,
}) : this._internal(
(ref) => getAllFeedStream(
ref as GetAllFeedStreamRef,
(ref) => getAllUpdateStream(
ref as GetAllUpdateStreamRef,
isManga: isManga,
),
from: getAllFeedStreamProvider,
name: r'getAllFeedStreamProvider',
from: getAllUpdateStreamProvider,
name: r'getAllUpdateStreamProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$getAllFeedStreamHash,
dependencies: GetAllFeedStreamFamily._dependencies,
: _$getAllUpdateStreamHash,
dependencies: GetAllUpdateStreamFamily._dependencies,
allTransitiveDependencies:
GetAllFeedStreamFamily._allTransitiveDependencies,
GetAllUpdateStreamFamily._allTransitiveDependencies,
isManga: isManga,
);
GetAllFeedStreamProvider._internal(
GetAllUpdateStreamProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
@ -238,12 +240,12 @@ class GetAllFeedStreamProvider extends AutoDisposeStreamProvider<List<Feed>> {
@override
Override overrideWith(
Stream<List<Feed>> Function(GetAllFeedStreamRef provider) create,
Stream<List<Update>> Function(GetAllUpdateStreamRef provider) create,
) {
return ProviderOverride(
origin: this,
override: GetAllFeedStreamProvider._internal(
(ref) => create(ref as GetAllFeedStreamRef),
override: GetAllUpdateStreamProvider._internal(
(ref) => create(ref as GetAllUpdateStreamRef),
from: from,
name: null,
dependencies: null,
@ -255,13 +257,13 @@ class GetAllFeedStreamProvider extends AutoDisposeStreamProvider<List<Feed>> {
}
@override
AutoDisposeStreamProviderElement<List<Feed>> createElement() {
return _GetAllFeedStreamProviderElement(this);
AutoDisposeStreamProviderElement<List<Update>> createElement() {
return _GetAllUpdateStreamProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is GetAllFeedStreamProvider && other.isManga == isManga;
return other is GetAllUpdateStreamProvider && other.isManga == isManga;
}
@override
@ -273,18 +275,18 @@ class GetAllFeedStreamProvider extends AutoDisposeStreamProvider<List<Feed>> {
}
}
mixin GetAllFeedStreamRef on AutoDisposeStreamProviderRef<List<Feed>> {
mixin GetAllUpdateStreamRef on AutoDisposeStreamProviderRef<List<Update>> {
/// The parameter `isManga` of this provider.
bool get isManga;
}
class _GetAllFeedStreamProviderElement
extends AutoDisposeStreamProviderElement<List<Feed>>
with GetAllFeedStreamRef {
_GetAllFeedStreamProviderElement(super.provider);
class _GetAllUpdateStreamProviderElement
extends AutoDisposeStreamProviderElement<List<Update>>
with GetAllUpdateStreamRef {
_GetAllUpdateStreamProviderElement(super.provider);
@override
bool get isManga => (origin as GetAllFeedStreamProvider).isManga;
bool get isManga => (origin as GetAllUpdateStreamProvider).isManga;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View file

@ -16,7 +16,7 @@ import 'package:mangayomi/models/download.dart';
import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/models/feed.dart';
import 'package:mangayomi/models/update.dart';
import 'package:mangayomi/modules/library/providers/add_torrent.dart';
import 'package:mangayomi/modules/library/providers/local_archive.dart';
import 'package:mangayomi/modules/manga/detail/providers/update_manga_detail_providers.dart';
@ -59,26 +59,21 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
botToast(context.l10n.updating_library,
fontSize: 13, second: 1600, alignY: 0.8);
int numbers = 0;
try {
for (var manga in mangaList) {
ref
.watch(updateMangaDetailProvider(mangaId: manga.id, isInit: false)
.future)
.then((value) {
numbers++;
});
}
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
if (mangaList.length == numbers) {
return false;
}
return true;
});
BotToast.cleanAll();
} catch (e) {
BotToast.cleanAll();
for (var manga in mangaList) {
try {
await ref.read(
updateMangaDetailProvider(mangaId: manga.id, isInit: false).future);
} catch (_) {}
numbers++;
}
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
if (mangaList.length == numbers) {
return false;
}
return true;
});
BotToast.cleanAll();
}
@override
@ -1165,7 +1160,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
.notifier)
.addUpdatedChapter(
chapter, true, false);
isar.feeds
isar.updates
.filter()
.mangaIdEqualTo(chapter.mangaId)
.chapterNameEqualTo(chapter.name)

View file

@ -5,7 +5,7 @@ import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/feed.dart';
import 'package:mangayomi/models/update.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/widgets/loading_icon.dart';
import 'package:mangayomi/services/fetch_anime_sources.dart';
@ -42,11 +42,10 @@ class MainScreen extends ConsumerWidget {
bool isReadingScreen =
location == '/mangareaderview' || location == '/animePlayerView';
int currentIndex = switch (location) {
null => 0,
'/MangaLibrary' => 0,
null || '/MangaLibrary' => 0,
'/AnimeLibrary' => 1,
'/history' => 2,
'/feed' => 3,
'/updates' => 2,
'/history' => 3,
'/browse' => 4,
_ => 5,
};
@ -98,7 +97,7 @@ class MainScreen extends ConsumerWidget {
!= '/MangaLibrary' &&
!= '/AnimeLibrary' &&
!= '/history' &&
!= '/feed' &&
!= '/updates' &&
!= '/browse' &&
!= '/more' =>
0,
@ -113,103 +112,112 @@ class MainScreen extends ConsumerWidget {
borderRadius:
BorderRadius.circular(30)),
),
child: NavigationRail(
labelType: NavigationRailLabelType.all,
useIndicator: true,
destinations: [
NavigationRailDestination(
selectedIcon: const Icon(
Icons.collections_bookmark),
icon: const Icon(Icons
.collections_bookmark_outlined),
label: Padding(
padding:
const EdgeInsets.only(top: 5),
child: Text(l10n.manga))),
NavigationRailDestination(
selectedIcon: const Icon(
Icons.video_collection),
icon: const Icon(
Icons.video_collection_outlined),
label: Padding(
padding:
const EdgeInsets.only(top: 5),
child: Text(l10n.anime))),
NavigationRailDestination(
selectedIcon:
const Icon(Icons.history),
icon: const Icon(
Icons.history_outlined),
label: Padding(
padding:
const EdgeInsets.only(top: 5),
child: Text(l10n.history))),
NavigationRailDestination(
selectedIcon: Stack(
children: [
const Icon(Icons.rss_feed),
Positioned(
right: 0,
top: 0,
child: _feedTotalNumbers(
ref, false))
],
),
icon: Stack(
children: [
const Icon(
Icons.rss_feed_outlined),
Positioned(
right: 0,
top: 0,
child: _feedTotalNumbers(
ref, false))
],
),
label: Padding(
padding:
const EdgeInsets.only(top: 5),
child: Stack(
children: [
Text(l10n.feed),
],
))),
NavigationRailDestination(
selectedIcon:
const Icon(Icons.explore),
icon: const Icon(
Icons.explore_outlined),
label: Padding(
padding:
const EdgeInsets.only(top: 5),
child: Text(l10n.browse))),
NavigationRailDestination(
selectedIcon:
const Icon(Icons.more_horiz),
icon: const Icon(
Icons.more_horiz_outlined),
label: Padding(
padding:
const EdgeInsets.only(top: 5),
child: Text(l10n.more))),
],
selectedIndex: currentIndex,
onDestinationSelected: (newIndex) {
if (newIndex == 0) {
route.go('/MangaLibrary');
} else if (newIndex == 1) {
route.go('/AnimeLibrary');
} else if (newIndex == 2) {
route.go('/history');
} else if (newIndex == 3) {
route.go('/feed');
} else if (newIndex == 4) {
route.go('/browse');
} else if (newIndex == 5) {
route.go('/more');
}
},
),
child: Builder(builder: (context) {
final updatesTotalNumbersWidget = Positioned(
right: 0,
top: 0,
child: _updatesTotalNumbers(ref, false));
final extensionUpdateTotalNumbersWidget =
Positioned(
right: 0,
top: 0,
child: _extensionUpdateTotalNumbers(
ref));
return NavigationRail(
labelType: NavigationRailLabelType.all,
useIndicator: true,
destinations: [
NavigationRailDestination(
selectedIcon: const Icon(
Icons.collections_bookmark),
icon: const Icon(Icons
.collections_bookmark_outlined),
label: Padding(
padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.manga))),
NavigationRailDestination(
selectedIcon: const Icon(
Icons.video_collection),
icon: const Icon(Icons
.video_collection_outlined),
label: Padding(
padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.anime))),
NavigationRailDestination(
selectedIcon: Stack(
children: [
const Icon(Icons.new_releases),
updatesTotalNumbersWidget
],
),
icon: Stack(
children: [
const Icon(Icons
.new_releases_outlined),
updatesTotalNumbersWidget
],
),
label: Padding(
padding: const EdgeInsets.only(
top: 5),
child: Stack(
children: [
Text(l10n.updates),
],
))),
NavigationRailDestination(
selectedIcon:
const Icon(Icons.history),
icon: const Icon(
Icons.history_outlined),
label: Padding(
padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.history))),
NavigationRailDestination(
selectedIcon: Stack(
children: [
const Icon(Icons.explore),
extensionUpdateTotalNumbersWidget
],
),
icon: Stack(
children: [
const Icon(
Icons.explore_outlined),
extensionUpdateTotalNumbersWidget
],
),
label: Padding(
padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.browse))),
NavigationRailDestination(
selectedIcon:
const Icon(Icons.more_horiz),
icon: const Icon(
Icons.more_horiz_outlined),
label: Padding(
padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.more))),
],
selectedIndex: currentIndex,
onDestinationSelected: (newIndex) {
final fn = switch (newIndex) {
0 => route.go('/MangaLibrary'),
1 => route.go('/AnimeLibrary'),
2 => route.go('/updates'),
3 => route.go('/history'),
4 => route.go('/browse'),
_ => route.go('/more'),
};
fn;
},
);
}),
),
Positioned(
right: 18,
@ -234,7 +242,7 @@ class MainScreen extends ConsumerWidget {
!= '/MangaLibrary' &&
!= '/AnimeLibrary' &&
!= '/history' &&
!= '/feed' &&
!= '/updates' &&
!= '/browse' &&
!= '/more' =>
0,
@ -263,22 +271,24 @@ class MainScreen extends ConsumerWidget {
icon: const Icon(
Icons.video_collection_outlined),
label: l10n.anime),
Stack(
children: [
NavigationDestination(
selectedIcon:
const Icon(Icons.new_releases),
icon: const Icon(
Icons.new_releases_outlined),
label: l10n.updates),
Positioned(
right: 14,
top: 3,
child: _updatesTotalNumbers(ref, true)),
],
),
NavigationDestination(
selectedIcon: const Icon(Icons.history),
icon: const Icon(Icons.history_outlined),
label: l10n.history),
Stack(
children: [
NavigationDestination(
selectedIcon: const Icon(Icons.rss_feed),
icon: const Icon(Icons.rss_feed_outlined),
label: l10n.feed),
Positioned(
right: 14,
top: 3,
child: _feedTotalNumbers(ref, true)),
],
),
Stack(
children: [
NavigationDestination(
@ -297,19 +307,15 @@ class MainScreen extends ConsumerWidget {
label: l10n.more),
],
onDestinationSelected: (newIndex) {
if (newIndex == 0) {
route.go('/MangaLibrary');
} else if (newIndex == 1) {
route.go('/AnimeLibrary');
} else if (newIndex == 2) {
route.go('/history');
} else if (newIndex == 3) {
route.go('/feed');
} else if (newIndex == 4) {
route.go('/browse');
} else if (newIndex == 5) {
route.go('/more');
}
final fn = switch (newIndex) {
0 => route.go('/MangaLibrary'),
1 => route.go('/AnimeLibrary'),
2 => route.go('/updates'),
3 => route.go('/history'),
4 => route.go('/browse'),
_ => route.go('/more'),
};
fn;
},
),
),
@ -366,9 +372,9 @@ Widget _extensionUpdateTotalNumbers(WidgetRef ref) {
});
}
Widget _feedTotalNumbers(WidgetRef ref, bool mobile) {
Widget _updatesTotalNumbers(WidgetRef ref, bool mobile) {
return StreamBuilder(
stream: isar.feeds.filter().idIsNotNull().watch(fireImmediately: true),
stream: isar.updates.filter().idIsNotNull().watch(fireImmediately: true),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final entries = snapshot.data!.where((element) {

View file

@ -2,7 +2,7 @@ import 'package:mangayomi/eval/dart/model/m_bridge.dart';
import 'package:mangayomi/eval/dart/model/m_manga.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/feed.dart';
import 'package:mangayomi/models/update.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
import 'package:mangayomi/services/get_detail.dart';
@ -85,13 +85,13 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
isar.chapters.putSync(chap);
chap.manga.saveSync();
if (manga.chapters.isNotEmpty) {
final feed = Feed(
final update = Update(
mangaId: mangaId,
chapterName: chap.name,
date: DateTime.now().millisecondsSinceEpoch.toString())
..chapter.value = chap;
isar.feeds.putSync(feed);
feed.chapter.saveSync();
isar.updates.putSync(update);
update.chapter.saveSync();
}
}
}

View file

@ -6,7 +6,7 @@ part of 'update_manga_detail_providers.dart';
// RiverpodGenerator
// **************************************************************************
String _$updateMangaDetailHash() => r'f72eb5e66fd9fb7ed61aa08365e068d77737438d';
String _$updateMangaDetailHash() => r'736b68c65f624da85b15c0a7a2a263aab8e8df7e';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -9,7 +9,7 @@ import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/category.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/download.dart';
import 'package:mangayomi/models/feed.dart';
import 'package:mangayomi/models/update.dart';
import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
@ -61,8 +61,8 @@ void doRestore(DoRestoreRef ref,
final extensionsPref = (backup["extensions_preferences"] as List?)
?.map((e) => SourcePreference.fromJson(e))
.toList();
final feeds =
(backup["feeds"] as List?)?.map((e) => Feed.fromJson(e)).toList();
final updates =
(backup["updates"] as List?)?.map((e) => Update.fromJson(e)).toList();
isar.writeTxnSync(() {
isar.mangas.clearSync();
@ -100,19 +100,19 @@ void doRestore(DoRestoreRef ref,
}
}
isar.feeds.clearSync();
if (feeds != null) {
isar.updates.clearSync();
if (updates != null) {
final tempChapters =
isar.chapters.filter().idIsNotNull().findAllSync().toList();
for (var feed in feeds) {
for (var update in updates) {
final matchingChapter = tempChapters
.where((chapter) =>
chapter.mangaId == feed.mangaId &&
chapter.name == feed.chapterName)
chapter.mangaId == update.mangaId &&
chapter.name == update.chapterName)
.firstOrNull;
if (matchingChapter != null) {
isar.feeds.putSync(feed..chapter.value = matchingChapter);
feed.chapter.saveSync();
isar.updates.putSync(update..chapter.value = matchingChapter);
update.chapter.saveSync();
}
}
}

View file

@ -6,7 +6,7 @@ part of 'restore.dart';
// RiverpodGenerator
// **************************************************************************
String _$doRestoreHash() => r'823b26bade20d89ae7b7b56a7eb7c25020795b45';
String _$doRestoreHash() => r'69153ba0467229d219346aab9e6ec87c52f66095';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -1,30 +1,324 @@
import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/material.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:grouped_list/sliver_grouped_list.dart';
class UpdatesScreen extends StatelessWidget {
import 'package:isar/isar.dart';
import 'package:mangayomi/eval/dart/model/m_bridge.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/update.dart';
import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/modules/manga/detail/providers/update_manga_detail_providers.dart';
import 'package:mangayomi/modules/updates/widgets/update_chapter_list_tile_widget.dart';
import 'package:mangayomi/modules/history/providers/isar_providers.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/date.dart';
import 'package:mangayomi/modules/library/widgets/search_text_form_field.dart';
import 'package:mangayomi/modules/widgets/error_text.dart';
import 'package:mangayomi/modules/widgets/progress_center.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
class UpdatesScreen extends ConsumerStatefulWidget {
const UpdatesScreen({super.key});
@override
ConsumerState<UpdatesScreen> createState() => _UpdatesScreenState();
}
class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
with TickerProviderStateMixin {
late TabController _tabBarController;
bool _isLoading = false;
Future<void> _updateLibrary() async {
setState(() {
_isLoading = true;
});
botToast(context.l10n.updating_library,
fontSize: 13, second: 1600, alignY: 0.8);
final mangaList =
isar.mangas.filter().idIsNotNull().favoriteEqualTo(true).findAllSync();
int numbers = 0;
for (var manga in mangaList) {
try {
await ref.read(
updateMangaDetailProvider(mangaId: manga.id, isInit: false).future);
} catch (_) {}
numbers++;
}
await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1));
if (mangaList.length == numbers) {
return false;
}
return true;
});
BotToast.cleanAll();
setState(() {
_isLoading = false;
});
}
@override
void initState() {
_tabBarController = TabController(length: 2, vsync: this);
_tabBarController.animateTo(0);
_tabBarController.addListener(() {
setState(() {
_textEditingController.clear();
_isSearch = false;
});
});
super.initState();
}
final _textEditingController = TextEditingController();
bool _isSearch = false;
List<History> entriesData = [];
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context);
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
title: Text(
l10n!.updates,
style: TextStyle(color: Theme.of(context).hintColor),
final l10n = l10nLocalizations(context)!;
return DefaultTabController(
animationDuration: Duration.zero,
length: 2,
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
title: _isSearch
? null
: Text(
l10n.updates,
style: TextStyle(color: Theme.of(context).hintColor),
),
actions: [
_isSearch
? SeachFormTextField(
onChanged: (value) {
setState(() {});
},
onSuffixPressed: () {
_textEditingController.clear();
setState(() {});
},
onPressed: () {
setState(() {
_isSearch = false;
});
_textEditingController.clear();
},
controller: _textEditingController,
)
: IconButton(
splashRadius: 20,
onPressed: () {
setState(() {
_isSearch = true;
});
},
icon: Icon(Icons.search_outlined,
color: Theme.of(context).hintColor)),
IconButton(
splashRadius: 20,
onPressed: () {
_updateLibrary();
},
icon: Icon(Icons.refresh_outlined,
color: Theme.of(context).hintColor)),
IconButton(
splashRadius: 20,
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(
l10n.remove_everything,
),
content: Text(l10n.remove_all_update_msg),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
TextButton(
onPressed: () {
List<Update> updates = isar.updates
.filter()
.idIsNotNull()
.chapter((q) => q.manga((q) =>
q.isMangaEqualTo(
_tabBarController.index ==
0)))
.findAllSync()
.toList();
isar.writeTxnSync(() {
for (var update in updates) {
isar.updates.deleteSync(update.id!);
}
});
if (mounted) {
Navigator.pop(context);
}
},
child: Text(l10n.ok)),
],
)
],
);
});
},
icon: Icon(Icons.delete_sweep_outlined,
color: Theme.of(context).hintColor)),
],
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
controller: _tabBarController,
tabs: [
Tab(text: l10n.manga),
Tab(text: l10n.anime),
],
),
),
body: Padding(
padding: const EdgeInsets.only(top: 10),
child: TabBarView(controller: _tabBarController, children: [
UpdateTab(
isManga: true,
query: _textEditingController.text,
isLoading: _isLoading),
UpdateTab(
isManga: false,
query: _textEditingController.text,
isLoading: _isLoading)
]),
),
actions: [
IconButton(
splashRadius: 20,
onPressed: () {},
icon: Icon(Icons.refresh, color: Theme.of(context).hintColor)),
],
),
body: Center(
child: Text(l10n.no_recent_updates),
),
);
}
}
class UpdateTab extends ConsumerStatefulWidget {
final String query;
final bool isManga;
final bool isLoading;
const UpdateTab(
{required this.isManga,
required this.query,
required this.isLoading,
super.key});
@override
ConsumerState<UpdateTab> createState() => _UpdateTabState();
}
class _UpdateTabState extends ConsumerState<UpdateTab> {
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
final update =
ref.watch(getAllUpdateStreamProvider(isManga: widget.isManga));
return Scaffold(
body: Stack(
children: [
update.when(
data: (data) {
final entries = data
.where((element) => widget.query.isNotEmpty
? element.chapter.value!.manga.value!.name!
.toLowerCase()
.contains(widget.query.toLowerCase())
: true)
.toList();
final lastUpdatedList = data
.map((e) => e.chapter.value!.manga.value!.lastUpdate!)
.toList();
lastUpdatedList.sort((a, b) => a.compareTo(b));
final lastUpdated = lastUpdatedList.firstOrNull;
if (entries.isNotEmpty) {
return CustomScrollView(
slivers: [
if (lastUpdated != null)
SliverPadding(
padding: const EdgeInsets.only(
left: 10, right: 10, top: 10, bottom: 20),
sliver: SliverList(
delegate: SliverChildListDelegate.fixed([
Text(
l10n.library_last_updated(dateFormat(
lastUpdated.toString(),
ref: ref,
context: context,
showHOURorMINUTE: true)),
style: TextStyle(
fontStyle: FontStyle.italic,
color: context.secondaryColor))
])),
),
SliverGroupedListView<Update, String>(
elements: entries,
groupBy: (element) => dateFormat(element.date!,
context: context,
ref: ref,
forHistoryValue: true,
useRelativeTimesTamps: false),
groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(bottom: 8, left: 12),
child: Row(
children: [
Text(dateFormat(
null,
context: context,
stringDate: groupByValue,
ref: ref,
)),
],
),
),
itemBuilder: (context, element) {
final chapter = element.chapter.value!;
return UpdateChapterListTileWidget(
chapter: chapter, sourceExist: true);
},
itemComparator: (item1, item2) =>
item1.date!.compareTo(item2.date!),
order: GroupedListOrder.DESC,
),
],
);
}
return Center(
child: Text(l10n.no_recent_updates),
);
},
error: (Object error, StackTrace stackTrace) {
return ErrorText(error);
},
loading: () {
return const ProgressCenter();
},
),
if (widget.isLoading)
const Positioned(
top: 0,
left: 0,
right: 0,
child: Padding(
padding: EdgeInsets.only(top: 40),
child: Center(
child: RefreshProgressIndicator(),
),
)),
],
));
}
}

View file

@ -10,10 +10,10 @@ import 'package:mangayomi/modules/manga/download/download_page_widget.dart';
import 'package:mangayomi/utils/extensions/chapter.dart';
import 'package:mangayomi/utils/headers.dart';
class FeedChapterListTileWidget extends ConsumerWidget {
class UpdateChapterListTileWidget extends ConsumerWidget {
final Chapter chapter;
final bool sourceExist;
const FeedChapterListTileWidget({
const UpdateChapterListTileWidget({
required this.chapter,
required this.sourceExist,
super.key,

View file

@ -7,7 +7,7 @@ import 'package:mangayomi/models/category.dart';
import 'package:mangayomi/models/changed_items.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/download.dart';
import 'package:mangayomi/models/feed.dart';
import 'package:mangayomi/models/update.dart';
import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
@ -132,7 +132,7 @@ class StorageProvider {
ChangedItemsSchema,
ChapterSchema,
CategorySchema,
FeedSchema,
UpdateSchema,
HistorySchema,
DownloadSchema,
SourceSchema,

View file

@ -10,7 +10,7 @@ import 'package:mangayomi/modules/browse/extension/edit_code.dart';
import 'package:mangayomi/modules/browse/extension/extension_detail.dart';
import 'package:mangayomi/modules/browse/extension/widgets/create_extension.dart';
import 'package:mangayomi/modules/browse/sources/sources_filter_screen.dart';
import 'package:mangayomi/modules/feed/feed_screen.dart';
import 'package:mangayomi/modules/updates/updates_screen.dart';
import 'package:mangayomi/modules/more/backup_and_restore/backup_and_restore.dart';
import 'package:mangayomi/modules/more/categories/categories_screen.dart';
import 'package:mangayomi/modules/more/settings/downloads/downloads_screen.dart';
@ -19,7 +19,6 @@ import 'package:mangayomi/modules/more/settings/sync/sync.dart';
import 'package:mangayomi/modules/more/settings/track/track.dart';
import 'package:mangayomi/modules/more/settings/track/manage_trackers/manage_trackers.dart';
import 'package:mangayomi/modules/more/settings/track/manage_trackers/tracking_detail.dart';
import 'package:mangayomi/modules/updates/updates_screen.dart';
import 'package:mangayomi/modules/webview/webview.dart';
import 'package:mangayomi/modules/browse/browse_screen.dart';
import 'package:mangayomi/modules/browse/extension/extension_lang.dart';
@ -117,12 +116,12 @@ class RouterNotifier extends ChangeNotifier {
),
),
GoRoute(
name: "feed",
path: '/feed',
builder: (context, state) => const FeedScreen(),
name: "updates",
path: '/updates',
builder: (context, state) => const UpdatesScreen(),
pageBuilder: (context, state) => transitionPage(
key: state.pageKey,
child: const FeedScreen(),
child: const UpdatesScreen(),
),
),
GoRoute(
@ -144,15 +143,6 @@ class RouterNotifier extends ChangeNotifier {
),
),
]),
GoRoute(
name: "updates",
path: '/updates',
builder: (context, state) => const UpdatesScreen(),
pageBuilder: (context, state) => transitionPage(
key: state.pageKey,
child: const UpdatesScreen(),
),
),
GoRoute(
path: "/mangaHome",
name: "mangaHome",

View file

@ -4,7 +4,7 @@ import 'package:mangayomi/eval/dart/model/m_bridge.dart';
import 'package:mangayomi/eval/dart/model/source_preference.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/changed_items.dart';
import 'package:mangayomi/models/feed.dart';
import 'package:mangayomi/models/update.dart';
import 'package:mangayomi/models/sync_preference.dart';
import 'package:mangayomi/models/track.dart';
import 'package:mangayomi/models/manga.dart';
@ -206,7 +206,7 @@ class SyncServer extends _$SyncServer {
datas["chapters"] = data["chapters"];
datas["tracks"] = data["tracks"];
datas["history"] = data["history"];
datas["feeds"] = data["feeds"];
datas["updates"] = data["updates"];
var encodedJson = jsonEncode(datas);
return sha256.convert(utf8.encode(encodedJson)).toString();
}
@ -296,13 +296,13 @@ class SyncServer extends _$SyncServer {
.map((e) => e.toJson())
.toList();
datas.addAll({"extensions_preferences": sourcePreferences});
final feeds = isar.feeds
final updates = isar.updates
.filter()
.idIsNotNull()
.findAllSync()
.map((e) => e.toJson())
.toList();
datas.addAll({"feeds": feeds});
datas.addAll({"updates": updates});
return datas;
}
@ -322,8 +322,8 @@ class SyncServer extends _$SyncServer {
final history = (backup["history"] as List?)
?.map((e) => History.fromJson(e))
.toList();
final feeds =
(backup["feeds"] as List?)?.map((e) => Feed.fromJson(e)).toList();
final updates =
(backup["updates"] as List?)?.map((e) => Update.fromJson(e)).toList();
isar.writeTxnSync(() {
isar.mangas.clearSync();
@ -350,19 +350,19 @@ class SyncServer extends _$SyncServer {
}
}
isar.feeds.clearSync();
if (feeds != null) {
isar.updates.clearSync();
if (updates != null) {
final tempChapters =
isar.chapters.filter().idIsNotNull().findAllSync().toList();
for (var feed in feeds) {
for (var update in updates) {
final matchingChapter = tempChapters
.where((chapter) =>
chapter.mangaId == feed.mangaId &&
chapter.name == feed.chapterName)
chapter.mangaId == update.mangaId &&
chapter.name == update.chapterName)
.firstOrNull;
if (matchingChapter != null) {
isar.feeds.putSync(feed..chapter.value = matchingChapter);
feed.chapter.saveSync();
isar.updates.putSync(update..chapter.value = matchingChapter);
update.chapter.saveSync();
}
}
}
@ -416,8 +416,8 @@ class SyncServer extends _$SyncServer {
final extensionsPref = (backup["extensions_preferences"] as List?)
?.map((e) => SourcePreference.fromJson(e))
.toList();
final feeds =
(backup["feeds"] as List?)?.map((e) => Feed.fromJson(e)).toList();
final updates =
(backup["updates"] as List?)?.map((e) => Update.fromJson(e)).toList();
isar.writeTxnSync(() {
isar.mangas.clearSync();
@ -444,19 +444,19 @@ class SyncServer extends _$SyncServer {
}
}
isar.feeds.clearSync();
if (feeds != null) {
isar.updates.clearSync();
if (updates != null) {
final tempChapters =
isar.chapters.filter().idIsNotNull().findAllSync().toList();
for (var feed in feeds) {
for (var update in updates) {
final matchingChapter = tempChapters
.where((chapter) =>
chapter.mangaId == feed.mangaId &&
chapter.name == feed.chapterName)
chapter.mangaId == update.mangaId &&
chapter.name == update.chapterName)
.firstOrNull;
if (matchingChapter != null) {
isar.feeds.putSync(feed..chapter.value = matchingChapter);
feed.chapter.saveSync();
isar.updates.putSync(update..chapter.value = matchingChapter);
update.chapter.saveSync();
}
}
}

View file

@ -6,7 +6,7 @@ part of 'sync_server.dart';
// RiverpodGenerator
// **************************************************************************
String _$syncServerHash() => r'e019e8870184d25f7a2659e35f6c3969bc683b50';
String _$syncServerHash() => r'0f4a07754abea35efb563ba8471b47d1c8854058';
/// Copied from Dart SDK
class _SystemHash {