Merge branch 'feature/novel' into feature/light-novel

This commit is contained in:
Schnitzel5 2024-12-20 15:59:06 +01:00
commit 34179a17a5
78 changed files with 4546 additions and 1124 deletions

View file

@ -99,6 +99,13 @@ class $MProvider extends MProvider with $Bridge<MProvider> {
BridgeParameter('url', BridgeParameter('url',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
])), ])),
'getHtmlContent': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.future, [BridgeTypeRef(CoreTypes.string)])),
params: [
BridgeParameter('url',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
])),
'getFilterList': BridgeMethodDef(BridgeFunctionDef( 'getFilterList': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef( returns: BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])), CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])),
@ -1140,6 +1147,10 @@ class $MProvider extends MProvider with $Bridge<MProvider> {
return list.map((e) => (e is $Value ? e.$reified : e) as Video).toList(); return list.map((e) => (e is $Value ? e.$reified : e) as Video).toList();
} }
@override
Future<String> getHtmlContent(String url) async =>
await $_invoke('getHtmlContent', [$String(url)]);
@override @override
Map<String, String> get headers { Map<String, String> get headers {
try { try {

View file

@ -115,6 +115,11 @@ class DartExtensionService implements ExtensionService {
return await _executeLib().getVideoList(url); return await _executeLib().getVideoList(url);
} }
@override
Future<String> getHtmlContent(String url) async {
return await _executeLib().getHtmlContent(url);
}
@override @override
FilterList getFilterList() { FilterList getFilterList() {
List<dynamic> list; List<dynamic> list;

View file

@ -29,6 +29,8 @@ abstract interface class ExtensionService {
Future<List<Video>> getVideoList(String url); Future<List<Video>> getVideoList(String url);
Future<String> getHtmlContent(String url);
FilterList getFilterList(); FilterList getFilterList();
List<SourcePreference> getSourcePreferences(); List<SourcePreference> getSourcePreferences();

View file

@ -60,6 +60,9 @@ class MProvider {
async getVideoList(url) { async getVideoList(url) {
throw new Error("getVideoList not implemented"); throw new Error("getVideoList not implemented");
} }
async getHtmlContent(url) {
throw new Error("getHtmlContent not implemented");
}
getFilterList() { getFilterList() {
throw new Error("getFilterList not implemented"); throw new Error("getFilterList not implemented");
} }
@ -135,6 +138,15 @@ var extention = new DefaultExtension();
.toList(); .toList();
} }
@override
Future<String> getHtmlContent(String url) async {
_init();
final res = (await runtime.handlePromise(await runtime.evaluateAsync(
'jsonStringify(() => extention.getHtmlContent(`$url`))')))
.stringResult;
return res;
}
@override @override
FilterList getFilterList() { FilterList getFilterList() {
List<dynamic> list; List<dynamic> list;

View file

@ -24,6 +24,8 @@ abstract class MProvider {
Future<List<Video>> getVideoList(String url); Future<List<Video>> getVideoList(String url);
Future<String> getHtmlContent(String url);
List<dynamic> getFilterList(); List<dynamic> getFilterList();
List<dynamic> getSourcePreferences(); List<dynamic> getSourcePreferences();

View file

@ -223,6 +223,7 @@
"anime_sources": "Anime-Quellen", "anime_sources": "Anime-Quellen",
"anime_extensions": "Anime-Erweiterungen", "anime_extensions": "Anime-Erweiterungen",
"manga_extensions": "Manga-Erweiterungen", "manga_extensions": "Manga-Erweiterungen",
"novel": "Novel",
"anime": "Anime", "anime": "Anime",
"manga": "Manga", "manga": "Manga",
"library_no_category_exist": "Du hast noch keine Kategorien", "library_no_category_exist": "Du hast noch keine Kategorien",

View file

@ -221,10 +221,13 @@
"n_episodes": "{n} episodes", "n_episodes": "{n} episodes",
"manga_sources": "Manga Sources", "manga_sources": "Manga Sources",
"anime_sources": "Anime Sources", "anime_sources": "Anime Sources",
"novel_sources": "Novel Sources",
"anime_extensions": "Anime Extensions", "anime_extensions": "Anime Extensions",
"manga_extensions": "Manga Extensions", "manga_extensions": "Manga Extensions",
"novel_extensions": "Novel Extensions",
"anime": "Anime", "anime": "Anime",
"manga": "Manga", "manga": "Manga",
"novel": "Novel",
"library_no_category_exist": "You don't have any categories yet", "library_no_category_exist": "You don't have any categories yet",
"watching": "Watching", "watching": "Watching",
"plan_to_watch": "Plan to watch", "plan_to_watch": "Plan to watch",

View file

@ -1,4 +1,5 @@
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/models/manga.dart';
part 'category.g.dart'; part 'category.g.dart';
@collection @collection
@ -6,18 +7,19 @@ part 'category.g.dart';
class Category { class Category {
Id? id; Id? id;
String? name; String? name;
bool? forManga; @enumerated
late ItemType forItemType;
Category( Category(
{this.id = Isar.autoIncrement, {this.id = Isar.autoIncrement,
required this.name, required this.name,
required this.forManga}); required this.forItemType});
Category.fromJson(Map<String, dynamic> json) { Category.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
name = json['name']; name = json['name'];
forManga = json['forManga']; forItemType = json['forItemType'];
} }
Map<String, dynamic> toJson() => Map<String, dynamic> toJson() =>
{'id': id, 'name': name, 'forManga': forManga}; {'id': id, 'name': name, 'forItemType': forItemType};
} }

View file

@ -17,10 +17,11 @@ const CategorySchema = CollectionSchema(
name: r'Category', name: r'Category',
id: 5751694338128944171, id: 5751694338128944171,
properties: { properties: {
r'forManga': PropertySchema( r'forItemType': PropertySchema(
id: 0, id: 0,
name: r'forManga', name: r'forItemType',
type: IsarType.bool, type: IsarType.byte,
enumMap: _CategoryforItemTypeEnumValueMap,
), ),
r'name': PropertySchema( r'name': PropertySchema(
id: 1, id: 1,
@ -63,7 +64,7 @@ void _categorySerialize(
List<int> offsets, List<int> offsets,
Map<Type, List<int>> allOffsets, Map<Type, List<int>> allOffsets,
) { ) {
writer.writeBool(offsets[0], object.forManga); writer.writeByte(offsets[0], object.forItemType.index);
writer.writeString(offsets[1], object.name); writer.writeString(offsets[1], object.name);
} }
@ -74,7 +75,9 @@ Category _categoryDeserialize(
Map<Type, List<int>> allOffsets, Map<Type, List<int>> allOffsets,
) { ) {
final object = Category( final object = Category(
forManga: reader.readBoolOrNull(offsets[0]), forItemType:
_CategoryforItemTypeValueEnumMap[reader.readByteOrNull(offsets[0])] ??
ItemType.manga,
id: id, id: id,
name: reader.readStringOrNull(offsets[1]), name: reader.readStringOrNull(offsets[1]),
); );
@ -89,7 +92,8 @@ P _categoryDeserializeProp<P>(
) { ) {
switch (propertyId) { switch (propertyId) {
case 0: case 0:
return (reader.readBoolOrNull(offset)) as P; return (_CategoryforItemTypeValueEnumMap[reader.readByteOrNull(offset)] ??
ItemType.manga) as P;
case 1: case 1:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
default: default:
@ -97,6 +101,17 @@ P _categoryDeserializeProp<P>(
} }
} }
const _CategoryforItemTypeEnumValueMap = {
'manga': 0,
'anime': 1,
'novel': 2,
};
const _CategoryforItemTypeValueEnumMap = {
0: ItemType.manga,
1: ItemType.anime,
2: ItemType.novel,
};
Id _categoryGetId(Category object) { Id _categoryGetId(Category object) {
return object.id ?? Isar.autoIncrement; return object.id ?? Isar.autoIncrement;
} }
@ -186,32 +201,60 @@ extension CategoryQueryWhere on QueryBuilder<Category, Category, QWhereClause> {
extension CategoryQueryFilter extension CategoryQueryFilter
on QueryBuilder<Category, Category, QFilterCondition> { on QueryBuilder<Category, Category, QFilterCondition> {
QueryBuilder<Category, Category, QAfterFilterCondition> forMangaIsNull() { QueryBuilder<Category, Category, QAfterFilterCondition> forItemTypeEqualTo(
return QueryBuilder.apply(this, (query) { ItemType value) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'forManga',
));
});
}
QueryBuilder<Category, Category, QAfterFilterCondition> forMangaIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'forManga',
));
});
}
QueryBuilder<Category, Category, QAfterFilterCondition> forMangaEqualTo(
bool? value) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo( return query.addFilterCondition(FilterCondition.equalTo(
property: r'forManga', property: r'forItemType',
value: value, value: value,
)); ));
}); });
} }
QueryBuilder<Category, Category, QAfterFilterCondition>
forItemTypeGreaterThan(
ItemType value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'forItemType',
value: value,
));
});
}
QueryBuilder<Category, Category, QAfterFilterCondition> forItemTypeLessThan(
ItemType value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'forItemType',
value: value,
));
});
}
QueryBuilder<Category, Category, QAfterFilterCondition> forItemTypeBetween(
ItemType lower,
ItemType upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'forItemType',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
QueryBuilder<Category, Category, QAfterFilterCondition> idIsNull() { QueryBuilder<Category, Category, QAfterFilterCondition> idIsNull() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull( return query.addFilterCondition(const FilterCondition.isNull(
@ -434,15 +477,15 @@ extension CategoryQueryLinks
on QueryBuilder<Category, Category, QFilterCondition> {} on QueryBuilder<Category, Category, QFilterCondition> {}
extension CategoryQuerySortBy on QueryBuilder<Category, Category, QSortBy> { extension CategoryQuerySortBy on QueryBuilder<Category, Category, QSortBy> {
QueryBuilder<Category, Category, QAfterSortBy> sortByForManga() { QueryBuilder<Category, Category, QAfterSortBy> sortByForItemType() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'forManga', Sort.asc); return query.addSortBy(r'forItemType', Sort.asc);
}); });
} }
QueryBuilder<Category, Category, QAfterSortBy> sortByForMangaDesc() { QueryBuilder<Category, Category, QAfterSortBy> sortByForItemTypeDesc() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'forManga', Sort.desc); return query.addSortBy(r'forItemType', Sort.desc);
}); });
} }
@ -461,15 +504,15 @@ extension CategoryQuerySortBy on QueryBuilder<Category, Category, QSortBy> {
extension CategoryQuerySortThenBy extension CategoryQuerySortThenBy
on QueryBuilder<Category, Category, QSortThenBy> { on QueryBuilder<Category, Category, QSortThenBy> {
QueryBuilder<Category, Category, QAfterSortBy> thenByForManga() { QueryBuilder<Category, Category, QAfterSortBy> thenByForItemType() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'forManga', Sort.asc); return query.addSortBy(r'forItemType', Sort.asc);
}); });
} }
QueryBuilder<Category, Category, QAfterSortBy> thenByForMangaDesc() { QueryBuilder<Category, Category, QAfterSortBy> thenByForItemTypeDesc() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'forManga', Sort.desc); return query.addSortBy(r'forItemType', Sort.desc);
}); });
} }
@ -500,9 +543,9 @@ extension CategoryQuerySortThenBy
extension CategoryQueryWhereDistinct extension CategoryQueryWhereDistinct
on QueryBuilder<Category, Category, QDistinct> { on QueryBuilder<Category, Category, QDistinct> {
QueryBuilder<Category, Category, QDistinct> distinctByForManga() { QueryBuilder<Category, Category, QDistinct> distinctByForItemType() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'forManga'); return query.addDistinctBy(r'forItemType');
}); });
} }
@ -522,9 +565,9 @@ extension CategoryQueryProperty
}); });
} }
QueryBuilder<Category, bool?, QQueryOperations> forMangaProperty() { QueryBuilder<Category, ItemType, QQueryOperations> forItemTypeProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'forManga'); return query.addPropertyName(r'forItemType');
}); });
} }

View file

@ -1,5 +1,6 @@
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart';
part 'history.g.dart'; part 'history.g.dart';
@collection @collection
@ -11,7 +12,8 @@ class History {
int? chapterId; int? chapterId;
bool? isManga; @enumerated
late ItemType itemType;
final chapter = IsarLink<Chapter>(); final chapter = IsarLink<Chapter>();
@ -19,7 +21,7 @@ class History {
History({ History({
this.id = Isar.autoIncrement, this.id = Isar.autoIncrement,
required this.isManga, required this.itemType,
required this.chapterId, required this.chapterId,
required this.mangaId, required this.mangaId,
required this.date, required this.date,
@ -29,7 +31,7 @@ class History {
chapterId = json['chapterId']; chapterId = json['chapterId'];
date = json['date']; date = json['date'];
id = json['id']; id = json['id'];
isManga = json['isManga']; itemType = json['itemType'];
mangaId = json['mangaId']; mangaId = json['mangaId'];
} }
@ -37,7 +39,7 @@ class History {
'chapterId': chapterId, 'chapterId': chapterId,
'date': date, 'date': date,
'id': id, 'id': id,
'isManga': isManga, 'itemType': itemType,
'mangaId': mangaId 'mangaId': mangaId
}; };
} }

View file

@ -27,10 +27,11 @@ const HistorySchema = CollectionSchema(
name: r'date', name: r'date',
type: IsarType.string, type: IsarType.string,
), ),
r'isManga': PropertySchema( r'itemType': PropertySchema(
id: 2, id: 2,
name: r'isManga', name: r'itemType',
type: IsarType.bool, type: IsarType.byte,
enumMap: _HistoryitemTypeEnumValueMap,
), ),
r'mangaId': PropertySchema( r'mangaId': PropertySchema(
id: 3, id: 3,
@ -82,7 +83,7 @@ void _historySerialize(
) { ) {
writer.writeLong(offsets[0], object.chapterId); writer.writeLong(offsets[0], object.chapterId);
writer.writeString(offsets[1], object.date); writer.writeString(offsets[1], object.date);
writer.writeBool(offsets[2], object.isManga); writer.writeByte(offsets[2], object.itemType.index);
writer.writeLong(offsets[3], object.mangaId); writer.writeLong(offsets[3], object.mangaId);
} }
@ -96,7 +97,8 @@ History _historyDeserialize(
chapterId: reader.readLongOrNull(offsets[0]), chapterId: reader.readLongOrNull(offsets[0]),
date: reader.readStringOrNull(offsets[1]), date: reader.readStringOrNull(offsets[1]),
id: id, id: id,
isManga: reader.readBoolOrNull(offsets[2]), itemType: _HistoryitemTypeValueEnumMap[reader.readByteOrNull(offsets[2])] ??
ItemType.manga,
mangaId: reader.readLongOrNull(offsets[3]), mangaId: reader.readLongOrNull(offsets[3]),
); );
return object; return object;
@ -114,7 +116,8 @@ P _historyDeserializeProp<P>(
case 1: case 1:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 2: case 2:
return (reader.readBoolOrNull(offset)) as P; return (_HistoryitemTypeValueEnumMap[reader.readByteOrNull(offset)] ??
ItemType.manga) as P;
case 3: case 3:
return (reader.readLongOrNull(offset)) as P; return (reader.readLongOrNull(offset)) as P;
default: default:
@ -122,6 +125,17 @@ P _historyDeserializeProp<P>(
} }
} }
const _HistoryitemTypeEnumValueMap = {
'manga': 0,
'anime': 1,
'novel': 2,
};
const _HistoryitemTypeValueEnumMap = {
0: ItemType.manga,
1: ItemType.anime,
2: ItemType.novel,
};
Id _historyGetId(History object) { Id _historyGetId(History object) {
return object.id ?? Isar.autoIncrement; return object.id ?? Isar.autoIncrement;
} }
@ -495,32 +509,59 @@ extension HistoryQueryFilter
}); });
} }
QueryBuilder<History, History, QAfterFilterCondition> isMangaIsNull() { QueryBuilder<History, History, QAfterFilterCondition> itemTypeEqualTo(
return QueryBuilder.apply(this, (query) { ItemType value) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'isManga',
));
});
}
QueryBuilder<History, History, QAfterFilterCondition> isMangaIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'isManga',
));
});
}
QueryBuilder<History, History, QAfterFilterCondition> isMangaEqualTo(
bool? value) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo( return query.addFilterCondition(FilterCondition.equalTo(
property: r'isManga', property: r'itemType',
value: value, value: value,
)); ));
}); });
} }
QueryBuilder<History, History, QAfterFilterCondition> itemTypeGreaterThan(
ItemType value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'itemType',
value: value,
));
});
}
QueryBuilder<History, History, QAfterFilterCondition> itemTypeLessThan(
ItemType value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'itemType',
value: value,
));
});
}
QueryBuilder<History, History, QAfterFilterCondition> itemTypeBetween(
ItemType lower,
ItemType upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'itemType',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
QueryBuilder<History, History, QAfterFilterCondition> mangaIdIsNull() { QueryBuilder<History, History, QAfterFilterCondition> mangaIdIsNull() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull( return query.addFilterCondition(const FilterCondition.isNull(
@ -635,15 +676,15 @@ extension HistoryQuerySortBy on QueryBuilder<History, History, QSortBy> {
}); });
} }
QueryBuilder<History, History, QAfterSortBy> sortByIsManga() { QueryBuilder<History, History, QAfterSortBy> sortByItemType() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.asc); return query.addSortBy(r'itemType', Sort.asc);
}); });
} }
QueryBuilder<History, History, QAfterSortBy> sortByIsMangaDesc() { QueryBuilder<History, History, QAfterSortBy> sortByItemTypeDesc() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.desc); return query.addSortBy(r'itemType', Sort.desc);
}); });
} }
@ -698,15 +739,15 @@ extension HistoryQuerySortThenBy
}); });
} }
QueryBuilder<History, History, QAfterSortBy> thenByIsManga() { QueryBuilder<History, History, QAfterSortBy> thenByItemType() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.asc); return query.addSortBy(r'itemType', Sort.asc);
}); });
} }
QueryBuilder<History, History, QAfterSortBy> thenByIsMangaDesc() { QueryBuilder<History, History, QAfterSortBy> thenByItemTypeDesc() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.desc); return query.addSortBy(r'itemType', Sort.desc);
}); });
} }
@ -738,9 +779,9 @@ extension HistoryQueryWhereDistinct
}); });
} }
QueryBuilder<History, History, QDistinct> distinctByIsManga() { QueryBuilder<History, History, QDistinct> distinctByItemType() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'isManga'); return query.addDistinctBy(r'itemType');
}); });
} }
@ -771,9 +812,9 @@ extension HistoryQueryProperty
}); });
} }
QueryBuilder<History, bool?, QQueryOperations> isMangaProperty() { QueryBuilder<History, ItemType, QQueryOperations> itemTypeProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'isManga'); return query.addPropertyName(r'itemType');
}); });
} }

View file

@ -22,7 +22,8 @@ class Manga {
@enumerated @enumerated
late Status status; late Status status;
bool? isManga; @enumerated
late ItemType itemType;
List<String>? genre; List<String>? genre;
@ -62,7 +63,7 @@ class Manga {
required this.name, required this.name,
required this.status, required this.status,
required this.description, required this.description,
this.isManga = true, this.itemType = ItemType.manga,
this.dateAdded, this.dateAdded,
this.lastUpdate, this.lastUpdate,
this.categories, this.categories,
@ -83,7 +84,7 @@ class Manga {
id = json['id']; id = json['id'];
imageUrl = json['imageUrl']; imageUrl = json['imageUrl'];
isLocalArchive = json['isLocalArchive']; isLocalArchive = json['isLocalArchive'];
isManga = json['isManga']; itemType = ItemType.values[json['itemType']];
lang = json['lang']; lang = json['lang'];
lastRead = json['lastRead']; lastRead = json['lastRead'];
lastUpdate = json['lastUpdate']; lastUpdate = json['lastUpdate'];
@ -106,7 +107,7 @@ class Manga {
'id': id, 'id': id,
'imageUrl': imageUrl, 'imageUrl': imageUrl,
'isLocalArchive': isLocalArchive, 'isLocalArchive': isLocalArchive,
'isManga': isManga, 'itemType': itemType.index,
'lang': lang, 'lang': lang,
'lastRead': lastRead, 'lastRead': lastRead,
'lastUpdate': lastUpdate, 'lastUpdate': lastUpdate,
@ -126,3 +127,9 @@ enum Status {
onHiatus, onHiatus,
publishingFinished publishingFinished
} }
enum ItemType {
manga,
anime,
novel
}

View file

@ -72,10 +72,11 @@ const MangaSchema = CollectionSchema(
name: r'isLocalArchive', name: r'isLocalArchive',
type: IsarType.bool, type: IsarType.bool,
), ),
r'isManga': PropertySchema( r'itemType': PropertySchema(
id: 11, id: 11,
name: r'isManga', name: r'itemType',
type: IsarType.bool, type: IsarType.byte,
enumMap: _MangaitemTypeEnumValueMap,
), ),
r'lang': PropertySchema( r'lang': PropertySchema(
id: 12, id: 12,
@ -240,7 +241,7 @@ void _mangaSerialize(
writer.writeStringList(offsets[8], object.genre); writer.writeStringList(offsets[8], object.genre);
writer.writeString(offsets[9], object.imageUrl); writer.writeString(offsets[9], object.imageUrl);
writer.writeBool(offsets[10], object.isLocalArchive); writer.writeBool(offsets[10], object.isLocalArchive);
writer.writeBool(offsets[11], object.isManga); writer.writeByte(offsets[11], object.itemType.index);
writer.writeString(offsets[12], object.lang); writer.writeString(offsets[12], object.lang);
writer.writeLong(offsets[13], object.lastRead); writer.writeLong(offsets[13], object.lastRead);
writer.writeLong(offsets[14], object.lastUpdate); writer.writeLong(offsets[14], object.lastUpdate);
@ -269,7 +270,8 @@ Manga _mangaDeserialize(
id: id, id: id,
imageUrl: reader.readStringOrNull(offsets[9]), imageUrl: reader.readStringOrNull(offsets[9]),
isLocalArchive: reader.readBoolOrNull(offsets[10]), isLocalArchive: reader.readBoolOrNull(offsets[10]),
isManga: reader.readBoolOrNull(offsets[11]), itemType: _MangaitemTypeValueEnumMap[reader.readByteOrNull(offsets[11])] ??
ItemType.manga,
lang: reader.readStringOrNull(offsets[12]), lang: reader.readStringOrNull(offsets[12]),
lastRead: reader.readLongOrNull(offsets[13]), lastRead: reader.readLongOrNull(offsets[13]),
lastUpdate: reader.readLongOrNull(offsets[14]), lastUpdate: reader.readLongOrNull(offsets[14]),
@ -312,7 +314,8 @@ P _mangaDeserializeProp<P>(
case 10: case 10:
return (reader.readBoolOrNull(offset)) as P; return (reader.readBoolOrNull(offset)) as P;
case 11: case 11:
return (reader.readBoolOrNull(offset)) as P; return (_MangaitemTypeValueEnumMap[reader.readByteOrNull(offset)] ??
ItemType.manga) as P;
case 12: case 12:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 13: case 13:
@ -333,6 +336,16 @@ P _mangaDeserializeProp<P>(
} }
} }
const _MangaitemTypeEnumValueMap = {
'manga': 0,
'anime': 1,
'novel': 2,
};
const _MangaitemTypeValueEnumMap = {
0: ItemType.manga,
1: ItemType.anime,
2: ItemType.novel,
};
const _MangastatusEnumValueMap = { const _MangastatusEnumValueMap = {
'ongoing': 0, 'ongoing': 0,
'completed': 1, 'completed': 1,
@ -1911,32 +1924,59 @@ extension MangaQueryFilter on QueryBuilder<Manga, Manga, QFilterCondition> {
}); });
} }
QueryBuilder<Manga, Manga, QAfterFilterCondition> isMangaIsNull() { QueryBuilder<Manga, Manga, QAfterFilterCondition> itemTypeEqualTo(
return QueryBuilder.apply(this, (query) { ItemType value) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'isManga',
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> isMangaIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'isManga',
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> isMangaEqualTo(
bool? value) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo( return query.addFilterCondition(FilterCondition.equalTo(
property: r'isManga', property: r'itemType',
value: value, value: value,
)); ));
}); });
} }
QueryBuilder<Manga, Manga, QAfterFilterCondition> itemTypeGreaterThan(
ItemType value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'itemType',
value: value,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> itemTypeLessThan(
ItemType value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'itemType',
value: value,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> itemTypeBetween(
ItemType lower,
ItemType upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'itemType',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> langIsNull() { QueryBuilder<Manga, Manga, QAfterFilterCondition> langIsNull() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull( return query.addFilterCondition(const FilterCondition.isNull(
@ -2863,15 +2903,15 @@ extension MangaQuerySortBy on QueryBuilder<Manga, Manga, QSortBy> {
}); });
} }
QueryBuilder<Manga, Manga, QAfterSortBy> sortByIsManga() { QueryBuilder<Manga, Manga, QAfterSortBy> sortByItemType() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.asc); return query.addSortBy(r'itemType', Sort.asc);
}); });
} }
QueryBuilder<Manga, Manga, QAfterSortBy> sortByIsMangaDesc() { QueryBuilder<Manga, Manga, QAfterSortBy> sortByItemTypeDesc() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.desc); return query.addSortBy(r'itemType', Sort.desc);
}); });
} }
@ -3069,15 +3109,15 @@ extension MangaQuerySortThenBy on QueryBuilder<Manga, Manga, QSortThenBy> {
}); });
} }
QueryBuilder<Manga, Manga, QAfterSortBy> thenByIsManga() { QueryBuilder<Manga, Manga, QAfterSortBy> thenByItemType() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.asc); return query.addSortBy(r'itemType', Sort.asc);
}); });
} }
QueryBuilder<Manga, Manga, QAfterSortBy> thenByIsMangaDesc() { QueryBuilder<Manga, Manga, QAfterSortBy> thenByItemTypeDesc() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isManga', Sort.desc); return query.addSortBy(r'itemType', Sort.desc);
}); });
} }
@ -3239,9 +3279,9 @@ extension MangaQueryWhereDistinct on QueryBuilder<Manga, Manga, QDistinct> {
}); });
} }
QueryBuilder<Manga, Manga, QDistinct> distinctByIsManga() { QueryBuilder<Manga, Manga, QDistinct> distinctByItemType() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'isManga'); return query.addDistinctBy(r'itemType');
}); });
} }
@ -3366,9 +3406,9 @@ extension MangaQueryProperty on QueryBuilder<Manga, Manga, QQueryProperty> {
}); });
} }
QueryBuilder<Manga, bool?, QQueryOperations> isMangaProperty() { QueryBuilder<Manga, ItemType, QQueryOperations> itemTypeProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'isManga'); return query.addPropertyName(r'itemType');
}); });
} }

View file

@ -187,11 +187,38 @@ class Settings {
int? animeGridSize; int? animeGridSize;
int? novelGridSize;
@enumerated @enumerated
late SectionType disableSectionType; late SectionType disableSectionType;
bool? useLibass; bool? useLibass;
int? libraryFilterNovelDownloadType;
int? libraryFilterNovelUnreadType;
int? libraryFilterNovelStartedType;
int? libraryFilterNovelBookMarkedType;
bool? novelLibraryShowCategoryTabs;
bool? novelLibraryDownloadedChapters;
bool? novelLibraryShowLanguage;
bool? novelLibraryShowNumbersOfItems;
bool? novelLibraryShowContinueReadingButton;
bool? novelLibraryLocalSource;
late SortLibraryManga? sortLibraryNovel;
@enumerated
late DisplayType novelDisplayType;
Settings( Settings(
{this.id = 227, {this.id = 227,
this.displayType = DisplayType.compactGrid, this.displayType = DisplayType.compactGrid,
@ -276,7 +303,19 @@ class Settings {
this.mangaGridSize, this.mangaGridSize,
this.animeGridSize, this.animeGridSize,
this.disableSectionType = SectionType.all, this.disableSectionType = SectionType.all,
this.useLibass = true}); this.useLibass = true,
this.libraryFilterNovelDownloadType = 0,
this.libraryFilterNovelUnreadType = 0,
this.libraryFilterNovelStartedType = 0,
this.libraryFilterNovelBookMarkedType = 0,
this.novelLibraryShowCategoryTabs = false,
this.novelLibraryDownloadedChapters = false,
this.novelLibraryShowLanguage = false,
this.novelLibraryShowNumbersOfItems = false,
this.novelLibraryShowContinueReadingButton = false,
this.novelLibraryLocalSource,
this.sortLibraryNovel,
this.novelDisplayType = DisplayType.comfortableGrid});
Settings.fromJson(Map<String, dynamic> json) { Settings.fromJson(Map<String, dynamic> json) {
animatePageTransitions = json['animatePageTransitions']; animatePageTransitions = json['animatePageTransitions'];
@ -432,6 +471,22 @@ class Settings {
disableSectionType = disableSectionType =
SectionType.values[json['disableSectionType'] ?? SectionType.all]; SectionType.values[json['disableSectionType'] ?? SectionType.all];
useLibass = json['useLibass']; useLibass = json['useLibass'];
libraryFilterNovelBookMarkedType = json['libraryFilterNovelBookMarkedType'];
libraryFilterNovelDownloadType = json['libraryFilterNovelDownloadType'];
libraryFilterNovelStartedType = json['libraryFilterNovelStartedType'];
libraryFilterNovelUnreadType = json['libraryFilterNovelUnreadType'];
novelLibraryShowCategoryTabs = json['novelLibraryShowCategoryTabs'];
novelLibraryDownloadedChapters = json['novelLibraryDownloadedChapters'];
novelLibraryShowLanguage = json['novelLibraryShowLanguage'];
novelLibraryShowNumbersOfItems = json['novelLibraryShowNumbersOfItems'];
novelLibraryShowContinueReadingButton =
json['novelLibraryShowContinueReadingButton'];
novelLibraryLocalSource = json['novelLibraryLocalSource'];
sortLibraryNovel = json['sortLibraryNovel'] != null
? SortLibraryManga.fromJson(json['sortLibraryNovel'])
: null;
novelDisplayType = DisplayType
.values[json['novelDisplayType'] ?? DisplayType.compactGrid.index];
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
@ -532,7 +587,20 @@ class Settings {
'mangaGridSize': mangaGridSize, 'mangaGridSize': mangaGridSize,
'animeGridSize': animeGridSize, 'animeGridSize': animeGridSize,
'disableSectionType': disableSectionType.index, 'disableSectionType': disableSectionType.index,
'useLibass': useLibass 'useLibass': useLibass,
'libraryFilterNovelBookMarkedType': libraryFilterNovelBookMarkedType,
'libraryFilterNovelDownloadType': libraryFilterNovelDownloadType,
'libraryFilterNovelStartedType': libraryFilterNovelStartedType,
'libraryFilterNovelUnreadType': libraryFilterNovelUnreadType,
'novelLibraryShowCategoryTabs': novelLibraryShowCategoryTabs,
'novelLibraryDownloadedChapters': novelLibraryDownloadedChapters,
'novelLibraryShowLanguage': novelLibraryShowLanguage,
'novelLibraryShowNumbersOfItems': novelLibraryShowNumbersOfItems,
'novelLibraryShowContinueReadingButton':
novelLibraryShowContinueReadingButton,
'novelLibraryLocalSource': novelLibraryLocalSource,
'sortLibraryNovel': sortLibraryNovel?.toJson(),
'novelDisplayType': novelDisplayType.index,
}; };
} }

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,6 @@
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/eval/model/m_source.dart'; import 'package:mangayomi/eval/model/m_source.dart';
import 'package:mangayomi/models/manga.dart';
part 'source.g.dart'; part 'source.g.dart';
@collection @collection
@ -49,6 +50,9 @@ class Source {
bool? isManga; bool? isManga;
@enumerated
late ItemType itemType;
String? appMinVerReq; String? appMinVerReq;
String? additionalParams; String? additionalParams;
@ -83,6 +87,7 @@ class Source {
this.sourceCode = '', this.sourceCode = '',
this.headers = '', this.headers = '',
this.isManga = true, this.isManga = true,
this.itemType = ItemType.manga,
this.appMinVerReq = "", this.appMinVerReq = "",
this.additionalParams = "", this.additionalParams = "",
this.isLocal = false, this.isLocal = false,
@ -102,6 +107,7 @@ class Source {
isAdded = json['isAdded']; isAdded = json['isAdded'];
isFullData = json['isFullData']; isFullData = json['isFullData'];
isManga = json['isManga']; isManga = json['isManga'];
itemType = ItemType.values[json['itemType'] ?? 0];
isNsfw = json['isNsfw']; isNsfw = json['isNsfw'];
isPinned = json['isPinned']; isPinned = json['isPinned'];
lang = json['lang']; lang = json['lang'];
@ -133,6 +139,7 @@ class Source {
'isAdded': isAdded, 'isAdded': isAdded,
'isFullData': isFullData, 'isFullData': isFullData,
'isManga': isManga, 'isManga': isManga,
'itemType': itemType,
'isNsfw': isNsfw, 'isNsfw': isNsfw,
'isPinned': isPinned, 'isPinned': isPinned,
'lang': lang, 'lang': lang,

View file

@ -107,49 +107,55 @@ const SourceSchema = CollectionSchema(
name: r'isTorrent', name: r'isTorrent',
type: IsarType.bool, type: IsarType.bool,
), ),
r'lang': PropertySchema( r'itemType': PropertySchema(
id: 18, id: 18,
name: r'itemType',
type: IsarType.byte,
enumMap: _SourceitemTypeEnumValueMap,
),
r'lang': PropertySchema(
id: 19,
name: r'lang', name: r'lang',
type: IsarType.string, type: IsarType.string,
), ),
r'lastUsed': PropertySchema( r'lastUsed': PropertySchema(
id: 19, id: 20,
name: r'lastUsed', name: r'lastUsed',
type: IsarType.bool, type: IsarType.bool,
), ),
r'name': PropertySchema( r'name': PropertySchema(
id: 20, id: 21,
name: r'name', name: r'name',
type: IsarType.string, type: IsarType.string,
), ),
r'sourceCode': PropertySchema( r'sourceCode': PropertySchema(
id: 21, id: 22,
name: r'sourceCode', name: r'sourceCode',
type: IsarType.string, type: IsarType.string,
), ),
r'sourceCodeLanguage': PropertySchema( r'sourceCodeLanguage': PropertySchema(
id: 22, id: 23,
name: r'sourceCodeLanguage', name: r'sourceCodeLanguage',
type: IsarType.byte, type: IsarType.byte,
enumMap: _SourcesourceCodeLanguageEnumValueMap, enumMap: _SourcesourceCodeLanguageEnumValueMap,
), ),
r'sourceCodeUrl': PropertySchema( r'sourceCodeUrl': PropertySchema(
id: 23, id: 24,
name: r'sourceCodeUrl', name: r'sourceCodeUrl',
type: IsarType.string, type: IsarType.string,
), ),
r'typeSource': PropertySchema( r'typeSource': PropertySchema(
id: 24, id: 25,
name: r'typeSource', name: r'typeSource',
type: IsarType.string, type: IsarType.string,
), ),
r'version': PropertySchema( r'version': PropertySchema(
id: 25, id: 26,
name: r'version', name: r'version',
type: IsarType.string, type: IsarType.string,
), ),
r'versionLast': PropertySchema( r'versionLast': PropertySchema(
id: 26, id: 27,
name: r'versionLast', name: r'versionLast',
type: IsarType.string, type: IsarType.string,
) )
@ -291,15 +297,16 @@ void _sourceSerialize(
writer.writeBool(offsets[15], object.isObsolete); writer.writeBool(offsets[15], object.isObsolete);
writer.writeBool(offsets[16], object.isPinned); writer.writeBool(offsets[16], object.isPinned);
writer.writeBool(offsets[17], object.isTorrent); writer.writeBool(offsets[17], object.isTorrent);
writer.writeString(offsets[18], object.lang); writer.writeByte(offsets[18], object.itemType.index);
writer.writeBool(offsets[19], object.lastUsed); writer.writeString(offsets[19], object.lang);
writer.writeString(offsets[20], object.name); writer.writeBool(offsets[20], object.lastUsed);
writer.writeString(offsets[21], object.sourceCode); writer.writeString(offsets[21], object.name);
writer.writeByte(offsets[22], object.sourceCodeLanguage.index); writer.writeString(offsets[22], object.sourceCode);
writer.writeString(offsets[23], object.sourceCodeUrl); writer.writeByte(offsets[23], object.sourceCodeLanguage.index);
writer.writeString(offsets[24], object.typeSource); writer.writeString(offsets[24], object.sourceCodeUrl);
writer.writeString(offsets[25], object.version); writer.writeString(offsets[25], object.typeSource);
writer.writeString(offsets[26], object.versionLast); writer.writeString(offsets[26], object.version);
writer.writeString(offsets[27], object.versionLast);
} }
Source _sourceDeserialize( Source _sourceDeserialize(
@ -327,17 +334,19 @@ Source _sourceDeserialize(
isNsfw: reader.readBoolOrNull(offsets[14]), isNsfw: reader.readBoolOrNull(offsets[14]),
isObsolete: reader.readBoolOrNull(offsets[15]), isObsolete: reader.readBoolOrNull(offsets[15]),
isPinned: reader.readBoolOrNull(offsets[16]), isPinned: reader.readBoolOrNull(offsets[16]),
lang: reader.readStringOrNull(offsets[18]), itemType: _SourceitemTypeValueEnumMap[reader.readByteOrNull(offsets[18])] ??
lastUsed: reader.readBoolOrNull(offsets[19]), ItemType.manga,
name: reader.readStringOrNull(offsets[20]), lang: reader.readStringOrNull(offsets[19]),
sourceCode: reader.readStringOrNull(offsets[21]), lastUsed: reader.readBoolOrNull(offsets[20]),
sourceCodeUrl: reader.readStringOrNull(offsets[23]), name: reader.readStringOrNull(offsets[21]),
typeSource: reader.readStringOrNull(offsets[24]), sourceCode: reader.readStringOrNull(offsets[22]),
version: reader.readStringOrNull(offsets[25]), sourceCodeUrl: reader.readStringOrNull(offsets[24]),
versionLast: reader.readStringOrNull(offsets[26]), typeSource: reader.readStringOrNull(offsets[25]),
version: reader.readStringOrNull(offsets[26]),
versionLast: reader.readStringOrNull(offsets[27]),
); );
object.sourceCodeLanguage = _SourcesourceCodeLanguageValueEnumMap[ object.sourceCodeLanguage = _SourcesourceCodeLanguageValueEnumMap[
reader.readByteOrNull(offsets[22])] ?? reader.readByteOrNull(offsets[23])] ??
SourceCodeLanguage.dart; SourceCodeLanguage.dart;
return object; return object;
} }
@ -386,30 +395,43 @@ P _sourceDeserializeProp<P>(
case 17: case 17:
return (reader.readBool(offset)) as P; return (reader.readBool(offset)) as P;
case 18: case 18:
return (reader.readStringOrNull(offset)) as P; return (_SourceitemTypeValueEnumMap[reader.readByteOrNull(offset)] ??
ItemType.manga) as P;
case 19: case 19:
return (reader.readBoolOrNull(offset)) as P;
case 20:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 20:
return (reader.readBoolOrNull(offset)) as P;
case 21: case 21:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 22: case 22:
return (reader.readStringOrNull(offset)) as P;
case 23:
return (_SourcesourceCodeLanguageValueEnumMap[ return (_SourcesourceCodeLanguageValueEnumMap[
reader.readByteOrNull(offset)] ?? reader.readByteOrNull(offset)] ??
SourceCodeLanguage.dart) as P; SourceCodeLanguage.dart) as P;
case 23:
return (reader.readStringOrNull(offset)) as P;
case 24: case 24:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 25: case 25:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 26: case 26:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 27:
return (reader.readStringOrNull(offset)) as P;
default: default:
throw IsarError('Unknown property with id $propertyId'); throw IsarError('Unknown property with id $propertyId');
} }
} }
const _SourceitemTypeEnumValueMap = {
'manga': 0,
'anime': 1,
'novel': 2,
};
const _SourceitemTypeValueEnumMap = {
0: ItemType.manga,
1: ItemType.anime,
2: ItemType.novel,
};
const _SourcesourceCodeLanguageEnumValueMap = { const _SourcesourceCodeLanguageEnumValueMap = {
'dart': 0, 'dart': 0,
'javascript': 1, 'javascript': 1,
@ -1997,6 +2019,59 @@ extension SourceQueryFilter on QueryBuilder<Source, Source, QFilterCondition> {
}); });
} }
QueryBuilder<Source, Source, QAfterFilterCondition> itemTypeEqualTo(
ItemType value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'itemType',
value: value,
));
});
}
QueryBuilder<Source, Source, QAfterFilterCondition> itemTypeGreaterThan(
ItemType value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'itemType',
value: value,
));
});
}
QueryBuilder<Source, Source, QAfterFilterCondition> itemTypeLessThan(
ItemType value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'itemType',
value: value,
));
});
}
QueryBuilder<Source, Source, QAfterFilterCondition> itemTypeBetween(
ItemType lower,
ItemType upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'itemType',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
QueryBuilder<Source, Source, QAfterFilterCondition> langIsNull() { QueryBuilder<Source, Source, QAfterFilterCondition> langIsNull() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull( return query.addFilterCondition(const FilterCondition.isNull(
@ -3321,6 +3396,18 @@ extension SourceQuerySortBy on QueryBuilder<Source, Source, QSortBy> {
}); });
} }
QueryBuilder<Source, Source, QAfterSortBy> sortByItemType() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'itemType', Sort.asc);
});
}
QueryBuilder<Source, Source, QAfterSortBy> sortByItemTypeDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'itemType', Sort.desc);
});
}
QueryBuilder<Source, Source, QAfterSortBy> sortByLang() { QueryBuilder<Source, Source, QAfterSortBy> sortByLang() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'lang', Sort.asc); return query.addSortBy(r'lang', Sort.asc);
@ -3659,6 +3746,18 @@ extension SourceQuerySortThenBy on QueryBuilder<Source, Source, QSortThenBy> {
}); });
} }
QueryBuilder<Source, Source, QAfterSortBy> thenByItemType() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'itemType', Sort.asc);
});
}
QueryBuilder<Source, Source, QAfterSortBy> thenByItemTypeDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'itemType', Sort.desc);
});
}
QueryBuilder<Source, Source, QAfterSortBy> thenByLang() { QueryBuilder<Source, Source, QAfterSortBy> thenByLang() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'lang', Sort.asc); return query.addSortBy(r'lang', Sort.asc);
@ -3887,6 +3986,12 @@ extension SourceQueryWhereDistinct on QueryBuilder<Source, Source, QDistinct> {
}); });
} }
QueryBuilder<Source, Source, QDistinct> distinctByItemType() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'itemType');
});
}
QueryBuilder<Source, Source, QDistinct> distinctByLang( QueryBuilder<Source, Source, QDistinct> distinctByLang(
{bool caseSensitive = true}) { {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
@ -4065,6 +4170,12 @@ extension SourceQueryProperty on QueryBuilder<Source, Source, QQueryProperty> {
}); });
} }
QueryBuilder<Source, ItemType, QQueryOperations> itemTypeProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'itemType');
});
}
QueryBuilder<Source, String?, QQueryOperations> langProperty() { QueryBuilder<Source, String?, QQueryOperations> langProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'lang'); return query.addPropertyName(r'lang');

View file

@ -133,7 +133,7 @@ class AnimeStreamController extends _$AnimeStreamController {
history = History( history = History(
mangaId: getAnime().id, mangaId: getAnime().id,
date: DateTime.now().millisecondsSinceEpoch.toString(), date: DateTime.now().millisecondsSinceEpoch.toString(),
isManga: getAnime().isManga, itemType: getAnime().itemType,
chapterId: episode.id) chapterId: episode.id)
..chapter.value = episode; ..chapter.value = episode;
} else { } else {

View file

@ -7,7 +7,7 @@ part of 'anime_player_controller_provider.dart';
// ************************************************************************** // **************************************************************************
String _$animeStreamControllerHash() => String _$animeStreamControllerHash() =>
r'0d97207a4d015d5089766ccbeeba093c55cb1ef9'; r'd3ec7fe7ac2af84393b128e430fd2f5b9224ed14';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {

View file

@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/providers/storage_provider.dart'; import 'package:mangayomi/providers/storage_provider.dart';
@ -24,7 +25,7 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
@override @override
void initState() { void initState() {
_tabBarController = TabController(length: 4, vsync: this); _tabBarController = TabController(length: 6, vsync: this);
_tabBarController.animateTo(0); _tabBarController.animateTo(0);
_tabBarController.addListener(() { _tabBarController.addListener(() {
_chekPermission(); _chekPermission();
@ -47,7 +48,7 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return DefaultTabController( return DefaultTabController(
animationDuration: Duration.zero, animationDuration: Duration.zero,
length: 4, length: 6,
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
elevation: 0, elevation: 0,
@ -75,8 +76,9 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
) )
: Row( : Row(
children: [ children: [
if (_tabBarController.index == 2 || if (_tabBarController.index == 3 ||
_tabBarController.index == 3) _tabBarController.index == 4 ||
_tabBarController.index == 5)
IconButton( IconButton(
onPressed: () { onPressed: () {
context.push('/createExtension'); context.push('/createExtension');
@ -87,8 +89,9 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
? IconButton( ? IconButton(
splashRadius: 20, splashRadius: 20,
onPressed: () { onPressed: () {
if (_tabBarController.index != 1 && if (_tabBarController.index != 0 &&
_tabBarController.index != 0) { _tabBarController.index != 1 &&
_tabBarController.index != 2) {
setState(() { setState(() {
_isSearch = true; _isSearch = true;
}); });
@ -101,7 +104,8 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
}, },
icon: Icon( icon: Icon(
_tabBarController.index == 0 || _tabBarController.index == 0 ||
_tabBarController.index == 1 _tabBarController.index == 1 ||
_tabBarController.index == 2
? Icons.travel_explore_rounded ? Icons.travel_explore_rounded
: Icons.search_rounded, : Icons.search_rounded,
color: Theme.of(context).hintColor)) color: Theme.of(context).hintColor))
@ -116,18 +120,24 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
} else if (_tabBarController.index == 1) { } else if (_tabBarController.index == 1) {
context.push('/sourceFilter', extra: false); context.push('/sourceFilter', extra: false);
} else if (_tabBarController.index == 2) { } else if (_tabBarController.index == 2) {
_textEditingController.clear(); context.push('/sourceFilter', extra: false);
context.push('/ExtensionLang', extra: true);
} else if (_tabBarController.index == 3) { } else if (_tabBarController.index == 3) {
_textEditingController.clear(); _textEditingController.clear();
context.push('/ExtensionLang', extra: false); context.push('/ExtensionLang', extra: false);
} else if (_tabBarController.index == 4) {
_textEditingController.clear();
context.push('/ExtensionLang', extra: false);
} else if (_tabBarController.index == 5) {
_textEditingController.clear();
context.push('/ExtensionLang', extra: false);
} else {} } else {}
}, },
icon: Icon( icon: Icon(
_tabBarController.index == 0 || _tabBarController.index == 1 _tabBarController.index == 0 || _tabBarController.index == 1 || _tabBarController.index == 2
? Icons.filter_list_sharp ? Icons.filter_list_sharp
: _tabBarController.index == 2 || : _tabBarController.index == 3 ||
_tabBarController.index == 3 _tabBarController.index == 4 ||
_tabBarController.index == 5
? Icons.translate_rounded ? Icons.translate_rounded
: Icons.help_outline_outlined, : Icons.help_outline_outlined,
color: Theme.of(context).hintColor)), color: Theme.of(context).hintColor)),
@ -139,12 +149,13 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
tabs: [ tabs: [
Tab(text: l10n.manga_sources), Tab(text: l10n.manga_sources),
Tab(text: l10n.anime_sources), Tab(text: l10n.anime_sources),
Tab(text: l10n.novel_sources),
Tab( Tab(
child: Row( child: Row(
children: [ children: [
Text(l10n.manga_extensions), Text(l10n.manga_extensions),
const SizedBox(width: 8), const SizedBox(width: 8),
_extensionUpdateNumbers(ref, true) _extensionUpdateNumbers(ref, ItemType.manga)
], ],
), ),
), ),
@ -153,7 +164,16 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
children: [ children: [
Text(l10n.anime_extensions), Text(l10n.anime_extensions),
const SizedBox(width: 8), const SizedBox(width: 8),
_extensionUpdateNumbers(ref, false) _extensionUpdateNumbers(ref, ItemType.anime)
],
),
),
Tab(
child: Row(
children: [
Text(l10n.novel_extensions),
const SizedBox(width: 8),
_extensionUpdateNumbers(ref, ItemType.novel)
], ],
), ),
), ),
@ -163,24 +183,34 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
), ),
body: TabBarView(controller: _tabBarController, children: [ body: TabBarView(controller: _tabBarController, children: [
SourcesScreen( SourcesScreen(
isManga: true, itemType: ItemType.manga,
tabIndex: (index) { tabIndex: (index) {
_tabBarController.animateTo(index); _tabBarController.animateTo(index);
}, },
), ),
SourcesScreen( SourcesScreen(
isManga: false, itemType: ItemType.anime,
tabIndex: (index) {
_tabBarController.animateTo(index);
},
),
SourcesScreen(
itemType: ItemType.novel,
tabIndex: (index) { tabIndex: (index) {
_tabBarController.animateTo(index); _tabBarController.animateTo(index);
}, },
), ),
ExtensionScreen( ExtensionScreen(
query: _textEditingController.text, query: _textEditingController.text,
isManga: true, itemType: ItemType.manga,
), ),
ExtensionScreen( ExtensionScreen(
query: _textEditingController.text, query: _textEditingController.text,
isManga: false, itemType: ItemType.anime,
),
ExtensionScreen(
query: _textEditingController.text,
itemType: ItemType.novel,
), ),
// const MigrateScreen() // const MigrateScreen()
]), ]),
@ -189,14 +219,14 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
} }
} }
Widget _extensionUpdateNumbers(WidgetRef ref, bool isManga) { Widget _extensionUpdateNumbers(WidgetRef ref, ItemType itemType) {
return StreamBuilder( return StreamBuilder(
stream: isar.sources stream: isar.sources
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.isActiveEqualTo(true) .isActiveEqualTo(true)
.isMangaEqualTo(isManga) .itemTypeEqualTo(itemType)
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) { if (snapshot.hasData && snapshot.data!.isNotEmpty) {

View file

@ -50,7 +50,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
("search", 2), ("search", 2),
("getDetail", 3), ("getDetail", 3),
("getPageList", 4), ("getPageList", 4),
("getVideoList", 5) ("getVideoList", 5),
("getHtmlContent", 6)
]; ];
int _serviceIndex = 0; int _serviceIndex = 0;
@ -219,7 +220,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
}), }),
if (_serviceIndex == 3 || if (_serviceIndex == 3 ||
_serviceIndex == 4 || _serviceIndex == 4 ||
_serviceIndex == 5) _serviceIndex == 5 ||
_serviceIndex == 6)
_textEditing("Url", context, "ex: url of the entry", _textEditing("Url", context, "ex: url of the entry",
(v) { (v) {
_url = v; _url = v;
@ -286,11 +288,14 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
.map((e) => e.toJson()) .map((e) => e.toJson())
.toList(), .toList(),
}; };
} else { } else if (_serviceIndex == 5) {
result = result =
(await service.getVideoList(_url)) (await service.getVideoList(_url))
.map((e) => e.toJson()) .map((e) => e.toJson())
.toList(); .toList();
} else {
result = (await service
.getHtmlContent(_url));
} }
if (mounted) { if (mounted) {
setState(() { setState(() {

View file

@ -1,21 +1,23 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:grouped_list/sliver_grouped_list.dart'; import 'package:grouped_list/sliver_grouped_list.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/browse/extension/providers/extensions_provider.dart'; import 'package:mangayomi/modules/browse/extension/providers/extensions_provider.dart';
import 'package:mangayomi/services/fetch_anime_sources.dart'; import 'package:mangayomi/services/fetch_anime_sources.dart';
import 'package:mangayomi/services/fetch_manga_sources.dart'; import 'package:mangayomi/services/fetch_manga_sources.dart';
import 'package:mangayomi/modules/widgets/progress_center.dart'; import 'package:mangayomi/modules/widgets/progress_center.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/services/fetch_novel_sources.dart';
import 'package:mangayomi/services/fetch_sources_list.dart'; import 'package:mangayomi/services/fetch_sources_list.dart';
import 'package:mangayomi/utils/language.dart'; import 'package:mangayomi/utils/language.dart';
import 'package:mangayomi/modules/browse/extension/widgets/extension_list_tile_widget.dart'; import 'package:mangayomi/modules/browse/extension/widgets/extension_list_tile_widget.dart';
class ExtensionScreen extends ConsumerStatefulWidget { class ExtensionScreen extends ConsumerStatefulWidget {
final bool isManga; final ItemType itemType;
final String query; final String query;
const ExtensionScreen( const ExtensionScreen(
{required this.query, required this.isManga, super.key}); {required this.query, required this.itemType, super.key});
@override @override
ConsumerState<ExtensionScreen> createState() => _ExtensionScreenState(); ConsumerState<ExtensionScreen> createState() => _ExtensionScreenState();
@ -26,19 +28,24 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final streamExtensions = final streamExtensions =
ref.watch(getExtensionsStreamProvider(widget.isManga)); ref.watch(getExtensionsStreamProvider(widget.itemType));
if (widget.isManga) { if (widget.itemType == ItemType.manga) {
ref.watch(fetchMangaSourcesListProvider(id: null, reFresh: false)); ref.watch(fetchMangaSourcesListProvider(id: null, reFresh: false));
} else { } else if (widget.itemType == ItemType.anime) {
ref.watch(fetchAnimeSourcesListProvider(id: null, reFresh: false)); ref.watch(fetchAnimeSourcesListProvider(id: null, reFresh: false));
} else {
ref.watch(fetchNovelSourcesListProvider(id: null, reFresh: false));
} }
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return RefreshIndicator( return RefreshIndicator(
onRefresh: () => widget.isManga onRefresh: () => widget.itemType == ItemType.manga
? ref.refresh( ? ref.refresh(
fetchMangaSourcesListProvider(id: null, reFresh: true).future) fetchMangaSourcesListProvider(id: null, reFresh: true).future)
: ref.refresh( : widget.itemType == ItemType.anime
fetchAnimeSourcesListProvider(id: null, reFresh: true).future), ? ref.refresh(
fetchAnimeSourcesListProvider(id: null, reFresh: true).future) :
ref.refresh(
fetchNovelSourcesListProvider(id: null, reFresh: true).future),
child: Padding( child: Padding(
padding: const EdgeInsets.only(top: 10), padding: const EdgeInsets.only(top: 10),
child: streamExtensions.when( child: streamExtensions.when(
@ -87,14 +94,19 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
ElevatedButton( ElevatedButton(
onPressed: () async { onPressed: () async {
for (var source in updateEntries) { for (var source in updateEntries) {
source.isManga! source.itemType == ItemType.manga
? await ref.watch( ? await ref.watch(
fetchMangaSourcesListProvider( fetchMangaSourcesListProvider(
id: source.id, reFresh: true) id: source.id, reFresh: true)
.future) .future)
: await ref.watch( : source.itemType == ItemType.anime ?
await ref.watch(
fetchAnimeSourcesListProvider( fetchAnimeSourcesListProvider(
id: source.id, reFresh: true) id: source.id, reFresh: true)
.future) :
await ref.watch(
fetchNovelSourcesListProvider(
id: source.id, reFresh: true)
.future); .future);
} }
}, },
@ -167,12 +179,15 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
error: (error, _) => Center( error: (error, _) => Center(
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {
if (widget.isManga) { if (widget.itemType == ItemType.manga) {
ref.invalidate( ref.invalidate(
fetchMangaSourcesListProvider(id: null, reFresh: true)); fetchMangaSourcesListProvider(id: null, reFresh: true));
} else { } else if (widget.itemType == ItemType.anime) {
ref.invalidate( ref.invalidate(
fetchAnimeSourcesListProvider(id: null, reFresh: true)); fetchAnimeSourcesListProvider(id: null, reFresh: true));
} else {
ref.invalidate(
fetchNovelSourcesListProvider(id: null, reFresh: true));
} }
}, },
child: Text(context.l10n.refresh)), child: Text(context.l10n.refresh)),

View file

@ -1,17 +1,18 @@
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/source.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'extensions_provider.g.dart'; part 'extensions_provider.g.dart';
@riverpod @riverpod
Stream<List<Source>> getExtensionsStream(Ref ref, bool? isManga) async* { Stream<List<Source>> getExtensionsStream(Ref ref, ItemType itemType) async* {
yield* isar.sources yield* isar.sources
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.isActiveEqualTo(true) .isActiveEqualTo(true)
.isMangaEqualTo(isManga) .itemTypeEqualTo(itemType)
.watch(fireImmediately: true); .watch(fireImmediately: true);
} }

View file

@ -7,7 +7,7 @@ part of 'extensions_provider.dart';
// ************************************************************************** // **************************************************************************
String _$getExtensionsStreamHash() => String _$getExtensionsStreamHash() =>
r'62f2884dd64a2f3d8928f7399c6b2547f0311078'; r'3c5d6625c40c222f25fc8141df078dd46bcc762f';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -41,10 +41,10 @@ class GetExtensionsStreamFamily extends Family<AsyncValue<List<Source>>> {
/// See also [getExtensionsStream]. /// See also [getExtensionsStream].
GetExtensionsStreamProvider call( GetExtensionsStreamProvider call(
bool? isManga, ItemType itemType,
) { ) {
return GetExtensionsStreamProvider( return GetExtensionsStreamProvider(
isManga, itemType,
); );
} }
@ -53,7 +53,7 @@ class GetExtensionsStreamFamily extends Family<AsyncValue<List<Source>>> {
covariant GetExtensionsStreamProvider provider, covariant GetExtensionsStreamProvider provider,
) { ) {
return call( return call(
provider.isManga, provider.itemType,
); );
} }
@ -77,11 +77,11 @@ class GetExtensionsStreamProvider
extends AutoDisposeStreamProvider<List<Source>> { extends AutoDisposeStreamProvider<List<Source>> {
/// See also [getExtensionsStream]. /// See also [getExtensionsStream].
GetExtensionsStreamProvider( GetExtensionsStreamProvider(
bool? isManga, ItemType itemType,
) : this._internal( ) : this._internal(
(ref) => getExtensionsStream( (ref) => getExtensionsStream(
ref as GetExtensionsStreamRef, ref as GetExtensionsStreamRef,
isManga, itemType,
), ),
from: getExtensionsStreamProvider, from: getExtensionsStreamProvider,
name: r'getExtensionsStreamProvider', name: r'getExtensionsStreamProvider',
@ -92,7 +92,7 @@ class GetExtensionsStreamProvider
dependencies: GetExtensionsStreamFamily._dependencies, dependencies: GetExtensionsStreamFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
GetExtensionsStreamFamily._allTransitiveDependencies, GetExtensionsStreamFamily._allTransitiveDependencies,
isManga: isManga, itemType: itemType,
); );
GetExtensionsStreamProvider._internal( GetExtensionsStreamProvider._internal(
@ -102,10 +102,10 @@ class GetExtensionsStreamProvider
required super.allTransitiveDependencies, required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash, required super.debugGetCreateSourceHash,
required super.from, required super.from,
required this.isManga, required this.itemType,
}) : super.internal(); }) : super.internal();
final bool? isManga; final ItemType itemType;
@override @override
Override overrideWith( Override overrideWith(
@ -120,7 +120,7 @@ class GetExtensionsStreamProvider
dependencies: null, dependencies: null,
allTransitiveDependencies: null, allTransitiveDependencies: null,
debugGetCreateSourceHash: null, debugGetCreateSourceHash: null,
isManga: isManga, itemType: itemType,
), ),
); );
} }
@ -132,13 +132,13 @@ class GetExtensionsStreamProvider
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is GetExtensionsStreamProvider && other.isManga == isManga; return other is GetExtensionsStreamProvider && other.itemType == itemType;
} }
@override @override
int get hashCode { int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode); var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode); hash = _SystemHash.combine(hash, itemType.hashCode);
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
} }
@ -147,8 +147,8 @@ class GetExtensionsStreamProvider
@Deprecated('Will be removed in 3.0. Use Ref instead') @Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element // ignore: unused_element
mixin GetExtensionsStreamRef on AutoDisposeStreamProviderRef<List<Source>> { mixin GetExtensionsStreamRef on AutoDisposeStreamProviderRef<List<Source>> {
/// The parameter `isManga` of this provider. /// The parameter `itemType` of this provider.
bool? get isManga; ItemType get itemType;
} }
class _GetExtensionsStreamProviderElement class _GetExtensionsStreamProviderElement
@ -157,7 +157,7 @@ class _GetExtensionsStreamProviderElement
_GetExtensionsStreamProviderElement(super.provider); _GetExtensionsStreamProviderElement(super.provider);
@override @override
bool? get isManga => (origin as GetExtensionsStreamProvider).isManga; ItemType get itemType => (origin as GetExtensionsStreamProvider).itemType;
} }
// ignore_for_file: type=lint // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mangayomi/eval/model/m_bridge.dart'; import 'package:mangayomi/eval/model/m_bridge.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart'; import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
@ -13,15 +14,16 @@ class CreateExtension extends StatefulWidget {
} }
class _CreateExtensionState extends State<CreateExtension> { class _CreateExtensionState extends State<CreateExtension> {
bool _isManga = false;
String _name = ""; String _name = "";
String _lang = ""; String _lang = "";
String _baseUrl = ""; String _baseUrl = "";
String _apiUrl = ""; String _apiUrl = "";
String _iconUrl = ""; String _iconUrl = "";
int _sourceTypeIndex = 0; int _sourceTypeIndex = 0;
int _itemTypeIndex = 0;
int _languageIndex = 0; int _languageIndex = 0;
final List<String> _sourceTypes = ["single", "multi", "torrent"]; final List<String> _sourceTypes = ["single", "multi", "torrent"];
final List<String> _itemTypes = ["Manga", "Anime", "Novel"];
final List<String> _languages = ["Dart", "JavaScript"]; final List<String> _languages = ["Dart", "JavaScript"];
SourceCodeLanguage _sourceCodeLanguage = SourceCodeLanguage.dart; SourceCodeLanguage _sourceCodeLanguage = SourceCodeLanguage.dart;
@override @override
@ -129,12 +131,35 @@ class _CreateExtensionState extends State<CreateExtension> {
], ],
), ),
), ),
SwitchListTile( Padding(
title: const Text("isManga"), padding: const EdgeInsets.symmetric(horizontal: 17),
value: _isManga, child: Row(
onChanged: (value) => setState(() { children: [
_isManga = value; const Text("Target"),
}), const SizedBox(width: 20),
Flexible(
child: DropdownButton(
icon: const Icon(Icons.keyboard_arrow_down),
isExpanded: true,
value: _itemTypeIndex,
hint: Text(_itemTypes[_itemTypeIndex],
style: const TextStyle(fontSize: 13)),
items: _itemTypes
.map((e) => DropdownMenuItem(
value: _itemTypes.indexOf(e),
child: Text(e,
style: const TextStyle(fontSize: 13)),
))
.toList(),
onChanged: (v) {
setState(() {
_itemTypeIndex = v!;
});
},
),
),
],
),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
@ -159,7 +184,7 @@ class _CreateExtensionState extends State<CreateExtension> {
apiUrl: _apiUrl, apiUrl: _apiUrl,
iconUrl: _iconUrl, iconUrl: _iconUrl,
typeSource: _sourceTypes[_sourceTypeIndex], typeSource: _sourceTypes[_sourceTypeIndex],
isManga: _isManga, itemType: ItemType.values.elementAt(_itemTypeIndex),
isAdded: true, isAdded: true,
isActive: true, isActive: true,
version: "0.0.1", version: "0.0.1",
@ -252,6 +277,12 @@ class TestSource extends MProvider {
// TODO: implement // TODO: implement
} }
// For novel html content
@override
Future<String> getHtmlContent(String url) async {
// TODO: implement
}
// For anime episode video list // For anime episode video list
@override @override
Future<List<MVideo>> getVideoList(String url) async { Future<List<MVideo>> getVideoList(String url) async {
@ -313,6 +344,10 @@ class DefaultExtension extends MProvider {
async getDetail(url) { async getDetail(url) {
throw new Error("getDetail not implemented"); throw new Error("getDetail not implemented");
} }
// For novel html content
async getHtmlContent(url) {
throw new Error("getHtmlContent not implemented");
}
// For anime episode video list // For anime episode video list
async getVideoList(url) { async getVideoList(url) {
throw new Error("getVideoList not implemented"); throw new Error("getVideoList not implemented");

View file

@ -2,10 +2,12 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/services/fetch_anime_sources.dart'; import 'package:mangayomi/services/fetch_anime_sources.dart';
import 'package:mangayomi/services/fetch_manga_sources.dart'; import 'package:mangayomi/services/fetch_manga_sources.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/services/fetch_novel_sources.dart';
import 'package:mangayomi/services/fetch_sources_list.dart'; import 'package:mangayomi/services/fetch_sources_list.dart';
import 'package:mangayomi/utils/cached_network.dart'; import 'package:mangayomi/utils/cached_network.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart'; import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
@ -48,13 +50,17 @@ class _ExtensionListTileWidgetState
setState(() { setState(() {
_isLoading = true; _isLoading = true;
}); });
widget.source.isManga! widget.source.itemType == ItemType.manga
? await ref.watch(fetchMangaSourcesListProvider( ? await ref.watch(fetchMangaSourcesListProvider(
id: widget.source.id, reFresh: true) id: widget.source.id, reFresh: true)
.future) .future)
: await ref.watch(fetchAnimeSourcesListProvider( : widget.source.itemType == ItemType.anime
id: widget.source.id, reFresh: true) ? await ref.watch(fetchAnimeSourcesListProvider(
.future); id: widget.source.id, reFresh: true)
.future)
: await ref.watch(fetchNovelSourcesListProvider(
id: widget.source.id, reFresh: true)
.future);
if (mounted) { if (mounted) {
setState(() { setState(() {
_isLoading = false; _isLoading = false;
@ -116,13 +122,17 @@ class _ExtensionListTileWidgetState
setState(() { setState(() {
_isLoading = true; _isLoading = true;
}); });
widget.source.isManga! widget.source.itemType == ItemType.manga
? await ref.watch(fetchMangaSourcesListProvider( ? await ref.watch(fetchMangaSourcesListProvider(
id: widget.source.id, reFresh: true) id: widget.source.id, reFresh: true)
.future) .future)
: await ref.watch(fetchAnimeSourcesListProvider( : widget.source.itemType == ItemType.anime
id: widget.source.id, reFresh: true) ? await ref.watch(fetchAnimeSourcesListProvider(
.future); id: widget.source.id, reFresh: true)
.future)
: await ref.watch(fetchNovelSourcesListProvider(
id: widget.source.id, reFresh: true)
.future);
if (mounted) { if (mounted) {
setState(() { setState(() {
_isLoading = false; _isLoading = false;

View file

@ -236,7 +236,7 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
context: context, context: context,
getManga: getMangaDetail, getManga: getMangaDetail,
lang: widget.source.lang!, lang: widget.source.lang!,
isManga: widget.source.isManga ?? true, itemType: widget.source.itemType,
useMaterialRoute: true, useMaterialRoute: true,
source: widget.source.name!); source: widget.source.name!);
}, },

View file

@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:grouped_list/sliver_grouped_list.dart'; import 'package:grouped_list/sliver_grouped_list.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/browse/sources/widgets/source_list_tile.dart'; import 'package:mangayomi/modules/browse/sources/widgets/source_list_tile.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
@ -10,9 +11,9 @@ import 'package:mangayomi/utils/language.dart';
class SourcesScreen extends ConsumerStatefulWidget { class SourcesScreen extends ConsumerStatefulWidget {
final Function(int) tabIndex; final Function(int) tabIndex;
final bool isManga; final ItemType itemType;
const SourcesScreen( const SourcesScreen(
{required this.tabIndex, required this.isManga, super.key}); {required this.tabIndex, required this.itemType, super.key});
@override @override
ConsumerState<SourcesScreen> createState() => _SourcesScreenState(); ConsumerState<SourcesScreen> createState() => _SourcesScreenState();
@ -33,7 +34,7 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
.and() .and()
.isActiveEqualTo(true) .isActiveEqualTo(true)
.and() .and()
.isMangaEqualTo(widget.isManga) .itemTypeEqualTo(widget.itemType)
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData) { if (!snapshot.hasData) {
@ -52,7 +53,7 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: ElevatedButton.icon( child: ElevatedButton.icon(
onPressed: () => onPressed: () =>
widget.tabIndex(widget.isManga ? 2 : 3), widget.tabIndex(widget.itemType == ItemType.manga ? 3 : widget.itemType == ItemType.anime ? 4 : 5),
icon: const Icon(Icons.extension_rounded), icon: const Icon(Icons.extension_rounded),
label: Text(context.l10n.show_extensions)), label: Text(context.l10n.show_extensions)),
) )
@ -91,7 +92,7 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
itemBuilder: (context, Source element) { itemBuilder: (context, Source element) {
return SourceListTile( return SourceListTile(
source: element, source: element,
isManga: widget.isManga, itemType: widget.itemType,
); );
}, },
groupComparator: (group1, group2) => groupComparator: (group1, group2) =>
@ -118,7 +119,7 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
itemBuilder: (context, Source element) { itemBuilder: (context, Source element) {
return SourceListTile( return SourceListTile(
source: element, source: element,
isManga: widget.isManga, itemType: widget.itemType,
); );
}, },
groupComparator: (group1, group2) => groupComparator: (group1, group2) =>
@ -146,7 +147,7 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
itemBuilder: (context, Source element) { itemBuilder: (context, Source element) {
return SourceListTile( return SourceListTile(
source: element, source: element,
isManga: widget.isManga, itemType: widget.itemType,
); );
}, },
groupComparator: (group1, group2) => groupComparator: (group1, group2) =>

View file

@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/cached_network.dart'; import 'package:mangayomi/utils/cached_network.dart';
@ -10,10 +11,10 @@ import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
import 'package:mangayomi/utils/language.dart'; import 'package:mangayomi/utils/language.dart';
class SourceListTile extends StatelessWidget { class SourceListTile extends StatelessWidget {
final bool isManga; final ItemType itemType;
final Source source; final Source source;
const SourceListTile( const SourceListTile(
{super.key, required this.source, required this.isManga}); {super.key, required this.source, required this.itemType});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -23,7 +24,7 @@ class SourceListTile extends StatelessWidget {
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.isMangaEqualTo(isManga) .itemTypeEqualTo(itemType)
.findAllSync(); .findAllSync();
isar.writeTxnSync(() { isar.writeTxnSync(() {
for (var src in sources) { for (var src in sources) {

View file

@ -34,7 +34,7 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen>
@override @override
void initState() { void initState() {
_tabBarController = TabController(length: 2, vsync: this); _tabBarController = TabController(length: 3, vsync: this);
_tabBarController.animateTo(0); _tabBarController.animateTo(0);
_tabBarController.addListener(() { _tabBarController.addListener(() {
setState(() { setState(() {
@ -119,10 +119,14 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen>
List<History> histories = isar.historys List<History> histories = isar.historys
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.chapter((q) => q.manga((q) => .chapter((q) => q.manga((q) => q
q.isMangaEqualTo( .itemTypeEqualTo(_tabBarController
_tabBarController.index == .index ==
0))) 0
? ItemType.manga
: _tabBarController.index == 1
? ItemType.anime
: ItemType.novel)))
.findAllSync() .findAllSync()
.toList(); .toList();
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -150,6 +154,7 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen>
tabs: [ tabs: [
Tab(text: l10n.manga), Tab(text: l10n.manga),
Tab(text: l10n.anime), Tab(text: l10n.anime),
Tab(text: l10n.novel),
], ],
), ),
), ),
@ -157,11 +162,15 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen>
padding: const EdgeInsets.only(top: 10), padding: const EdgeInsets.only(top: 10),
child: TabBarView(controller: _tabBarController, children: [ child: TabBarView(controller: _tabBarController, children: [
HistoryTab( HistoryTab(
isManga: true, itemType: ItemType.manga,
query: _textEditingController.text, query: _textEditingController.text,
), ),
HistoryTab( HistoryTab(
isManga: false, itemType: ItemType.anime,
query: _textEditingController.text,
),
HistoryTab(
itemType: ItemType.novel,
query: _textEditingController.text, query: _textEditingController.text,
) )
]), ]),
@ -173,8 +182,8 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen>
class HistoryTab extends ConsumerStatefulWidget { class HistoryTab extends ConsumerStatefulWidget {
final String query; final String query;
final bool isManga; final ItemType itemType;
const HistoryTab({required this.isManga, required this.query, super.key}); const HistoryTab({required this.itemType, required this.query, super.key});
@override @override
ConsumerState<HistoryTab> createState() => _HistoryTabState(); ConsumerState<HistoryTab> createState() => _HistoryTabState();
@ -185,7 +194,7 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
final history = final history =
ref.watch(getAllHistoryStreamProvider(isManga: widget.isManga)); ref.watch(getAllHistoryStreamProvider(itemType: widget.itemType));
return Scaffold( return Scaffold(
body: history.when( body: history.when(
data: (data) { data: (data) {

View file

@ -10,22 +10,22 @@ part 'isar_providers.g.dart';
@riverpod @riverpod
Stream<List<History>> getAllHistoryStream(Ref ref, Stream<List<History>> getAllHistoryStream(Ref ref,
{required bool isManga}) async* { {required ItemType itemType}) async* {
yield* isar.historys yield* isar.historys
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.chapter((q) => q.manga((q) => q.isMangaEqualTo(isManga))) .chapter((q) => q.manga((q) => q.itemTypeEqualTo(itemType)))
.watch(fireImmediately: true); .watch(fireImmediately: true);
} }
@riverpod @riverpod
Stream<List<Update>> getAllUpdateStream(Ref ref, Stream<List<Update>> getAllUpdateStream(Ref ref,
{required bool isManga}) async* { {required ItemType itemType}) async* {
yield* isar.updates yield* isar.updates
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.chapter((q) => q.manga((q) => q.isMangaEqualTo(isManga))) .chapter((q) => q.manga((q) => q.itemTypeEqualTo(itemType)))
.watch(fireImmediately: true); .watch(fireImmediately: true);
} }

View file

@ -7,7 +7,7 @@ part of 'isar_providers.dart';
// ************************************************************************** // **************************************************************************
String _$getAllHistoryStreamHash() => String _$getAllHistoryStreamHash() =>
r'53b3a7837efab9e7d2808930e5070dbd788c59f8'; r'42048cb03035be55b52fc501fb2309cdb2acfcb8';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -41,10 +41,10 @@ class GetAllHistoryStreamFamily extends Family<AsyncValue<List<History>>> {
/// See also [getAllHistoryStream]. /// See also [getAllHistoryStream].
GetAllHistoryStreamProvider call({ GetAllHistoryStreamProvider call({
required bool isManga, required ItemType itemType,
}) { }) {
return GetAllHistoryStreamProvider( return GetAllHistoryStreamProvider(
isManga: isManga, itemType: itemType,
); );
} }
@ -53,7 +53,7 @@ class GetAllHistoryStreamFamily extends Family<AsyncValue<List<History>>> {
covariant GetAllHistoryStreamProvider provider, covariant GetAllHistoryStreamProvider provider,
) { ) {
return call( return call(
isManga: provider.isManga, itemType: provider.itemType,
); );
} }
@ -77,11 +77,11 @@ class GetAllHistoryStreamProvider
extends AutoDisposeStreamProvider<List<History>> { extends AutoDisposeStreamProvider<List<History>> {
/// See also [getAllHistoryStream]. /// See also [getAllHistoryStream].
GetAllHistoryStreamProvider({ GetAllHistoryStreamProvider({
required bool isManga, required ItemType itemType,
}) : this._internal( }) : this._internal(
(ref) => getAllHistoryStream( (ref) => getAllHistoryStream(
ref as GetAllHistoryStreamRef, ref as GetAllHistoryStreamRef,
isManga: isManga, itemType: itemType,
), ),
from: getAllHistoryStreamProvider, from: getAllHistoryStreamProvider,
name: r'getAllHistoryStreamProvider', name: r'getAllHistoryStreamProvider',
@ -92,7 +92,7 @@ class GetAllHistoryStreamProvider
dependencies: GetAllHistoryStreamFamily._dependencies, dependencies: GetAllHistoryStreamFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
GetAllHistoryStreamFamily._allTransitiveDependencies, GetAllHistoryStreamFamily._allTransitiveDependencies,
isManga: isManga, itemType: itemType,
); );
GetAllHistoryStreamProvider._internal( GetAllHistoryStreamProvider._internal(
@ -102,10 +102,10 @@ class GetAllHistoryStreamProvider
required super.allTransitiveDependencies, required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash, required super.debugGetCreateSourceHash,
required super.from, required super.from,
required this.isManga, required this.itemType,
}) : super.internal(); }) : super.internal();
final bool isManga; final ItemType itemType;
@override @override
Override overrideWith( Override overrideWith(
@ -120,7 +120,7 @@ class GetAllHistoryStreamProvider
dependencies: null, dependencies: null,
allTransitiveDependencies: null, allTransitiveDependencies: null,
debugGetCreateSourceHash: null, debugGetCreateSourceHash: null,
isManga: isManga, itemType: itemType,
), ),
); );
} }
@ -132,13 +132,13 @@ class GetAllHistoryStreamProvider
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is GetAllHistoryStreamProvider && other.isManga == isManga; return other is GetAllHistoryStreamProvider && other.itemType == itemType;
} }
@override @override
int get hashCode { int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode); var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode); hash = _SystemHash.combine(hash, itemType.hashCode);
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
} }
@ -147,8 +147,8 @@ class GetAllHistoryStreamProvider
@Deprecated('Will be removed in 3.0. Use Ref instead') @Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element // ignore: unused_element
mixin GetAllHistoryStreamRef on AutoDisposeStreamProviderRef<List<History>> { mixin GetAllHistoryStreamRef on AutoDisposeStreamProviderRef<List<History>> {
/// The parameter `isManga` of this provider. /// The parameter `itemType` of this provider.
bool get isManga; ItemType get itemType;
} }
class _GetAllHistoryStreamProviderElement class _GetAllHistoryStreamProviderElement
@ -157,11 +157,11 @@ class _GetAllHistoryStreamProviderElement
_GetAllHistoryStreamProviderElement(super.provider); _GetAllHistoryStreamProviderElement(super.provider);
@override @override
bool get isManga => (origin as GetAllHistoryStreamProvider).isManga; ItemType get itemType => (origin as GetAllHistoryStreamProvider).itemType;
} }
String _$getAllUpdateStreamHash() => String _$getAllUpdateStreamHash() =>
r'01f77807c8be11f471b6acee6e7bc358ce600a65'; r'6a20f8feba3010c2ab7a80560f7a7f6cf10c7366';
/// See also [getAllUpdateStream]. /// See also [getAllUpdateStream].
@ProviderFor(getAllUpdateStream) @ProviderFor(getAllUpdateStream)
@ -174,10 +174,10 @@ class GetAllUpdateStreamFamily extends Family<AsyncValue<List<Update>>> {
/// See also [getAllUpdateStream]. /// See also [getAllUpdateStream].
GetAllUpdateStreamProvider call({ GetAllUpdateStreamProvider call({
required bool isManga, required ItemType itemType,
}) { }) {
return GetAllUpdateStreamProvider( return GetAllUpdateStreamProvider(
isManga: isManga, itemType: itemType,
); );
} }
@ -186,7 +186,7 @@ class GetAllUpdateStreamFamily extends Family<AsyncValue<List<Update>>> {
covariant GetAllUpdateStreamProvider provider, covariant GetAllUpdateStreamProvider provider,
) { ) {
return call( return call(
isManga: provider.isManga, itemType: provider.itemType,
); );
} }
@ -210,11 +210,11 @@ class GetAllUpdateStreamProvider
extends AutoDisposeStreamProvider<List<Update>> { extends AutoDisposeStreamProvider<List<Update>> {
/// See also [getAllUpdateStream]. /// See also [getAllUpdateStream].
GetAllUpdateStreamProvider({ GetAllUpdateStreamProvider({
required bool isManga, required ItemType itemType,
}) : this._internal( }) : this._internal(
(ref) => getAllUpdateStream( (ref) => getAllUpdateStream(
ref as GetAllUpdateStreamRef, ref as GetAllUpdateStreamRef,
isManga: isManga, itemType: itemType,
), ),
from: getAllUpdateStreamProvider, from: getAllUpdateStreamProvider,
name: r'getAllUpdateStreamProvider', name: r'getAllUpdateStreamProvider',
@ -225,7 +225,7 @@ class GetAllUpdateStreamProvider
dependencies: GetAllUpdateStreamFamily._dependencies, dependencies: GetAllUpdateStreamFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
GetAllUpdateStreamFamily._allTransitiveDependencies, GetAllUpdateStreamFamily._allTransitiveDependencies,
isManga: isManga, itemType: itemType,
); );
GetAllUpdateStreamProvider._internal( GetAllUpdateStreamProvider._internal(
@ -235,10 +235,10 @@ class GetAllUpdateStreamProvider
required super.allTransitiveDependencies, required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash, required super.debugGetCreateSourceHash,
required super.from, required super.from,
required this.isManga, required this.itemType,
}) : super.internal(); }) : super.internal();
final bool isManga; final ItemType itemType;
@override @override
Override overrideWith( Override overrideWith(
@ -253,7 +253,7 @@ class GetAllUpdateStreamProvider
dependencies: null, dependencies: null,
allTransitiveDependencies: null, allTransitiveDependencies: null,
debugGetCreateSourceHash: null, debugGetCreateSourceHash: null,
isManga: isManga, itemType: itemType,
), ),
); );
} }
@ -265,13 +265,13 @@ class GetAllUpdateStreamProvider
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is GetAllUpdateStreamProvider && other.isManga == isManga; return other is GetAllUpdateStreamProvider && other.itemType == itemType;
} }
@override @override
int get hashCode { int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode); var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode); hash = _SystemHash.combine(hash, itemType.hashCode);
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
} }
@ -280,8 +280,8 @@ class GetAllUpdateStreamProvider
@Deprecated('Will be removed in 3.0. Use Ref instead') @Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element // ignore: unused_element
mixin GetAllUpdateStreamRef on AutoDisposeStreamProviderRef<List<Update>> { mixin GetAllUpdateStreamRef on AutoDisposeStreamProviderRef<List<Update>> {
/// The parameter `isManga` of this provider. /// The parameter `itemType` of this provider.
bool get isManga; ItemType get itemType;
} }
class _GetAllUpdateStreamProviderElement class _GetAllUpdateStreamProviderElement
@ -290,7 +290,7 @@ class _GetAllUpdateStreamProviderElement
_GetAllUpdateStreamProviderElement(super.provider); _GetAllUpdateStreamProviderElement(super.provider);
@override @override
bool get isManga => (origin as GetAllUpdateStreamProvider).isManga; ItemType get itemType => (origin as GetAllUpdateStreamProvider).itemType;
} }
// ignore_for_file: type=lint // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View file

@ -40,8 +40,8 @@ import 'package:mangayomi/modules/widgets/progress_center.dart';
import 'package:mangayomi/utils/global_style.dart'; import 'package:mangayomi/utils/global_style.dart';
class LibraryScreen extends ConsumerStatefulWidget { class LibraryScreen extends ConsumerStatefulWidget {
final bool isManga; final ItemType itemType;
const LibraryScreen({required this.isManga, super.key}); const LibraryScreen({required this.itemType, super.key});
@override @override
ConsumerState<LibraryScreen> createState() => _LibraryScreenState(); ConsumerState<LibraryScreen> createState() => _LibraryScreenState();
@ -83,13 +83,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
final settings = settingsList.first; final settings = settingsList.first;
final categories = final categories =
ref.watch(getMangaCategorieStreamProvider(isManga: widget.isManga)); ref.watch(getMangaCategorieStreamProvider(itemType: widget.itemType));
final withoutCategories = ref.watch( final withoutCategories = ref.watch(
getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga)); getAllMangaWithoutCategoriesStreamProvider(
itemType: widget.itemType));
final showCategoryTabs = ref.watch(libraryShowCategoryTabsStateProvider( final showCategoryTabs = ref.watch(libraryShowCategoryTabsStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final mangaAll = ref.watch( final mangaAll = ref.watch(getAllMangaStreamProvider(
getAllMangaStreamProvider(categoryId: null, isManga: widget.isManga)); categoryId: null, itemType: widget.itemType));
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return Scaffold( return Scaffold(
body: mangaAll.when( body: mangaAll.when(
@ -113,55 +114,63 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
return Consumer(builder: (context, ref, child) { return Consumer(builder: (context, ref, child) {
bool reverse = ref bool reverse = ref
.watch(sortLibraryMangaStateProvider( .watch(sortLibraryMangaStateProvider(
isManga: widget.isManga, settings: settings)) itemType: widget.itemType,
settings: settings))
.reverse!; .reverse!;
final continueReaderBtn = ref.watch( final continueReaderBtn = ref.watch(
libraryShowContinueReadingButtonStateProvider( libraryShowContinueReadingButtonStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType,
settings: settings));
final showNumbersOfItems = ref.watch( final showNumbersOfItems = ref.watch(
libraryShowNumbersOfItemsStateProvider( libraryShowNumbersOfItemsStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType,
settings: settings));
final localSource = ref.watch( final localSource = ref.watch(
libraryLocalSourceStateProvider( libraryLocalSourceStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType,
settings: settings));
final downloadedChapter = ref.watch( final downloadedChapter = ref.watch(
libraryDownloadedChaptersStateProvider( libraryDownloadedChaptersStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType,
settings: settings));
final language = ref.watch( final language = ref.watch(
libraryLanguageStateProvider( libraryLanguageStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType,
settings: settings));
final displayType = ref.watch( final displayType = ref.watch(
libraryDisplayTypeStateProvider( libraryDisplayTypeStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType,
settings: settings));
final isNotFiltering = ref.watch( final isNotFiltering = ref.watch(
mangasFilterResultStateProvider( mangasFilterResultStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)); settings: settings));
final downloadFilterType = ref.watch( final downloadFilterType = ref.watch(
mangaFilterDownloadedStateProvider( mangaFilterDownloadedStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)); settings: settings));
final unreadFilterType = ref.watch( final unreadFilterType = ref.watch(
mangaFilterUnreadStateProvider( mangaFilterUnreadStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)); settings: settings));
final startedFilterType = ref.watch( final startedFilterType = ref.watch(
mangaFilterStartedStateProvider( mangaFilterStartedStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)); settings: settings));
final bookmarkedFilterType = ref.watch( final bookmarkedFilterType = ref.watch(
mangaFilterBookmarkedStateProvider( mangaFilterBookmarkedStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)); settings: settings));
final sortType = ref final sortType = ref
.watch(sortLibraryMangaStateProvider( .watch(sortLibraryMangaStateProvider(
isManga: widget.isManga, settings: settings)) itemType: widget.itemType,
settings: settings))
.index as int; .index as int;
final numberOfItemsList = _filterAndSortManga( final numberOfItemsList = _filterAndSortManga(
data: man, data: man,
@ -364,53 +373,53 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
return Consumer(builder: (context, ref, child) { return Consumer(builder: (context, ref, child) {
bool reverse = ref bool reverse = ref
.watch(sortLibraryMangaStateProvider( .watch(sortLibraryMangaStateProvider(
isManga: widget.isManga, settings: settings)) itemType: widget.itemType, settings: settings))
.reverse!; .reverse!;
final continueReaderBtn = ref.watch( final continueReaderBtn = ref.watch(
libraryShowContinueReadingButtonStateProvider( libraryShowContinueReadingButtonStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final showNumbersOfItems = ref.watch( final showNumbersOfItems = ref.watch(
libraryShowNumbersOfItemsStateProvider( libraryShowNumbersOfItemsStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final localSource = ref.watch( final localSource = ref.watch(
libraryLocalSourceStateProvider( libraryLocalSourceStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final downloadedChapter = ref.watch( final downloadedChapter = ref.watch(
libraryDownloadedChaptersStateProvider( libraryDownloadedChaptersStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final language = ref.watch(libraryLanguageStateProvider( final language = ref.watch(libraryLanguageStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final displayType = ref.watch( final displayType = ref.watch(
libraryDisplayTypeStateProvider( libraryDisplayTypeStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final isNotFiltering = ref.watch( final isNotFiltering = ref.watch(
mangasFilterResultStateProvider( mangasFilterResultStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)); settings: settings));
final downloadFilterType = ref.watch( final downloadFilterType = ref.watch(
mangaFilterDownloadedStateProvider( mangaFilterDownloadedStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)); settings: settings));
final unreadFilterType = ref.watch( final unreadFilterType = ref.watch(
mangaFilterUnreadStateProvider( mangaFilterUnreadStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)); settings: settings));
final startedFilterType = ref.watch( final startedFilterType = ref.watch(
mangaFilterStartedStateProvider( mangaFilterStartedStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)); settings: settings));
final bookmarkedFilterType = ref.watch( final bookmarkedFilterType = ref.watch(
mangaFilterBookmarkedStateProvider( mangaFilterBookmarkedStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)); settings: settings));
final sortType = ref final sortType = ref
.watch(sortLibraryMangaStateProvider( .watch(sortLibraryMangaStateProvider(
isManga: widget.isManga, settings: settings)) itemType: widget.itemType, settings: settings))
.index; .index;
final numberOfItemsList = _filterAndSortManga( final numberOfItemsList = _filterAndSortManga(
data: man, data: man,
@ -518,9 +527,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
.set(); .set();
ref.invalidate( ref.invalidate(
getAllMangaWithoutCategoriesStreamProvider( getAllMangaWithoutCategoriesStreamProvider(
isManga: widget.isManga)); itemType: widget.itemType));
ref.invalidate(getAllMangaStreamProvider( ref.invalidate(getAllMangaStreamProvider(
categoryId: null, isManga: widget.isManga)); categoryId: null, itemType: widget.itemType));
}, },
child: Icon( child: Icon(
Icons.done_all_sharp, Icons.done_all_sharp,
@ -545,9 +554,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
.set(); .set();
ref.invalidate( ref.invalidate(
getAllMangaWithoutCategoriesStreamProvider( getAllMangaWithoutCategoriesStreamProvider(
isManga: widget.isManga)); itemType: widget.itemType));
ref.invalidate(getAllMangaStreamProvider( ref.invalidate(getAllMangaStreamProvider(
categoryId: null, isManga: widget.isManga)); categoryId: null, itemType: widget.itemType));
}, },
child: Icon( child: Icon(
Icons.remove_done_sharp, Icons.remove_done_sharp,
@ -611,10 +620,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required int categoryId, required int categoryId,
required Settings settings}) { required Settings settings}) {
final mangas = ref.watch(getAllMangaStreamProvider( final mangas = ref.watch(getAllMangaStreamProvider(
categoryId: categoryId, isManga: widget.isManga)); categoryId: categoryId, itemType: widget.itemType));
final sortType = ref final sortType = ref
.watch(sortLibraryMangaStateProvider( .watch(sortLibraryMangaStateProvider(
isManga: widget.isManga, settings: settings)) itemType: widget.itemType, settings: settings))
.index; .index;
return mangas.when( return mangas.when(
data: (data) { data: (data) {
@ -661,10 +670,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required Settings settings}) { required Settings settings}) {
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
final mangas = ref.watch(getAllMangaStreamProvider( final mangas = ref.watch(getAllMangaStreamProvider(
categoryId: categoryId, isManga: widget.isManga)); categoryId: categoryId, itemType: widget.itemType));
final sortType = ref final sortType = ref
.watch(sortLibraryMangaStateProvider( .watch(sortLibraryMangaStateProvider(
isManga: widget.isManga, settings: settings)) itemType: widget.itemType, settings: settings))
.index; .index;
final mangaIdsList = ref.watch(mangasListStateProvider); final mangaIdsList = ref.watch(mangasListStateProvider);
return Scaffold( return Scaffold(
@ -702,7 +711,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
language: language, language: language,
mangaIdsList: mangaIdsList, mangaIdsList: mangaIdsList,
localSource: localSource, localSource: localSource,
isManga: widget.isManga, itemType: widget.itemType,
), ),
); );
} }
@ -733,13 +742,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required Settings settings}) { required Settings settings}) {
final sortType = ref final sortType = ref
.watch(sortLibraryMangaStateProvider( .watch(sortLibraryMangaStateProvider(
isManga: widget.isManga, settings: settings)) itemType: widget.itemType, settings: settings))
.index; .index;
final manga = withouCategories final manga = withouCategories
? ref.watch( ? ref.watch(getAllMangaWithoutCategoriesStreamProvider(
getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga)) itemType: widget.itemType))
: ref.watch(getAllMangaStreamProvider( : ref.watch(getAllMangaStreamProvider(
categoryId: null, isManga: widget.isManga)); categoryId: null, itemType: widget.itemType));
final mangaIdsList = ref.watch(mangasListStateProvider); final mangaIdsList = ref.watch(mangasListStateProvider);
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return manga.when( return manga.when(
@ -776,7 +785,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
language: language, language: language,
mangaIdsList: mangaIdsList, mangaIdsList: mangaIdsList,
localSource: localSource, localSource: localSource,
isManga: widget.isManga, itemType: widget.itemType,
), ),
); );
} }
@ -954,7 +963,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.forMangaEqualTo(widget.isManga) .forItemTypeEqualTo(widget.itemType)
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
return AlertDialog( return AlertDialog(
@ -1004,10 +1013,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
children: [ children: [
TextButton( TextButton(
onPressed: () { onPressed: () {
context.push("/categories", extra: ( context.push("/categories",
true, extra: (true, widget.itemType));
widget.isManga ? 0 : 1
));
Navigator.pop(context); Navigator.pop(context);
}, },
child: Text(l10n.edit)), child: Text(l10n.edit)),
@ -1057,10 +1064,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
children: [ children: [
TextButton( TextButton(
onPressed: () { onPressed: () {
context.push("/categories", extra: ( context.push("/categories",
true, extra: (true, widget.itemType));
widget.isManga ? 0 : 1
));
Navigator.pop(context); Navigator.pop(context);
}, },
child: Text( child: Text(
@ -1115,7 +1120,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
type: fromLibList.isNotEmpty ? 1 : 0, type: fromLibList.isNotEmpty ? 1 : 0,
), ),
ListTileChapterFilter( ListTileChapterFilter(
label: widget.isManga label: widget.itemType != ItemType.anime
? l10n.downloaded_chapters ? l10n.downloaded_chapters
: l10n.downloaded_episodes, : l10n.downloaded_episodes,
onTap: () { onTap: () {
@ -1272,28 +1277,30 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
ListTileChapterFilter( ListTileChapterFilter(
label: l10n.downloaded, label: l10n.downloaded,
type: ref.watch(mangaFilterDownloadedStateProvider( type: ref.watch(mangaFilterDownloadedStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)), settings: settings)),
onTap: () { onTap: () {
ref ref
.read(mangaFilterDownloadedStateProvider( .read(mangaFilterDownloadedStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings) settings: settings)
.notifier) .notifier)
.update(); .update();
}), }),
ListTileChapterFilter( ListTileChapterFilter(
label: widget.isManga ? l10n.unread : l10n.unwatched, label: widget.itemType != ItemType.anime
? l10n.unread
: l10n.unwatched,
type: ref.watch(mangaFilterUnreadStateProvider( type: ref.watch(mangaFilterUnreadStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)), settings: settings)),
onTap: () { onTap: () {
ref ref
.read(mangaFilterUnreadStateProvider( .read(mangaFilterUnreadStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings) settings: settings)
.notifier) .notifier)
@ -1302,13 +1309,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
ListTileChapterFilter( ListTileChapterFilter(
label: l10n.started, label: l10n.started,
type: ref.watch(mangaFilterStartedStateProvider( type: ref.watch(mangaFilterStartedStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)), settings: settings)),
onTap: () { onTap: () {
ref ref
.read(mangaFilterStartedStateProvider( .read(mangaFilterStartedStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings) settings: settings)
.notifier) .notifier)
@ -1317,14 +1324,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
ListTileChapterFilter( ListTileChapterFilter(
label: l10n.bookmarked, label: l10n.bookmarked,
type: ref.watch(mangaFilterBookmarkedStateProvider( type: ref.watch(mangaFilterBookmarkedStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings)), settings: settings)),
onTap: () { onTap: () {
setState(() { setState(() {
ref ref
.read(mangaFilterBookmarkedStateProvider( .read(mangaFilterBookmarkedStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
mangaList: _entries, mangaList: _entries,
settings: settings) settings: settings)
.notifier) .notifier)
@ -1337,11 +1344,11 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
Consumer(builder: (context, ref, chil) { Consumer(builder: (context, ref, chil) {
final reverse = ref final reverse = ref
.read(sortLibraryMangaStateProvider( .read(sortLibraryMangaStateProvider(
isManga: widget.isManga, settings: settings) itemType: widget.itemType, settings: settings)
.notifier) .notifier)
.isReverse(); .isReverse();
final reverseChapter = ref.watch(sortLibraryMangaStateProvider( final reverseChapter = ref.watch(sortLibraryMangaStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
return Column( return Column(
children: [ children: [
for (var i = 0; i < 7; i++) for (var i = 0; i < 7; i++)
@ -1351,7 +1358,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
onTap: () { onTap: () {
ref ref
.read(sortLibraryMangaStateProvider( .read(sortLibraryMangaStateProvider(
isManga: widget.isManga, settings: settings) itemType: widget.itemType, settings: settings)
.notifier) .notifier)
.set(i); .set(i);
}, },
@ -1362,25 +1369,25 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
}), }),
Consumer(builder: (context, ref, chil) { Consumer(builder: (context, ref, chil) {
final display = ref.watch(libraryDisplayTypeStateProvider( final display = ref.watch(libraryDisplayTypeStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final displayV = ref.read(libraryDisplayTypeStateProvider( final displayV = ref.read(libraryDisplayTypeStateProvider(
isManga: widget.isManga, settings: settings) itemType: widget.itemType, settings: settings)
.notifier); .notifier);
final showCategoryTabs = ref.watch(libraryShowCategoryTabsStateProvider( final showCategoryTabs = ref.watch(libraryShowCategoryTabsStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final continueReaderBtn = ref.watch( final continueReaderBtn = ref.watch(
libraryShowContinueReadingButtonStateProvider( libraryShowContinueReadingButtonStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final showNumbersOfItems = ref.watch( final showNumbersOfItems = ref.watch(
libraryShowNumbersOfItemsStateProvider( libraryShowNumbersOfItemsStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final downloadedChapter = ref.watch( final downloadedChapter = ref.watch(
libraryDownloadedChaptersStateProvider( libraryDownloadedChaptersStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final language = ref.watch(libraryLanguageStateProvider( final language = ref.watch(libraryLanguageStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
final localSource = ref.watch(libraryLocalSourceStateProvider( final localSource = ref.watch(libraryLocalSourceStateProvider(
isManga: widget.isManga, settings: settings)); itemType: widget.itemType, settings: settings));
return SingleChildScrollView( return SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
child: Column( child: Column(
@ -1453,7 +1460,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
Consumer( Consumer(
builder: (context, ref, child) { builder: (context, ref, child) {
final gridSize = ref.watch(libraryGridSizeStateProvider( final gridSize = ref.watch(libraryGridSizeStateProvider(
isManga: widget.isManga)) ?? itemType: widget.itemType)) ??
0; 0;
return Padding( return Padding(
padding: const EdgeInsets.only(left: 8, right: 8, top: 10), padding: const EdgeInsets.only(left: 8, right: 8, top: 10),
@ -1486,14 +1493,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
HapticFeedback.vibrate(); HapticFeedback.vibrate();
ref ref
.read(libraryGridSizeStateProvider( .read(libraryGridSizeStateProvider(
isManga: widget.isManga) itemType: widget.itemType)
.notifier) .notifier)
.set(value.toInt()); .set(value.toInt());
}, },
onChangeEnd: (value) { onChangeEnd: (value) {
ref ref
.read(libraryGridSizeStateProvider( .read(libraryGridSizeStateProvider(
isManga: widget.isManga) itemType: widget.itemType)
.notifier) .notifier)
.set(value.toInt(), end: true); .set(value.toInt(), end: true);
}, },
@ -1518,14 +1525,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
child: Column( child: Column(
children: [ children: [
ListTileChapterFilter( ListTileChapterFilter(
label: widget.isManga label: widget.itemType != ItemType.anime
? l10n.downloaded_chapters ? l10n.downloaded_chapters
: l10n.downloaded_episodes, : l10n.downloaded_episodes,
type: downloadedChapter ? 1 : 0, type: downloadedChapter ? 1 : 0,
onTap: () { onTap: () {
ref ref
.read(libraryDownloadedChaptersStateProvider( .read(libraryDownloadedChaptersStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
settings: settings) settings: settings)
.notifier) .notifier)
.set(!downloadedChapter); .set(!downloadedChapter);
@ -1536,7 +1543,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
onTap: () { onTap: () {
ref ref
.read(libraryLanguageStateProvider( .read(libraryLanguageStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
settings: settings) settings: settings)
.notifier) .notifier)
.set(!language); .set(!language);
@ -1547,13 +1554,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
onTap: () { onTap: () {
ref ref
.read(libraryLocalSourceStateProvider( .read(libraryLocalSourceStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
settings: settings) settings: settings)
.notifier) .notifier)
.set(!localSource); .set(!localSource);
}), }),
ListTileChapterFilter( ListTileChapterFilter(
label: widget.isManga label: widget.itemType != ItemType.anime
? l10n.show_continue_reading_buttons ? l10n.show_continue_reading_buttons
: l10n.show_continue_watching_buttons, : l10n.show_continue_watching_buttons,
type: continueReaderBtn ? 1 : 0, type: continueReaderBtn ? 1 : 0,
@ -1561,7 +1568,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
ref ref
.read( .read(
libraryShowContinueReadingButtonStateProvider( libraryShowContinueReadingButtonStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
settings: settings) settings: settings)
.notifier) .notifier)
.set(!continueReaderBtn); .set(!continueReaderBtn);
@ -1585,7 +1592,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
onTap: () { onTap: () {
ref ref
.read(libraryShowCategoryTabsStateProvider( .read(libraryShowCategoryTabsStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
settings: settings) settings: settings)
.notifier) .notifier)
.set(!showCategoryTabs); .set(!showCategoryTabs);
@ -1596,7 +1603,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
onTap: () { onTap: () {
ref ref
.read(libraryShowNumbersOfItemsStateProvider( .read(libraryShowNumbersOfItemsStateProvider(
isManga: widget.isManga, itemType: widget.itemType,
settings: settings) settings: settings)
.notifier) .notifier)
.set(!showNumbersOfItems); .set(!showNumbersOfItems);
@ -1616,15 +1623,23 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
if (index == 0) { if (index == 0) {
return l10n.alphabetically; return l10n.alphabetically;
} else if (index == 1) { } else if (index == 1) {
return widget.isManga ? l10n.last_read : l10n.last_watched; return widget.itemType != ItemType.anime
? l10n.last_read
: l10n.last_watched;
} else if (index == 2) { } else if (index == 2) {
return l10n.last_update_check; return l10n.last_update_check;
} else if (index == 3) { } else if (index == 3) {
return widget.isManga ? l10n.unread_count : l10n.unwatched_count; return widget.itemType != ItemType.anime
? l10n.unread_count
: l10n.unwatched_count;
} else if (index == 4) { } else if (index == 4) {
return widget.isManga ? l10n.total_chapters : l10n.total_episodes; return widget.itemType != ItemType.anime
? l10n.total_chapters
: l10n.total_episodes;
} else if (index == 5) { } else if (index == 5) {
return widget.isManga ? l10n.latest_chapter : l10n.latest_episode; return widget.itemType != ItemType.anime
? l10n.latest_chapter
: l10n.latest_episode;
} }
return l10n.date_added; return l10n.date_added;
} }
@ -1641,10 +1656,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
final isLongPressed = ref.watch(isLongPressedMangaStateProvider); final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
final mangaIdsList = ref.watch(mangasListStateProvider); final mangaIdsList = ref.watch(mangasListStateProvider);
final manga = categoryId == null final manga = categoryId == null
? ref.watch( ? ref.watch(getAllMangaWithoutCategoriesStreamProvider(
getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga)) itemType: widget.itemType))
: ref.watch(getAllMangaStreamProvider( : ref.watch(getAllMangaStreamProvider(
categoryId: categoryId, isManga: widget.isManga)); categoryId: categoryId, itemType: widget.itemType));
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return PreferredSize( return PreferredSize(
preferredSize: Size.fromHeight(AppBar().preferredSize.height), preferredSize: Size.fromHeight(AppBar().preferredSize.height),
@ -1714,7 +1729,11 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
: Row( : Row(
children: [ children: [
Text( Text(
widget.isManga ? l10n.manga : l10n.anime, widget.itemType == ItemType.manga
? l10n.manga
: widget.itemType == ItemType.anime
? l10n.anime
: l10n.novel,
style: style:
TextStyle(color: Theme.of(context).hintColor), TextStyle(color: Theme.of(context).hintColor),
), ),
@ -1790,7 +1809,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
value: 1, child: Text(l10n.open_random_entry)), value: 1, child: Text(l10n.open_random_entry)),
PopupMenuItem<int>( PopupMenuItem<int>(
value: 2, child: Text(l10n.import)), value: 2, child: Text(l10n.import)),
if (!widget.isManga) if (widget.itemType == ItemType.anime)
PopupMenuItem<int>( PopupMenuItem<int>(
value: 3, child: Text(l10n.torrent_stream)), value: 3, child: Text(l10n.torrent_stream)),
]; ];
@ -1813,8 +1832,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
source: randomManga.source!); source: randomManga.source!);
}); });
} else if (value == 2) { } else if (value == 2) {
_importLocal(context, widget.isManga); _importLocal(context, widget.itemType);
} else if (value == 3 && !widget.isManga) { } else if (value == 3 &&
widget.itemType == ItemType.anime) {
addTorrent(context); addTorrent(context);
} }
}), }),
@ -1823,7 +1843,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
} }
} }
void _importLocal(BuildContext context, bool isManga) { void _importLocal(BuildContext context, ItemType itemType) {
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
bool isLoading = false; bool isLoading = false;
showDialog( showDialog(
@ -1857,7 +1877,7 @@ void _importLocal(BuildContext context, bool isManga) {
}); });
await ref.watch( await ref.watch(
importArchivesFromFileProvider( importArchivesFromFileProvider(
isManga: isManga, itemType: itemType,
null, null,
init: true) init: true)
.future); .future);
@ -1872,7 +1892,7 @@ void _importLocal(BuildContext context, bool isManga) {
children: [ children: [
const Icon(Icons.archive_outlined), const Icon(Icons.archive_outlined),
Text( Text(
"${l10n.import_files} ( ${isManga ? ".zip, .cbz" : ".mp4, .mkv, .avi, and more"} )", "${l10n.import_files} ( ${itemType == ItemType.manga ? ".zip, .cbz" : ".mp4, .mkv, .avi, and more"} )",
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context)
.textTheme .textTheme

View file

@ -32,7 +32,7 @@ Future addTorrentFromUrlOrFromFile(Ref ref, Manga? mManga,
favorite: true, favorite: true,
source: 'torrent', source: 'torrent',
author: '', author: '',
isManga: false, itemType: ItemType.anime,
genre: [], genre: [],
imageUrl: '', imageUrl: '',
lang: '', lang: '',

View file

@ -7,7 +7,7 @@ part of 'add_torrent.dart';
// ************************************************************************** // **************************************************************************
String _$addTorrentFromUrlOrFromFileHash() => String _$addTorrentFromUrlOrFromFileHash() =>
r'8102259b30765a5c5cc57870f5c583bd5d421eee'; r'11cc239bb8b517326f9a005b0c89dd5eb1127099';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {

View file

@ -8,14 +8,14 @@ part 'isar_providers.g.dart';
@riverpod @riverpod
Stream<List<Manga>> getAllMangaStream(Ref ref, Stream<List<Manga>> getAllMangaStream(Ref ref,
{required int? categoryId, required bool? isManga}) async* { {required int? categoryId, required ItemType itemType}) async* {
yield* categoryId == null yield* categoryId == null
? isar.mangas ? isar.mangas
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.favoriteEqualTo(true) .favoriteEqualTo(true)
.and() .and()
.isMangaEqualTo(isManga) .itemTypeEqualTo(itemType)
.watch(fireImmediately: true) .watch(fireImmediately: true)
: isar.mangas : isar.mangas
.filter() .filter()
@ -24,26 +24,26 @@ Stream<List<Manga>> getAllMangaStream(Ref ref,
.categoriesIsNotEmpty() .categoriesIsNotEmpty()
.categoriesElementEqualTo(categoryId) .categoriesElementEqualTo(categoryId)
.and() .and()
.isMangaEqualTo(isManga) .itemTypeEqualTo(itemType)
.watch(fireImmediately: true); .watch(fireImmediately: true);
} }
@riverpod @riverpod
Stream<List<Manga>> getAllMangaWithoutCategoriesStream(Ref ref, Stream<List<Manga>> getAllMangaWithoutCategoriesStream(Ref ref,
{required bool? isManga}) async* { {required ItemType itemType}) async* {
yield* isar.mangas yield* isar.mangas
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.favoriteEqualTo(true) .favoriteEqualTo(true)
.categoriesIsEmpty() .categoriesIsEmpty()
.and() .and()
.isMangaEqualTo(isManga) .itemTypeEqualTo(itemType)
.or() .or()
.idIsNotNull() .idIsNotNull()
.categoriesIsNull() .categoriesIsNull()
.favoriteEqualTo(true) .favoriteEqualTo(true)
.and() .and()
.isMangaEqualTo(isManga) .itemTypeEqualTo(itemType)
.watch(fireImmediately: true); .watch(fireImmediately: true);
} }

View file

@ -6,7 +6,7 @@ part of 'isar_providers.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$getAllMangaStreamHash() => r'1c0b5442ae86b2fa899d509a555f5d375f0ff79a'; String _$getAllMangaStreamHash() => r'5e86a22a68ca1a52aefa9c0bc675d284369beac5';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -41,11 +41,11 @@ class GetAllMangaStreamFamily extends Family<AsyncValue<List<Manga>>> {
/// See also [getAllMangaStream]. /// See also [getAllMangaStream].
GetAllMangaStreamProvider call({ GetAllMangaStreamProvider call({
required int? categoryId, required int? categoryId,
required bool? isManga, required ItemType itemType,
}) { }) {
return GetAllMangaStreamProvider( return GetAllMangaStreamProvider(
categoryId: categoryId, categoryId: categoryId,
isManga: isManga, itemType: itemType,
); );
} }
@ -55,7 +55,7 @@ class GetAllMangaStreamFamily extends Family<AsyncValue<List<Manga>>> {
) { ) {
return call( return call(
categoryId: provider.categoryId, categoryId: provider.categoryId,
isManga: provider.isManga, itemType: provider.itemType,
); );
} }
@ -79,12 +79,12 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
/// See also [getAllMangaStream]. /// See also [getAllMangaStream].
GetAllMangaStreamProvider({ GetAllMangaStreamProvider({
required int? categoryId, required int? categoryId,
required bool? isManga, required ItemType itemType,
}) : this._internal( }) : this._internal(
(ref) => getAllMangaStream( (ref) => getAllMangaStream(
ref as GetAllMangaStreamRef, ref as GetAllMangaStreamRef,
categoryId: categoryId, categoryId: categoryId,
isManga: isManga, itemType: itemType,
), ),
from: getAllMangaStreamProvider, from: getAllMangaStreamProvider,
name: r'getAllMangaStreamProvider', name: r'getAllMangaStreamProvider',
@ -96,7 +96,7 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
allTransitiveDependencies: allTransitiveDependencies:
GetAllMangaStreamFamily._allTransitiveDependencies, GetAllMangaStreamFamily._allTransitiveDependencies,
categoryId: categoryId, categoryId: categoryId,
isManga: isManga, itemType: itemType,
); );
GetAllMangaStreamProvider._internal( GetAllMangaStreamProvider._internal(
@ -107,11 +107,11 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
required super.debugGetCreateSourceHash, required super.debugGetCreateSourceHash,
required super.from, required super.from,
required this.categoryId, required this.categoryId,
required this.isManga, required this.itemType,
}) : super.internal(); }) : super.internal();
final int? categoryId; final int? categoryId;
final bool? isManga; final ItemType itemType;
@override @override
Override overrideWith( Override overrideWith(
@ -127,7 +127,7 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
allTransitiveDependencies: null, allTransitiveDependencies: null,
debugGetCreateSourceHash: null, debugGetCreateSourceHash: null,
categoryId: categoryId, categoryId: categoryId,
isManga: isManga, itemType: itemType,
), ),
); );
} }
@ -141,14 +141,14 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
bool operator ==(Object other) { bool operator ==(Object other) {
return other is GetAllMangaStreamProvider && return other is GetAllMangaStreamProvider &&
other.categoryId == categoryId && other.categoryId == categoryId &&
other.isManga == isManga; other.itemType == itemType;
} }
@override @override
int get hashCode { int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode); var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, categoryId.hashCode); hash = _SystemHash.combine(hash, categoryId.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode); hash = _SystemHash.combine(hash, itemType.hashCode);
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
} }
@ -160,8 +160,8 @@ mixin GetAllMangaStreamRef on AutoDisposeStreamProviderRef<List<Manga>> {
/// The parameter `categoryId` of this provider. /// The parameter `categoryId` of this provider.
int? get categoryId; int? get categoryId;
/// The parameter `isManga` of this provider. /// The parameter `itemType` of this provider.
bool? get isManga; ItemType get itemType;
} }
class _GetAllMangaStreamProviderElement class _GetAllMangaStreamProviderElement
@ -172,11 +172,11 @@ class _GetAllMangaStreamProviderElement
@override @override
int? get categoryId => (origin as GetAllMangaStreamProvider).categoryId; int? get categoryId => (origin as GetAllMangaStreamProvider).categoryId;
@override @override
bool? get isManga => (origin as GetAllMangaStreamProvider).isManga; ItemType get itemType => (origin as GetAllMangaStreamProvider).itemType;
} }
String _$getAllMangaWithoutCategoriesStreamHash() => String _$getAllMangaWithoutCategoriesStreamHash() =>
r'78076f291274b7defd9567e55314002d9aeecab1'; r'61ea54070c7e87a45aeabce5fd21366faaf4ae6d';
/// See also [getAllMangaWithoutCategoriesStream]. /// See also [getAllMangaWithoutCategoriesStream].
@ProviderFor(getAllMangaWithoutCategoriesStream) @ProviderFor(getAllMangaWithoutCategoriesStream)
@ -191,10 +191,10 @@ class GetAllMangaWithoutCategoriesStreamFamily
/// See also [getAllMangaWithoutCategoriesStream]. /// See also [getAllMangaWithoutCategoriesStream].
GetAllMangaWithoutCategoriesStreamProvider call({ GetAllMangaWithoutCategoriesStreamProvider call({
required bool? isManga, required ItemType itemType,
}) { }) {
return GetAllMangaWithoutCategoriesStreamProvider( return GetAllMangaWithoutCategoriesStreamProvider(
isManga: isManga, itemType: itemType,
); );
} }
@ -203,7 +203,7 @@ class GetAllMangaWithoutCategoriesStreamFamily
covariant GetAllMangaWithoutCategoriesStreamProvider provider, covariant GetAllMangaWithoutCategoriesStreamProvider provider,
) { ) {
return call( return call(
isManga: provider.isManga, itemType: provider.itemType,
); );
} }
@ -227,11 +227,11 @@ class GetAllMangaWithoutCategoriesStreamProvider
extends AutoDisposeStreamProvider<List<Manga>> { extends AutoDisposeStreamProvider<List<Manga>> {
/// See also [getAllMangaWithoutCategoriesStream]. /// See also [getAllMangaWithoutCategoriesStream].
GetAllMangaWithoutCategoriesStreamProvider({ GetAllMangaWithoutCategoriesStreamProvider({
required bool? isManga, required ItemType itemType,
}) : this._internal( }) : this._internal(
(ref) => getAllMangaWithoutCategoriesStream( (ref) => getAllMangaWithoutCategoriesStream(
ref as GetAllMangaWithoutCategoriesStreamRef, ref as GetAllMangaWithoutCategoriesStreamRef,
isManga: isManga, itemType: itemType,
), ),
from: getAllMangaWithoutCategoriesStreamProvider, from: getAllMangaWithoutCategoriesStreamProvider,
name: r'getAllMangaWithoutCategoriesStreamProvider', name: r'getAllMangaWithoutCategoriesStreamProvider',
@ -242,7 +242,7 @@ class GetAllMangaWithoutCategoriesStreamProvider
dependencies: GetAllMangaWithoutCategoriesStreamFamily._dependencies, dependencies: GetAllMangaWithoutCategoriesStreamFamily._dependencies,
allTransitiveDependencies: GetAllMangaWithoutCategoriesStreamFamily allTransitiveDependencies: GetAllMangaWithoutCategoriesStreamFamily
._allTransitiveDependencies, ._allTransitiveDependencies,
isManga: isManga, itemType: itemType,
); );
GetAllMangaWithoutCategoriesStreamProvider._internal( GetAllMangaWithoutCategoriesStreamProvider._internal(
@ -252,10 +252,10 @@ class GetAllMangaWithoutCategoriesStreamProvider
required super.allTransitiveDependencies, required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash, required super.debugGetCreateSourceHash,
required super.from, required super.from,
required this.isManga, required this.itemType,
}) : super.internal(); }) : super.internal();
final bool? isManga; final ItemType itemType;
@override @override
Override overrideWith( Override overrideWith(
@ -271,7 +271,7 @@ class GetAllMangaWithoutCategoriesStreamProvider
dependencies: null, dependencies: null,
allTransitiveDependencies: null, allTransitiveDependencies: null,
debugGetCreateSourceHash: null, debugGetCreateSourceHash: null,
isManga: isManga, itemType: itemType,
), ),
); );
} }
@ -284,13 +284,13 @@ class GetAllMangaWithoutCategoriesStreamProvider
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is GetAllMangaWithoutCategoriesStreamProvider && return other is GetAllMangaWithoutCategoriesStreamProvider &&
other.isManga == isManga; other.itemType == itemType;
} }
@override @override
int get hashCode { int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode); var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode); hash = _SystemHash.combine(hash, itemType.hashCode);
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
} }
@ -300,8 +300,8 @@ class GetAllMangaWithoutCategoriesStreamProvider
// ignore: unused_element // ignore: unused_element
mixin GetAllMangaWithoutCategoriesStreamRef mixin GetAllMangaWithoutCategoriesStreamRef
on AutoDisposeStreamProviderRef<List<Manga>> { on AutoDisposeStreamProviderRef<List<Manga>> {
/// The parameter `isManga` of this provider. /// The parameter `itemType` of this provider.
bool? get isManga; ItemType get itemType;
} }
class _GetAllMangaWithoutCategoriesStreamProviderElement class _GetAllMangaWithoutCategoriesStreamProviderElement
@ -310,8 +310,8 @@ class _GetAllMangaWithoutCategoriesStreamProviderElement
_GetAllMangaWithoutCategoriesStreamProviderElement(super.provider); _GetAllMangaWithoutCategoriesStreamProviderElement(super.provider);
@override @override
bool? get isManga => ItemType get itemType =>
(origin as GetAllMangaWithoutCategoriesStreamProvider).isManga; (origin as GetAllMangaWithoutCategoriesStreamProvider).itemType;
} }
String _$getSettingsStreamHash() => r'c5a51e0e3473b25d2365025832a27ed2cc029b27'; String _$getSettingsStreamHash() => r'c5a51e0e3473b25d2365025832a27ed2cc029b27';

View file

@ -12,8 +12,15 @@ part 'library_state_provider.g.dart';
@riverpod @riverpod
class LibraryDisplayTypeState extends _$LibraryDisplayTypeState { class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
@override @override
DisplayType build({required bool isManga, required Settings settings}) { DisplayType build({required ItemType itemType, required Settings settings}) {
return isManga ? settings.displayType : settings.animeDisplayType; switch (itemType) {
case ItemType.manga:
return settings.displayType;
case ItemType.anime:
return settings.animeDisplayType;
default:
return settings.novelDisplayType;
}
} }
String getLibraryDisplayTypeName( String getLibraryDisplayTypeName(
@ -31,10 +38,16 @@ class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
Settings appSettings = Settings(); Settings appSettings = Settings();
state = displayType; state = displayType;
if (isManga) {
appSettings = settings..displayType = displayType; switch (itemType) {
} else { case ItemType.manga:
appSettings = settings..animeDisplayType = displayType; appSettings = settings..displayType = displayType;
break;
case ItemType.anime:
appSettings = settings..animeDisplayType = displayType;
break;
default:
appSettings = settings..novelDisplayType = displayType;
} }
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -46,8 +59,15 @@ class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
@riverpod @riverpod
class LibraryGridSizeState extends _$LibraryGridSizeState { class LibraryGridSizeState extends _$LibraryGridSizeState {
@override @override
int? build({required bool isManga}) { int? build({required ItemType itemType}) {
return isManga ? settings.mangaGridSize : settings.animeGridSize; switch (itemType) {
case ItemType.manga:
return settings.mangaGridSize;
case ItemType.anime:
return settings.animeGridSize;
default:
return settings.novelGridSize;
}
} }
Settings get settings { Settings get settings {
@ -59,10 +79,15 @@ class LibraryGridSizeState extends _$LibraryGridSizeState {
state = value; state = value;
if (end) { if (end) {
if (isManga) { switch (itemType) {
appSettings = settings..mangaGridSize = value; case ItemType.manga:
} else { appSettings = settings..mangaGridSize = value;
appSettings = settings..animeGridSize = value; break;
case ItemType.anime:
appSettings = settings..animeGridSize = value;
break;
default:
appSettings = settings..novelGridSize = value;
} }
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -77,24 +102,34 @@ class MangaFilterDownloadedState extends _$MangaFilterDownloadedState {
@override @override
int build( int build(
{required List<Manga> mangaList, {required List<Manga> mangaList,
required bool isManga, required ItemType itemType,
required Settings settings}) { required Settings settings}) {
state = getType(); state = getType();
return getType(); return getType();
} }
int getType() { int getType() {
return isManga switch (itemType) {
? settings.libraryFilterMangasDownloadType! case ItemType.manga:
: settings.libraryFilterAnimeDownloadType ?? 0; return settings.libraryFilterMangasDownloadType!;
case ItemType.anime:
return settings.libraryFilterAnimeDownloadType!;
default:
return settings.libraryFilterNovelDownloadType ?? 0;
}
} }
void setType(int type) { void setType(int type) {
Settings appSettings = Settings(); Settings appSettings = Settings();
if (isManga) { switch (itemType) {
appSettings = settings..libraryFilterMangasDownloadType = type; case ItemType.manga:
} else { appSettings = settings..libraryFilterMangasDownloadType = type;
appSettings = settings..libraryFilterAnimeDownloadType = type; break;
case ItemType.anime:
appSettings = settings..libraryFilterAnimeDownloadType = type;
break;
default:
appSettings = settings..libraryFilterNovelDownloadType = type;
} }
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(appSettings); isar.settings.putSync(appSettings);
@ -118,24 +153,34 @@ class MangaFilterUnreadState extends _$MangaFilterUnreadState {
@override @override
int build( int build(
{required List<Manga> mangaList, {required List<Manga> mangaList,
required bool isManga, required ItemType itemType,
required Settings settings}) { required Settings settings}) {
state = getType(); state = getType();
return getType(); return getType();
} }
int getType() { int getType() {
return isManga switch (itemType) {
? settings.libraryFilterMangasUnreadType! case ItemType.manga:
: settings.libraryFilterAnimeUnreadType ?? 0; return settings.libraryFilterMangasUnreadType!;
case ItemType.anime:
return settings.libraryFilterAnimeUnreadType!;
default:
return settings.libraryFilterNovelUnreadType ?? 0;
}
} }
void setType(int type) { void setType(int type) {
Settings appSettings = Settings(); Settings appSettings = Settings();
if (isManga) { switch (itemType) {
appSettings = settings..libraryFilterMangasUnreadType = type; case ItemType.manga:
} else { appSettings = settings..libraryFilterMangasUnreadType = type;
appSettings = settings..libraryFilterAnimeUnreadType = type; break;
case ItemType.anime:
appSettings = settings..libraryFilterAnimeUnreadType = type;
break;
default:
appSettings = settings..libraryFilterNovelUnreadType = type;
} }
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(appSettings); isar.settings.putSync(appSettings);
@ -208,24 +253,34 @@ class MangaFilterStartedState extends _$MangaFilterStartedState {
@override @override
int build( int build(
{required List<Manga> mangaList, {required List<Manga> mangaList,
required bool isManga, required ItemType itemType,
required Settings settings}) { required Settings settings}) {
state = getType(); state = getType();
return getType(); return getType();
} }
int getType() { int getType() {
return isManga switch (itemType) {
? settings.libraryFilterMangasStartedType! case ItemType.manga:
: settings.libraryFilterAnimeStartedType ?? 0; return settings.libraryFilterMangasStartedType!;
case ItemType.anime:
return settings.libraryFilterAnimeStartedType!;
default:
return settings.libraryFilterNovelStartedType ?? 0;
}
} }
void setType(int type) { void setType(int type) {
Settings appSettings = Settings(); Settings appSettings = Settings();
if (isManga) { switch (itemType) {
appSettings = settings..libraryFilterMangasStartedType = type; case ItemType.manga:
} else { appSettings = settings..libraryFilterMangasStartedType = type;
appSettings = settings..libraryFilterAnimeStartedType = type; break;
case ItemType.anime:
appSettings = settings..libraryFilterAnimeStartedType = type;
break;
default:
appSettings = settings..libraryFilterNovelStartedType = type;
} }
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(appSettings); isar.settings.putSync(appSettings);
@ -298,24 +353,34 @@ class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState {
@override @override
int build( int build(
{required List<Manga> mangaList, {required List<Manga> mangaList,
required bool isManga, required ItemType itemType,
required Settings settings}) { required Settings settings}) {
state = getType(); state = getType();
return getType(); return getType();
} }
int getType() { int getType() {
return isManga switch (itemType) {
? settings.libraryFilterMangasBookMarkedType! case ItemType.manga:
: settings.libraryFilterAnimeBookMarkedType ?? 0; return settings.libraryFilterMangasBookMarkedType!;
case ItemType.anime:
return settings.libraryFilterAnimeBookMarkedType!;
default:
return settings.libraryFilterNovelBookMarkedType ?? 0;
}
} }
void setType(int type) { void setType(int type) {
Settings appSettings = Settings(); Settings appSettings = Settings();
if (isManga) { switch (itemType) {
appSettings = settings..libraryFilterMangasBookMarkedType = type; case ItemType.manga:
} else { appSettings = settings..libraryFilterMangasBookMarkedType = type;
appSettings = settings..libraryFilterAnimeBookMarkedType = type; break;
case ItemType.anime:
appSettings = settings..libraryFilterAnimeBookMarkedType = type;
break;
default:
appSettings = settings..libraryFilterNovelBookMarkedType = type;
} }
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(appSettings); isar.settings.putSync(appSettings);
@ -388,16 +453,16 @@ class MangasFilterResultState extends _$MangasFilterResultState {
@override @override
bool build( bool build(
{required List<Manga> mangaList, {required List<Manga> mangaList,
required bool isManga, required ItemType itemType,
required Settings settings}) { required Settings settings}) {
final downloadFilterType = ref.watch(mangaFilterDownloadedStateProvider( final downloadFilterType = ref.watch(mangaFilterDownloadedStateProvider(
mangaList: mangaList, isManga: isManga, settings: settings)); mangaList: mangaList, itemType: itemType, settings: settings));
final unreadFilterType = ref.watch(mangaFilterUnreadStateProvider( final unreadFilterType = ref.watch(mangaFilterUnreadStateProvider(
mangaList: mangaList, isManga: isManga, settings: settings)); mangaList: mangaList, itemType: itemType, settings: settings));
final startedFilterType = ref.watch(mangaFilterStartedStateProvider( final startedFilterType = ref.watch(mangaFilterStartedStateProvider(
mangaList: mangaList, isManga: isManga, settings: settings)); mangaList: mangaList, itemType: itemType, settings: settings));
final bookmarkedFilterType = ref.watch(mangaFilterBookmarkedStateProvider( final bookmarkedFilterType = ref.watch(mangaFilterBookmarkedStateProvider(
mangaList: mangaList, isManga: isManga, settings: settings)); mangaList: mangaList, itemType: itemType, settings: settings));
return downloadFilterType == 0 && return downloadFilterType == 0 &&
unreadFilterType == 0 && unreadFilterType == 0 &&
startedFilterType == 0 && startedFilterType == 0 &&
@ -408,18 +473,28 @@ class MangasFilterResultState extends _$MangasFilterResultState {
@riverpod @riverpod
class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState { class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
@override @override
bool build({required bool isManga, required Settings settings}) { bool build({required ItemType itemType, required Settings settings}) {
return isManga switch (itemType) {
? settings.libraryShowCategoryTabs! case ItemType.manga:
: settings.animeLibraryShowCategoryTabs ?? false; return settings.libraryShowCategoryTabs!;
case ItemType.anime:
return settings.animeLibraryShowCategoryTabs!;
default:
return settings.novelLibraryShowCategoryTabs ?? false;
}
} }
void set(bool value) { void set(bool value) {
Settings appSettings = Settings(); Settings appSettings = Settings();
if (isManga) { switch (itemType) {
appSettings = settings..libraryShowCategoryTabs = value; case ItemType.manga:
} else { appSettings = settings..libraryShowCategoryTabs = value;
appSettings = settings..animeLibraryShowCategoryTabs = value; break;
case ItemType.anime:
appSettings = settings..animeLibraryShowCategoryTabs = value;
break;
default:
appSettings = settings..novelLibraryShowCategoryTabs = value;
} }
state = value; state = value;
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -431,18 +506,28 @@ class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
@riverpod @riverpod
class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState { class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
@override @override
bool build({required bool isManga, required Settings settings}) { bool build({required ItemType itemType, required Settings settings}) {
return isManga switch (itemType) {
? settings.libraryDownloadedChapters! case ItemType.manga:
: settings.animeLibraryDownloadedChapters ?? false; return settings.libraryDownloadedChapters!;
case ItemType.anime:
return settings.animeLibraryDownloadedChapters!;
default:
return settings.novelLibraryDownloadedChapters ?? false;
}
} }
void set(bool value) { void set(bool value) {
Settings appSettings = Settings(); Settings appSettings = Settings();
if (isManga) { switch (itemType) {
appSettings = settings..libraryDownloadedChapters = value; case ItemType.manga:
} else { appSettings = settings..libraryDownloadedChapters = value;
appSettings = settings..animeLibraryDownloadedChapters = value; break;
case ItemType.anime:
appSettings = settings..animeLibraryDownloadedChapters = value;
break;
default:
appSettings = settings..novelLibraryDownloadedChapters = value;
} }
state = value; state = value;
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -454,18 +539,28 @@ class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
@riverpod @riverpod
class LibraryLanguageState extends _$LibraryLanguageState { class LibraryLanguageState extends _$LibraryLanguageState {
@override @override
bool build({required bool isManga, required Settings settings}) { bool build({required ItemType itemType, required Settings settings}) {
return isManga switch (itemType) {
? settings.libraryShowLanguage! case ItemType.manga:
: settings.animeLibraryShowLanguage ?? false; return settings.libraryShowLanguage!;
case ItemType.anime:
return settings.animeLibraryShowLanguage!;
default:
return settings.novelLibraryShowLanguage ?? false;
}
} }
void set(bool value) { void set(bool value) {
Settings appSettings = Settings(); Settings appSettings = Settings();
if (isManga) { switch (itemType) {
appSettings = settings..libraryShowLanguage = value; case ItemType.manga:
} else { appSettings = settings..libraryShowLanguage = value;
appSettings = settings..animeLibraryShowLanguage = value; break;
case ItemType.anime:
appSettings = settings..animeLibraryShowLanguage = value;
break;
default:
appSettings = settings..novelLibraryShowLanguage = value;
} }
state = value; state = value;
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -477,18 +572,28 @@ class LibraryLanguageState extends _$LibraryLanguageState {
@riverpod @riverpod
class LibraryLocalSourceState extends _$LibraryLocalSourceState { class LibraryLocalSourceState extends _$LibraryLocalSourceState {
@override @override
bool build({required bool isManga, required Settings settings}) { bool build({required ItemType itemType, required Settings settings}) {
return isManga switch (itemType) {
? settings.libraryLocalSource ?? false case ItemType.manga:
: settings.animeLibraryLocalSource ?? false; return settings.libraryLocalSource ?? false;
case ItemType.anime:
return settings.animeLibraryLocalSource ?? false;
default:
return settings.novelLibraryLocalSource ?? false;
}
} }
void set(bool value) { void set(bool value) {
Settings appSettings = Settings(); Settings appSettings = Settings();
if (isManga) { switch (itemType) {
appSettings = settings..libraryLocalSource = value; case ItemType.manga:
} else { appSettings = settings..libraryLocalSource = value;
appSettings = settings..animeLibraryLocalSource = value; break;
case ItemType.anime:
appSettings = settings..animeLibraryLocalSource = value;
break;
default:
appSettings = settings..novelLibraryLocalSource = value;
} }
state = value; state = value;
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -500,18 +605,28 @@ class LibraryLocalSourceState extends _$LibraryLocalSourceState {
@riverpod @riverpod
class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState { class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
@override @override
bool build({required bool isManga, required Settings settings}) { bool build({required ItemType itemType, required Settings settings}) {
return isManga switch (itemType) {
? settings.libraryShowNumbersOfItems! case ItemType.manga:
: settings.animeLibraryShowNumbersOfItems ?? false; return settings.libraryShowNumbersOfItems!;
case ItemType.anime:
return settings.animeLibraryShowNumbersOfItems!;
default:
return settings.novelLibraryShowNumbersOfItems ?? false;
}
} }
void set(bool value) { void set(bool value) {
Settings appSettings = Settings(); Settings appSettings = Settings();
if (isManga) { switch (itemType) {
appSettings = settings..libraryShowNumbersOfItems = value; case ItemType.manga:
} else { appSettings = settings..libraryShowNumbersOfItems = value;
appSettings = settings..animeLibraryShowNumbersOfItems = value; break;
case ItemType.anime:
appSettings = settings..animeLibraryShowNumbersOfItems = value;
break;
default:
appSettings = settings..novelLibraryShowNumbersOfItems = value;
} }
state = value; state = value;
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -524,18 +639,28 @@ class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
class LibraryShowContinueReadingButtonState class LibraryShowContinueReadingButtonState
extends _$LibraryShowContinueReadingButtonState { extends _$LibraryShowContinueReadingButtonState {
@override @override
bool build({required bool isManga, required Settings settings}) { bool build({required ItemType itemType, required Settings settings}) {
return isManga switch (itemType) {
? settings.libraryShowContinueReadingButton! case ItemType.manga:
: settings.animeLibraryShowContinueReadingButton ?? false; return settings.libraryShowContinueReadingButton!;
case ItemType.anime:
return settings.animeLibraryShowContinueReadingButton!;
default:
return settings.novelLibraryShowContinueReadingButton ?? false;
}
} }
void set(bool value) { void set(bool value) {
Settings appSettings = Settings(); Settings appSettings = Settings();
if (isManga) { switch (itemType) {
appSettings = settings..libraryShowContinueReadingButton = value; case ItemType.manga:
} else { appSettings = settings..libraryShowContinueReadingButton = value;
appSettings = settings..animeLibraryShowContinueReadingButton = value; break;
case ItemType.anime:
appSettings = settings..animeLibraryShowContinueReadingButton = value;
break;
default:
appSettings = settings..novelLibraryShowContinueReadingButton = value;
} }
state = value; state = value;
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -547,10 +672,15 @@ class LibraryShowContinueReadingButtonState
@riverpod @riverpod
class SortLibraryMangaState extends _$SortLibraryMangaState { class SortLibraryMangaState extends _$SortLibraryMangaState {
@override @override
SortLibraryManga build({required bool isManga, required Settings settings}) { SortLibraryManga build({required ItemType itemType, required Settings settings}) {
return isManga switch (itemType) {
? settings.sortLibraryManga ?? SortLibraryManga() case ItemType.manga:
: settings.sortLibraryAnime ?? SortLibraryManga(); return settings.sortLibraryManga ?? SortLibraryManga();
case ItemType.anime:
return settings.sortLibraryAnime ?? SortLibraryManga();
default:
return settings.sortLibraryNovel ?? SortLibraryManga();
}
} }
void update(bool reverse, int index) { void update(bool reverse, int index) {
@ -559,10 +689,15 @@ class SortLibraryMangaState extends _$SortLibraryMangaState {
..index = index ..index = index
..reverse = state.index == index ? !reverse : reverse; ..reverse = state.index == index ? !reverse : reverse;
if (isManga) { switch (itemType) {
appSettings = settings..sortLibraryManga = value; case ItemType.manga:
} else { appSettings = settings..sortLibraryManga = value;
appSettings = settings..sortLibraryAnime = value; break;
case ItemType.anime:
appSettings = settings..sortLibraryAnime = value;
break;
default:
appSettings = settings..sortLibraryNovel = value;
} }
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(appSettings); isar.settings.putSync(appSettings);

File diff suppressed because it is too large Load diff

View file

@ -11,11 +11,11 @@ part 'local_archive.g.dart';
@riverpod @riverpod
Future importArchivesFromFile(Ref ref, Manga? mManga, Future importArchivesFromFile(Ref ref, Manga? mManga,
{required bool isManga, required bool init}) async { {required ItemType itemType, required bool init}) async {
FilePickerResult? result = await FilePicker.platform.pickFiles( FilePickerResult? result = await FilePicker.platform.pickFiles(
allowMultiple: true, allowMultiple: true,
type: FileType.custom, type: FileType.custom,
allowedExtensions: isManga allowedExtensions: itemType == ItemType.manga
? ['cbz', 'zip'] ? ['cbz', 'zip']
: ['mp4', 'mov', 'avi', 'flv', 'wmv', 'mpeg', 'mkv']); : ['mp4', 'mov', 'avi', 'flv', 'wmv', 'mpeg', 'mkv']);
if (result != null) { if (result != null) {
@ -25,7 +25,7 @@ Future importArchivesFromFile(Ref ref, Manga? mManga,
favorite: true, favorite: true,
source: 'archive', source: 'archive',
author: '', author: '',
isManga: isManga, itemType: itemType,
genre: [], genre: [],
imageUrl: '', imageUrl: '',
lang: '', lang: '',
@ -39,20 +39,20 @@ Future importArchivesFromFile(Ref ref, Manga? mManga,
artist: '', artist: '',
); );
for (var file in result.files.reversed.toList()) { for (var file in result.files.reversed.toList()) {
(String, LocalExtensionType, Uint8List, String)? data = isManga (String, LocalExtensionType, Uint8List, String)? data = itemType == ItemType.manga
? await ref.watch(getArchivesDataFromFileProvider(file.path!).future) ? await ref.watch(getArchivesDataFromFileProvider(file.path!).future)
: null; : null;
String name = _getName(file.path!); String name = _getName(file.path!);
if (init) { if (init) {
manga.customCoverImage = isManga ? data!.$3 : null; manga.customCoverImage = itemType == ItemType.manga ? data!.$3 : null;
} }
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.mangas.putSync(manga); isar.mangas.putSync(manga);
final chapters = Chapter( final chapters = Chapter(
name: isManga ? data!.$1 : name, name: itemType == ItemType.manga ? data!.$1 : name,
archivePath: isManga ? data!.$4 : file.path, archivePath: itemType == ItemType.manga ? data!.$4 : file.path,
mangaId: manga.id) mangaId: manga.id)
..manga.value = manga; ..manga.value = manga;
isar.chapters.putSync(chapters); isar.chapters.putSync(chapters);

View file

@ -7,7 +7,7 @@ part of 'local_archive.dart';
// ************************************************************************** // **************************************************************************
String _$importArchivesFromFileHash() => String _$importArchivesFromFileHash() =>
r'8be95f0947ab5247e3305a355a6f17f0aaecad00'; r'8e6e592c927ad080e93d54dac1144ef8637a7e52';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -42,12 +42,12 @@ class ImportArchivesFromFileFamily extends Family<AsyncValue> {
/// See also [importArchivesFromFile]. /// See also [importArchivesFromFile].
ImportArchivesFromFileProvider call( ImportArchivesFromFileProvider call(
Manga? mManga, { Manga? mManga, {
required bool isManga, required ItemType itemType,
required bool init, required bool init,
}) { }) {
return ImportArchivesFromFileProvider( return ImportArchivesFromFileProvider(
mManga, mManga,
isManga: isManga, itemType: itemType,
init: init, init: init,
); );
} }
@ -58,7 +58,7 @@ class ImportArchivesFromFileFamily extends Family<AsyncValue> {
) { ) {
return call( return call(
provider.mManga, provider.mManga,
isManga: provider.isManga, itemType: provider.itemType,
init: provider.init, init: provider.init,
); );
} }
@ -84,13 +84,13 @@ class ImportArchivesFromFileProvider
/// See also [importArchivesFromFile]. /// See also [importArchivesFromFile].
ImportArchivesFromFileProvider( ImportArchivesFromFileProvider(
Manga? mManga, { Manga? mManga, {
required bool isManga, required ItemType itemType,
required bool init, required bool init,
}) : this._internal( }) : this._internal(
(ref) => importArchivesFromFile( (ref) => importArchivesFromFile(
ref as ImportArchivesFromFileRef, ref as ImportArchivesFromFileRef,
mManga, mManga,
isManga: isManga, itemType: itemType,
init: init, init: init,
), ),
from: importArchivesFromFileProvider, from: importArchivesFromFileProvider,
@ -103,7 +103,7 @@ class ImportArchivesFromFileProvider
allTransitiveDependencies: allTransitiveDependencies:
ImportArchivesFromFileFamily._allTransitiveDependencies, ImportArchivesFromFileFamily._allTransitiveDependencies,
mManga: mManga, mManga: mManga,
isManga: isManga, itemType: itemType,
init: init, init: init,
); );
@ -115,12 +115,12 @@ class ImportArchivesFromFileProvider
required super.debugGetCreateSourceHash, required super.debugGetCreateSourceHash,
required super.from, required super.from,
required this.mManga, required this.mManga,
required this.isManga, required this.itemType,
required this.init, required this.init,
}) : super.internal(); }) : super.internal();
final Manga? mManga; final Manga? mManga;
final bool isManga; final ItemType itemType;
final bool init; final bool init;
@override @override
@ -137,7 +137,7 @@ class ImportArchivesFromFileProvider
allTransitiveDependencies: null, allTransitiveDependencies: null,
debugGetCreateSourceHash: null, debugGetCreateSourceHash: null,
mManga: mManga, mManga: mManga,
isManga: isManga, itemType: itemType,
init: init, init: init,
), ),
); );
@ -152,7 +152,7 @@ class ImportArchivesFromFileProvider
bool operator ==(Object other) { bool operator ==(Object other) {
return other is ImportArchivesFromFileProvider && return other is ImportArchivesFromFileProvider &&
other.mManga == mManga && other.mManga == mManga &&
other.isManga == isManga && other.itemType == itemType &&
other.init == init; other.init == init;
} }
@ -160,7 +160,7 @@ class ImportArchivesFromFileProvider
int get hashCode { int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode); var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, mManga.hashCode); hash = _SystemHash.combine(hash, mManga.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode); hash = _SystemHash.combine(hash, itemType.hashCode);
hash = _SystemHash.combine(hash, init.hashCode); hash = _SystemHash.combine(hash, init.hashCode);
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
@ -173,8 +173,8 @@ mixin ImportArchivesFromFileRef on AutoDisposeFutureProviderRef<Object?> {
/// The parameter `mManga` of this provider. /// The parameter `mManga` of this provider.
Manga? get mManga; Manga? get mManga;
/// The parameter `isManga` of this provider. /// The parameter `itemType` of this provider.
bool get isManga; ItemType get itemType;
/// The parameter `init` of this provider. /// The parameter `init` of this provider.
bool get init; bool get init;
@ -188,7 +188,7 @@ class _ImportArchivesFromFileProviderElement
@override @override
Manga? get mManga => (origin as ImportArchivesFromFileProvider).mManga; Manga? get mManga => (origin as ImportArchivesFromFileProvider).mManga;
@override @override
bool get isManga => (origin as ImportArchivesFromFileProvider).isManga; ItemType get itemType => (origin as ImportArchivesFromFileProvider).itemType;
@override @override
bool get init => (origin as ImportArchivesFromFileProvider).init; bool get init => (origin as ImportArchivesFromFileProvider).init;
} }

View file

@ -29,7 +29,7 @@ class LibraryGridViewWidget extends StatefulWidget {
final bool downloadedChapter; final bool downloadedChapter;
final bool continueReaderBtn; final bool continueReaderBtn;
final bool localSource; final bool localSource;
final bool isManga; final ItemType itemType;
const LibraryGridViewWidget( const LibraryGridViewWidget(
{super.key, {super.key,
required this.entriesManga, required this.entriesManga,
@ -40,7 +40,7 @@ class LibraryGridViewWidget extends StatefulWidget {
required this.continueReaderBtn, required this.continueReaderBtn,
required this.mangaIdsList, required this.mangaIdsList,
required this.localSource, required this.localSource,
required this.isManga}); required this.itemType});
@override @override
State<LibraryGridViewWidget> createState() => _LibraryGridViewWidgetState(); State<LibraryGridViewWidget> createState() => _LibraryGridViewWidgetState();
@ -51,10 +51,10 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Consumer(builder: (context, ref, child) { return Consumer(builder: (context, ref, child) {
final isLongPressed = ref.watch(isLongPressedMangaStateProvider); final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
final isManga = widget.isManga; final itemType = widget.itemType;
final gridSize = final gridSize =
ref.watch(libraryGridSizeStateProvider(isManga: isManga)); ref.watch(libraryGridSizeStateProvider(itemType: itemType));
return GridViewWidget( return GridViewWidget(
gridSize: gridSize, gridSize: gridSize,
childAspectRatio: widget.isComfortableGrid ? 0.642 : 0.69, childAspectRatio: widget.isComfortableGrid ? 0.642 : 0.69,
@ -97,9 +97,9 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
mangaM: entry, mangaM: entry,
source: entry.source!); source: entry.source!);
ref.invalidate(getAllMangaWithoutCategoriesStreamProvider( ref.invalidate(getAllMangaWithoutCategoriesStreamProvider(
isManga: widget.isManga)); itemType: widget.itemType));
ref.invalidate(getAllMangaStreamProvider( ref.invalidate(getAllMangaStreamProvider(
categoryId: null, isManga: widget.isManga)); categoryId: null, itemType: widget.itemType));
} }
}, },
onLongPress: () { onLongPress: () {
@ -279,7 +279,7 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
.idIsNotNull() .idIsNotNull()
.and() .and()
.chapter((q) => q.manga((q) => .chapter((q) => q.manga((q) =>
q.isMangaEqualTo(entry.isManga!))) q.itemTypeEqualTo(entry.itemType)))
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && if (snapshot.hasData &&

View file

@ -59,9 +59,9 @@ class LibraryListViewWidget extends StatelessWidget {
mangaM: entry, mangaM: entry,
source: entry.source!); source: entry.source!);
ref.invalidate(getAllMangaWithoutCategoriesStreamProvider( ref.invalidate(getAllMangaWithoutCategoriesStreamProvider(
isManga: entry.isManga)); itemType: entry.itemType));
ref.invalidate(getAllMangaStreamProvider( ref.invalidate(getAllMangaStreamProvider(
categoryId: null, isManga: entry.isManga)); categoryId: null, itemType: entry.itemType));
} }
}, },
onLongPress: () { onLongPress: () {
@ -264,7 +264,7 @@ class LibraryListViewWidget extends StatelessWidget {
.idIsNotNull() .idIsNotNull()
.and() .and()
.chapter((q) => q.manga((q) => .chapter((q) => q.manga((q) =>
q.isMangaEqualTo(entry.isManga!))) q.itemTypeEqualTo(entry.itemType)))
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && if (snapshot.hasData &&

View file

@ -55,14 +55,15 @@ class MainScreen extends ConsumerWidget {
routerCurrentLocationStateProvider(context), routerCurrentLocationStateProvider(context),
); );
bool isReadingScreen = bool isReadingScreen =
location == '/mangareaderview' || location == '/animePlayerView'; location == '/mangaReaderView' || location == '/animePlayerView' || location == '/novelReaderView';
int currentIndex = switch (location) { int currentIndex = switch (location) {
null || '/MangaLibrary' => 0, null || '/MangaLibrary' => 0,
'/AnimeLibrary' => 1, '/AnimeLibrary' => 1,
'/updates' => 2, '/NovelLibrary' => 2,
'/history' => 3, '/updates' => 3,
'/browse' => 4, '/history' => 4,
_ => 5, '/browse' => 5,
_ => 6,
}; };
final incognitoMode = ref.watch(incognitoModeStateProvider); final incognitoMode = ref.watch(incognitoModeStateProvider);
@ -111,6 +112,7 @@ class MainScreen extends ConsumerWidget {
null => 100, null => 100,
!= '/MangaLibrary' && != '/MangaLibrary' &&
!= '/AnimeLibrary' && != '/AnimeLibrary' &&
!= '/NovelLibrary' &&
!= '/history' && != '/history' &&
!= '/updates' && != '/updates' &&
!= '/browse' && != '/browse' &&
@ -150,6 +152,15 @@ class MainScreen extends ConsumerWidget {
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
top: 5), top: 5),
child: Text(l10n.anime))), child: Text(l10n.anime))),
NavigationRailDestination(
selectedIcon: const Icon(
Icons.local_library),
icon: const Icon(Icons
.local_library_outlined),
label: Padding(
padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.novel))),
NavigationRailDestination( NavigationRailDestination(
selectedIcon: selectedIcon:
const Icon(Icons.new_releases), const Icon(Icons.new_releases),
@ -206,9 +217,10 @@ class MainScreen extends ConsumerWidget {
final fn = switch (newIndex) { final fn = switch (newIndex) {
0 => route.go('/MangaLibrary'), 0 => route.go('/MangaLibrary'),
1 => route.go('/AnimeLibrary'), 1 => route.go('/AnimeLibrary'),
2 => route.go('/updates'), 2 => route.go('/NovelLibrary'),
3 => route.go('/history'), 3 => route.go('/updates'),
4 => route.go('/browse'), 4 => route.go('/history'),
5 => route.go('/browse'),
_ => route.go('/more'), _ => route.go('/more'),
}; };
fn; fn;
@ -242,6 +254,7 @@ class MainScreen extends ConsumerWidget {
null => null, null => null,
!= '/MangaLibrary' && != '/MangaLibrary' &&
!= '/AnimeLibrary' && != '/AnimeLibrary' &&
!= '/NovelLibrary' &&
!= '/history' && != '/history' &&
!= '/updates' && != '/updates' &&
!= '/browse' && != '/browse' &&
@ -272,6 +285,12 @@ class MainScreen extends ConsumerWidget {
icon: const Icon( icon: const Icon(
Icons.video_collection_outlined), Icons.video_collection_outlined),
label: l10n.anime), label: l10n.anime),
NavigationDestination(
selectedIcon:
const Icon(Icons.local_library),
icon: const Icon(
Icons.local_library_outlined),
label: l10n.novel),
Stack( Stack(
children: [ children: [
NavigationDestination( NavigationDestination(
@ -311,9 +330,10 @@ class MainScreen extends ConsumerWidget {
final fn = switch (newIndex) { final fn = switch (newIndex) {
0 => route.go('/MangaLibrary'), 0 => route.go('/MangaLibrary'),
1 => route.go('/AnimeLibrary'), 1 => route.go('/AnimeLibrary'),
2 => route.go('/updates'), 2 => route.go('/NovelLibrary'),
3 => route.go('/history'), 3 => route.go('/updates'),
4 => route.go('/browse'), 4 => route.go('/history'),
5 => route.go('/browse'),
_ => route.go('/more'), _ => route.go('/more'),
}; };
fn; fn;

View file

@ -21,10 +21,8 @@ Future<void> migration(Ref ref) async {
.chapterIdIsNull() .chapterIdIsNull()
.or() .or()
.idIsNotNull() .idIsNotNull()
.isMangaIsNull()
.findAllSync(); .findAllSync();
final tracks = final tracks = isar.tracks.filter().idIsNotNull().findAllSync();
isar.tracks.filter().idIsNotNull().isMangaIsNull().findAllSync();
isar.writeTxnSync(() { isar.writeTxnSync(() {
//mangaId in chapter //mangaId in chapter
@ -40,14 +38,17 @@ Future<void> migration(Ref ref) async {
//chapterId and isManga in History //chapterId and isManga in History
for (var history in histories) { for (var history in histories) {
final chapterId = history.chapter.value?.id; final chapterId = history.chapter.value?.id;
final isManga = history.chapter.value?.manga.value?.isManga; final itemType =
history.chapter.value?.manga.value?.itemType ?? ItemType.manga;
isar.historys.putSync(history isar.historys.putSync(history
..chapterId = chapterId ..chapterId = chapterId
..isManga = isManga); ..itemType = itemType);
} }
// isManga in Track // isManga in Track
for (var track in tracks) { for (var track in tracks) {
final isManga = isar.mangas.getSync(track.mangaId!)?.isManga; final isManga =
(isar.mangas.getSync(track.mangaId!)?.itemType ?? ItemType.manga) ==
ItemType.manga;
isar.tracks.putSync(track..isManga = isManga); isar.tracks.putSync(track..isManga = isManga);
} }
}); });

View file

@ -6,7 +6,7 @@ part of 'migration.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$migrationHash() => r'a302c6da3c1545c952a28e76a6d0b7af3fde1e7a'; String _$migrationHash() => r'403da626b6a797854dde7ae77b4ea452300c40e6';
/// See also [migration]. /// See also [migration].
@ProviderFor(migration) @ProviderFor(migration)

View file

@ -59,7 +59,7 @@ class MangaDetailView extends ConsumerStatefulWidget {
final Manga? manga; final Manga? manga;
final bool sourceExist; final bool sourceExist;
final Function(bool) checkForUpdate; final Function(bool) checkForUpdate;
final bool isManga; final ItemType itemType;
const MangaDetailView( const MangaDetailView(
{super.key, {super.key,
@ -70,7 +70,7 @@ class MangaDetailView extends ConsumerStatefulWidget {
required this.sourceExist, required this.sourceExist,
required this.manga, required this.manga,
required this.checkForUpdate, required this.checkForUpdate,
required this.isManga}); required this.itemType});
@override @override
ConsumerState<MangaDetailView> createState() => _MangaDetailViewState(); ConsumerState<MangaDetailView> createState() => _MangaDetailViewState();
@ -382,30 +382,35 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
return [ return [
PopupMenuItem<int>( PopupMenuItem<int>(
value: 0, value: 0,
child: Text(widget.isManga child: Text(widget.itemType !=
ItemType.anime
? context.l10n.next_chapter ? context.l10n.next_chapter
: context.l10n.next_episode)), : context.l10n.next_episode)),
PopupMenuItem<int>( PopupMenuItem<int>(
value: 1, value: 1,
child: Text(widget.isManga child: Text(widget.itemType !=
ItemType.anime
? context.l10n.next_5_chapters ? context.l10n.next_5_chapters
: context : context
.l10n.next_5_episodes)), .l10n.next_5_episodes)),
PopupMenuItem<int>( PopupMenuItem<int>(
value: 2, value: 2,
child: Text(widget.isManga child: Text(widget.itemType !=
ItemType.anime
? context.l10n.next_10_chapters ? context.l10n.next_10_chapters
: context : context
.l10n.next_10_episodes)), .l10n.next_10_episodes)),
PopupMenuItem<int>( PopupMenuItem<int>(
value: 3, value: 3,
child: Text(widget.isManga child: Text(widget.itemType !=
ItemType.anime
? context.l10n.next_25_chapters ? context.l10n.next_25_chapters
: context : context
.l10n.next_25_episodes)), .l10n.next_25_episodes)),
PopupMenuItem<int>( PopupMenuItem<int>(
value: 4, value: 4,
child: Text(widget.isManga child: Text(widget.itemType !=
ItemType.anime
? context.l10n.unread ? context.l10n.unread
: context.l10n.unwatched)), : context.l10n.unwatched)),
]; ];
@ -521,7 +526,12 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
if (value == 0) { if (value == 0) {
context.push("/categories", extra: ( context.push("/categories", extra: (
true, true,
widget.manga!.isManga! ? 0 : 1 widget.manga!.itemType == ItemType.manga
? 0
: widget.manga!.itemType ==
ItemType.anime
? 1
: 2
)); ));
} else if (value == 1) { } else if (value == 1) {
} else if (value == 2) { } else if (value == 2) {
@ -593,7 +603,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
8), 8),
child: Text( child: Text(
widget.manga! widget.manga!
.isManga! .itemType !=
ItemType
.anime
? l10n.n_chapters( ? l10n.n_chapters(
chapters chapters
.length) .length)
@ -622,7 +634,10 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
color: context color: context
.secondaryColor), .secondaryColor),
label: Text( label: Text(
widget.manga!.isManga! widget.manga!
.itemType !=
ItemType
.anime
? l10n ? l10n
.add_chapters .add_chapters
: l10n : l10n
@ -644,8 +659,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
manga: manga); manga: manga);
} else { } else {
await ref.watch(importArchivesFromFileProvider( await ref.watch(importArchivesFromFileProvider(
isManga: manga itemType:
.isManga!, manga
.itemType,
manga, manga,
init: init:
false) false)
@ -996,7 +1012,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
.update(); .update();
}), }),
ListTileChapterFilter( ListTileChapterFilter(
label: widget.isManga ? l10n.unread : l10n.unwatched, label: widget.itemType != ItemType.anime
? l10n.unread
: l10n.unwatched,
type: ref.watch(chapterFilterUnreadStateProvider( type: ref.watch(chapterFilterUnreadStateProvider(
mangaId: widget.manga!.id!)), mangaId: widget.manga!.id!)),
onTap: () { onTap: () {
@ -1193,8 +1211,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
), ),
RadioListTile( RadioListTile(
dense: true, dense: true,
title: Text( title: Text(widget.itemType != ItemType.anime
widget.isManga ? l10n.chapter_number : l10n.episode_number), ? l10n.chapter_number
: l10n.episode_number),
value: "ej", value: "ej",
groupValue: "e", groupValue: "e",
selected: false, selected: false,
@ -1211,7 +1230,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
if (index == 0) { if (index == 0) {
return l10n.by_scanlator; return l10n.by_scanlator;
} else if (index == 1) { } else if (index == 1) {
return widget.isManga ? l10n.by_chapter_number : l10n.by_episode_number; return widget.itemType != ItemType.anime
? l10n.by_chapter_number
: l10n.by_episode_number;
} else if (index == 2) { } else if (index == 2) {
return l10n.by_upload_date; return l10n.by_upload_date;
} }
@ -1373,7 +1394,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
padding: padding:
const EdgeInsets.symmetric(horizontal: 8), const EdgeInsets.symmetric(horizontal: 8),
child: Text( child: Text(
widget.manga!.isManga! widget.manga!.itemType != ItemType.anime
? l10n.n_chapters(chapterLength) ? l10n.n_chapters(chapterLength)
: l10n.n_episodes(chapterLength), : l10n.n_episodes(chapterLength),
style: const TextStyle( style: const TextStyle(
@ -1390,7 +1411,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
icon: Icon(Icons.add, icon: Icon(Icons.add,
color: context.secondaryColor), color: context.secondaryColor),
label: Text( label: Text(
widget.manga!.isManga! widget.manga!.itemType != ItemType.anime
? l10n.add_chapters ? l10n.add_chapters
: l10n.add_episodes, : l10n.add_episodes,
style: TextStyle( style: TextStyle(
@ -1404,7 +1425,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
} else { } else {
await ref.watch( await ref.watch(
importArchivesFromFileProvider( importArchivesFromFileProvider(
isManga: manga.isManga!, itemType: manga.itemType,
manga, manga,
init: false) init: false)
.future); .future);
@ -1652,7 +1673,8 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
final trackSearch = final trackSearch =
await trackersSearchraggableMenu( await trackersSearchraggableMenu(
context, context,
isManga: widget.manga!.isManga!, isManga: widget.manga!.itemType !=
ItemType.anime,
track: Track( track: Track(
status: status:
TrackStatus.planToRead, TrackStatus.planToRead,
@ -1975,14 +1997,16 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
mangaId: widget.manga!.id!, mangaId: widget.manga!.id!,
syncId: entries[index].syncId!, syncId: entries[index].syncId!,
trackRes: trackRes.first, trackRes: trackRes.first,
isManga: widget.manga!.isManga!) isManga:
widget.manga!.itemType == ItemType.manga)
: TrackListile( : TrackListile(
text: l10nLocalizations(context)!.add_tracker, text: l10nLocalizations(context)!.add_tracker,
onTap: () async { onTap: () async {
final trackSearch = final trackSearch =
await trackersSearchraggableMenu( await trackersSearchraggableMenu(
context, context,
isManga: widget.manga!.isManga!, isManga: widget.manga!.itemType !=
ItemType.anime,
track: Track( track: Track(
status: TrackStatus.planToRead, status: TrackStatus.planToRead,
syncId: entries[index].syncId!, syncId: entries[index].syncId!,
@ -1992,7 +2016,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
await ref await ref
.read(trackStateProvider( .read(trackStateProvider(
track: null, track: null,
isManga: widget.manga!.isManga!) isManga:
widget.manga!.itemType !=
ItemType.anime)
.notifier) .notifier)
.setTrackSearch( .setTrackSearch(
trackSearch, trackSearch,

View file

@ -69,11 +69,13 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
.idIsNotNull() .idIsNotNull()
.and() .and()
.chapter((q) => q.manga( .chapter((q) => q.manga(
(q) => q.isMangaEqualTo(widget.manga.isManga!))) (q) => q.itemTypeEqualTo(widget.manga.itemType)))
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
String buttonLabel = String buttonLabel =
widget.manga.isManga! ? l10n.read : l10n.watch; widget.manga.itemType != ItemType.anime
? l10n.read
: l10n.watch;
if (snapshot.hasData && snapshot.data!.isNotEmpty) { if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final incognitoMode = final incognitoMode =
ref.watch(incognitoModeStateProvider); ref.watch(incognitoModeStateProvider);
@ -224,7 +226,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.forMangaEqualTo(widget.manga.isManga) .forItemTypeEqualTo(widget.manga.itemType)
.isNotEmptySync(); .isNotEmptySync();
if (checkCategoryList) { if (checkCategoryList) {
_openCategory(widget.manga); _openCategory(widget.manga);
@ -262,7 +264,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
}, },
sourceExist: widget.sourceExist, sourceExist: widget.sourceExist,
checkForUpdate: widget.checkForUpdate, checkForUpdate: widget.checkForUpdate,
isManga: widget.manga.isManga!, itemType: widget.manga.itemType,
), ),
); );
} }
@ -286,7 +288,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.forMangaEqualTo(widget.manga.isManga) .forItemTypeEqualTo(widget.manga.itemType)
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) { if (snapshot.hasData && snapshot.data!.isNotEmpty) {
@ -323,8 +325,14 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
children: [ children: [
TextButton( TextButton(
onPressed: () { onPressed: () {
context.push("/categories", context.push("/categories", extra: (
extra: (true, widget.manga.isManga! ? 0 : 1)); true,
widget.manga.itemType == ItemType.manga
? 0
: widget.manga.itemType == ItemType.anime
? 1
: 2
));
Navigator.pop(context); Navigator.pop(context);
}, },
child: Text(l10n.edit)), child: Text(l10n.edit)),

View file

@ -49,7 +49,7 @@ Future<dynamic> updateMangaDetail(Ref ref,
..link = getManga.link?.trim().trimLeft().trimRight() ?? manga.link ..link = getManga.link?.trim().trimLeft().trimRight() ?? manga.link
..source = manga.source ..source = manga.source
..lang = manga.lang ..lang = manga.lang
..isManga = source.isManga ..itemType = source.itemType
..lastUpdate = DateTime.now().millisecondsSinceEpoch; ..lastUpdate = DateTime.now().millisecondsSinceEpoch;
final checkManga = isar.mangas.getSync(mangaId); final checkManga = isar.mangas.getSync(mangaId);
if (checkManga!.chapters.isNotEmpty && isInit) { if (checkManga!.chapters.isNotEmpty && isInit) {

View file

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

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/date.dart'; import 'package:mangayomi/utils/date.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart'; import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
@ -90,7 +91,7 @@ class ChapterListTileWidget extends ConsumerWidget {
children: [ children: [
const Text(''), const Text(''),
Text( Text(
!chapter.manga.value!.isManga! chapter.manga.value!.itemType == ItemType.anime
? l10n.episode_progress(Duration( ? l10n.episode_progress(Duration(
milliseconds: milliseconds:
int.parse(chapter.lastPageRead!)) int.parse(chapter.lastPageRead!))

View file

@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/page.dart'; import 'package:mangayomi/models/page.dart';
import 'package:mangayomi/services/background_downloader/background_downloader.dart'; import 'package:mangayomi/services/background_downloader/background_downloader.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
@ -46,10 +47,16 @@ Future<List<PageUrl>> downloadChapter(
: ""; : "";
final chapterName = chapter.name!.replaceForbiddenCharacters(' '); final chapterName = chapter.name!.replaceForbiddenCharacters(' ');
final isManga = manga.isManga!; final itemType = chapter.manga.value!.itemType;
final isManga = itemType == ItemType.manga;
final itemTypePath = itemType == ItemType.manga
? "Manga"
: itemType == ItemType.anime
? "Anime"
: "Novel";
final pathSegments = [ final pathSegments = [
"downloads", "downloads",
isManga ? "Manga" : "Anime", itemTypePath,
"${manga.source} (${manga.lang!.toUpperCase()})", "${manga.source} (${manga.lang!.toUpperCase()})",
manga.name!.replaceForbiddenCharacters('_'), manga.name!.replaceForbiddenCharacters('_'),
]; ];

View file

@ -6,7 +6,7 @@ part of 'download_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$downloadChapterHash() => r'19e094ae3e51346012c43320b59ae99107fedf57'; String _$downloadChapterHash() => r'44f8aeae592a90e0c657da0263276997afbbe433';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {

View file

@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:mangayomi/eval/model/m_manga.dart'; import 'package:mangayomi/eval/model/m_manga.dart';
import 'package:mangayomi/eval/model/m_pages.dart'; import 'package:mangayomi/eval/model/m_pages.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart'; import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/library/providers/library_state_provider.dart'; import 'package:mangayomi/modules/library/providers/library_state_provider.dart';
@ -520,14 +521,14 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
return buildProgressIndicator(); return buildProgressIndicator();
} }
return MangaHomeImageCardListTile( return MangaHomeImageCardListTile(
isManga: source.isManga ?? true, itemType: source.itemType,
manga: _mangaList[index], manga: _mangaList[index],
source: source); source: source);
}) })
: Consumer(builder: (context, ref, child) { : Consumer(builder: (context, ref, child) {
final gridSize = ref.watch( final gridSize = ref.watch(
libraryGridSizeStateProvider( libraryGridSizeStateProvider(
isManga: source.isManga!)); itemType: source.itemType));
return GridViewWidget( return GridViewWidget(
gridSize: gridSize, gridSize: gridSize,
@ -540,7 +541,7 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
return buildProgressIndicator(); return buildProgressIndicator();
} }
return MangaHomeImageCard( return MangaHomeImageCard(
isManga: source.isManga ?? true, itemType: source.itemType,
manga: _mangaList[index], manga: _mangaList[index],
source: source, source: source,
isComfortableGrid: isComfortableGrid, isComfortableGrid: isComfortableGrid,
@ -639,14 +640,14 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
class MangaHomeImageCard extends ConsumerStatefulWidget { class MangaHomeImageCard extends ConsumerStatefulWidget {
final MManga manga; final MManga manga;
final bool isManga; final ItemType itemType;
final Source source; final Source source;
final bool isComfortableGrid; final bool isComfortableGrid;
const MangaHomeImageCard( const MangaHomeImageCard(
{super.key, {super.key,
required this.manga, required this.manga,
required this.source, required this.source,
required this.isManga, required this.itemType,
required this.isComfortableGrid}); required this.isComfortableGrid});
@override @override
@ -662,7 +663,7 @@ class _MangaHomeImageCardState extends ConsumerState<MangaHomeImageCard>
return MangaImageCardWidget( return MangaImageCardWidget(
getMangaDetail: widget.manga, getMangaDetail: widget.manga,
source: widget.source, source: widget.source,
isManga: widget.isManga, itemType: widget.itemType,
isComfortableGrid: widget.isComfortableGrid); isComfortableGrid: widget.isComfortableGrid);
} }
@ -672,13 +673,13 @@ class _MangaHomeImageCardState extends ConsumerState<MangaHomeImageCard>
class MangaHomeImageCardListTile extends ConsumerStatefulWidget { class MangaHomeImageCardListTile extends ConsumerStatefulWidget {
final MManga manga; final MManga manga;
final bool isManga; final ItemType itemType;
final Source source; final Source source;
const MangaHomeImageCardListTile( const MangaHomeImageCardListTile(
{super.key, {super.key,
required this.manga, required this.manga,
required this.source, required this.source,
required this.isManga}); required this.itemType});
@override @override
ConsumerState<MangaHomeImageCardListTile> createState() => ConsumerState<MangaHomeImageCardListTile> createState() =>
@ -695,7 +696,7 @@ class _MangaHomeImageCardListTileState
return MangaImageCardListTileWidget( return MangaImageCardListTileWidget(
getMangaDetail: widget.manga, getMangaDetail: widget.manga,
source: widget.source, source: widget.source,
isManga: widget.isManga); itemType: widget.itemType);
} }
@override @override

View file

@ -3,6 +3,7 @@ import 'package:go_router/go_router.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/source.dart';
Future<void> pushMangaReaderView({ Future<void> pushMangaReaderView({
@ -23,19 +24,31 @@ Future<void> pushMangaReaderView({
.findAllSync() .findAllSync()
.isNotEmpty; .isNotEmpty;
if (sourceExist || chapter.manga.value!.isLocalArchive!) { if (sourceExist || chapter.manga.value!.isLocalArchive!) {
if (chapter.manga.value!.isManga!) { switch (chapter.manga.value!.itemType) {
await context.push('/mangareaderview', extra: chapter); case ItemType.manga:
} else { await context.push('/mangaReaderView', extra: chapter);
await context.push('/animePlayerView', extra: chapter); break;
case ItemType.anime:
await context.push('/animePlayerView', extra: chapter);
break;
case ItemType.novel:
await context.push('/novelReaderView', extra: chapter);
break;
} }
} }
} }
void pushReplacementMangaReaderView( void pushReplacementMangaReaderView(
{required BuildContext context, required Chapter chapter}) { {required BuildContext context, required Chapter chapter}) {
if (chapter.manga.value!.isManga!) { switch (chapter.manga.value!.itemType) {
context.pushReplacement('/mangareaderview', extra: chapter); case ItemType.manga:
} else { context.pushReplacement('/mangaReaderView', extra: chapter);
context.pushReplacement('/animePlayerView', extra: chapter); break;
} case ItemType.anime:
context.pushReplacement('/animePlayerView', extra: chapter);
break;
case ItemType.novel:
context.pushReplacement('/novelReaderView', extra: chapter);
break;
}
} }

View file

@ -171,7 +171,7 @@ class ReaderController extends _$ReaderController {
history = History( history = History(
mangaId: getManga().id, mangaId: getManga().id,
date: DateTime.now().millisecondsSinceEpoch.toString(), date: DateTime.now().millisecondsSinceEpoch.toString(),
isManga: getManga().isManga, itemType: getManga().itemType,
chapterId: chapter.id) chapterId: chapter.id)
..chapter.value = chapter; ..chapter.value = chapter;
} else { } else {
@ -379,7 +379,7 @@ extension ChapterExtensions on Chapter {
final tracks = isar.tracks final tracks = isar.tracks
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.isMangaEqualTo(manga.isManga) .isMangaEqualTo(manga.itemType == ItemType.manga)
.mangaIdEqualTo(manga.id!) .mangaIdEqualTo(manga.id!)
.findAllSync(); .findAllSync();
@ -398,15 +398,17 @@ extension ChapterExtensions on Chapter {
track.status = TrackStatus.completed; track.status = TrackStatus.completed;
track.finishedReadingDate = DateTime.now().millisecondsSinceEpoch; track.finishedReadingDate = DateTime.now().millisecondsSinceEpoch;
} else { } else {
track.status = track.status = manga.itemType == ItemType.manga
manga.isManga! ? TrackStatus.reading : TrackStatus.watching; ? TrackStatus.reading
: TrackStatus.watching;
if (track.lastChapterRead == 1) { if (track.lastChapterRead == 1) {
track.startedReadingDate = DateTime.now().millisecondsSinceEpoch; track.startedReadingDate = DateTime.now().millisecondsSinceEpoch;
} }
} }
} }
ref ref
.read(trackStateProvider(track: track, isManga: manga.isManga) .read(trackStateProvider(
track: track, isManga: manga.itemType == ItemType.manga)
.notifier) .notifier)
.updateManga(); .updateManga();
} }

View file

@ -171,7 +171,7 @@ class _CurrentIndexProviderElement
Chapter get chapter => (origin as CurrentIndexProvider).chapter; Chapter get chapter => (origin as CurrentIndexProvider).chapter;
} }
String _$readerControllerHash() => r'cc4f5fbe4192def4d19d9150340d305ba0ecf463'; String _$readerControllerHash() => r'6576f3506dc5ef309f870de3e5c6e92efe03eefd';
abstract class _$ReaderController extends BuildlessAutoDisposeNotifier<void> { abstract class _$ReaderController extends BuildlessAutoDisposeNotifier<void> {
late final Chapter chapter; late final Chapter chapter;

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/category.dart'; import 'package:mangayomi/models/category.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/modules/more/categories/providers/isar_providers.dart'; import 'package:mangayomi/modules/more/categories/providers/isar_providers.dart';
import 'package:mangayomi/modules/more/categories/widgets/custom_textfield.dart'; import 'package:mangayomi/modules/more/categories/widgets/custom_textfield.dart';
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart'; import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
@ -21,7 +22,7 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
late TabController _tabBarController; late TabController _tabBarController;
@override @override
void initState() { void initState() {
_tabBarController = TabController(length: 2, vsync: this); _tabBarController = TabController(length: 3, vsync: this);
_tabBarController.animateTo(widget.data.$2); _tabBarController.animateTo(widget.data.$2);
super.initState(); super.initState();
@ -47,15 +48,19 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
tabs: [ tabs: [
Tab(text: l10n.manga), Tab(text: l10n.manga),
Tab(text: l10n.anime), Tab(text: l10n.anime),
Tab(text: l10n.novel),
], ],
), ),
), ),
body: TabBarView(controller: _tabBarController, children: const [ body: TabBarView(controller: _tabBarController, children: const [
CategoriesTab( CategoriesTab(
isManga: true, itemType: ItemType.manga,
), ),
CategoriesTab( CategoriesTab(
isManga: false, itemType: ItemType.anime,
),
CategoriesTab(
itemType: ItemType.novel,
) )
]), ]),
), ),
@ -64,8 +69,8 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
} }
class CategoriesTab extends ConsumerStatefulWidget { class CategoriesTab extends ConsumerStatefulWidget {
final bool isManga; final ItemType itemType;
const CategoriesTab({required this.isManga, super.key}); const CategoriesTab({required this.itemType, super.key});
@override @override
ConsumerState<CategoriesTab> createState() => _CategoriesTabState(); ConsumerState<CategoriesTab> createState() => _CategoriesTabState();
@ -77,7 +82,7 @@ class _CategoriesTabState extends ConsumerState<CategoriesTab> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
final categories = final categories =
ref.watch(getMangaCategorieStreamProvider(isManga: widget.isManga)); ref.watch(getMangaCategorieStreamProvider(itemType: widget.itemType));
return Scaffold( return Scaffold(
body: categories.when( body: categories.when(
data: (data) { data: (data) {
@ -280,7 +285,7 @@ class _CategoriesTabState extends ConsumerState<CategoriesTab> {
: () async { : () async {
await isar.writeTxn(() async { await isar.writeTxn(() async {
await isar.categorys.put(Category( await isar.categorys.put(Category(
forManga: widget.isManga, forItemType: widget.itemType,
name: controller.text, name: controller.text,
)); ));
}); });

View file

@ -1,17 +1,18 @@
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/category.dart'; import 'package:mangayomi/models/category.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'isar_providers.g.dart'; part 'isar_providers.g.dart';
@riverpod @riverpod
Stream<List<Category>> getMangaCategorieStream(Ref ref, Stream<List<Category>> getMangaCategorieStream(Ref ref,
{required bool isManga}) async* { {required ItemType itemType}) async* {
yield* isar.categorys yield* isar.categorys
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.forMangaEqualTo(isManga) .forItemTypeEqualTo(itemType)
.watch(fireImmediately: true); .watch(fireImmediately: true);
} }

View file

@ -7,7 +7,7 @@ part of 'isar_providers.dart';
// ************************************************************************** // **************************************************************************
String _$getMangaCategorieStreamHash() => String _$getMangaCategorieStreamHash() =>
r'97e90977f4696eedcf597c655a40dd6ccd47ed37'; r'1dcf15018a6467eef7a26c1728b9e531ebd984d0';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -41,10 +41,10 @@ class GetMangaCategorieStreamFamily extends Family<AsyncValue<List<Category>>> {
/// See also [getMangaCategorieStream]. /// See also [getMangaCategorieStream].
GetMangaCategorieStreamProvider call({ GetMangaCategorieStreamProvider call({
required bool isManga, required ItemType itemType,
}) { }) {
return GetMangaCategorieStreamProvider( return GetMangaCategorieStreamProvider(
isManga: isManga, itemType: itemType,
); );
} }
@ -53,7 +53,7 @@ class GetMangaCategorieStreamFamily extends Family<AsyncValue<List<Category>>> {
covariant GetMangaCategorieStreamProvider provider, covariant GetMangaCategorieStreamProvider provider,
) { ) {
return call( return call(
isManga: provider.isManga, itemType: provider.itemType,
); );
} }
@ -77,11 +77,11 @@ class GetMangaCategorieStreamProvider
extends AutoDisposeStreamProvider<List<Category>> { extends AutoDisposeStreamProvider<List<Category>> {
/// See also [getMangaCategorieStream]. /// See also [getMangaCategorieStream].
GetMangaCategorieStreamProvider({ GetMangaCategorieStreamProvider({
required bool isManga, required ItemType itemType,
}) : this._internal( }) : this._internal(
(ref) => getMangaCategorieStream( (ref) => getMangaCategorieStream(
ref as GetMangaCategorieStreamRef, ref as GetMangaCategorieStreamRef,
isManga: isManga, itemType: itemType,
), ),
from: getMangaCategorieStreamProvider, from: getMangaCategorieStreamProvider,
name: r'getMangaCategorieStreamProvider', name: r'getMangaCategorieStreamProvider',
@ -92,7 +92,7 @@ class GetMangaCategorieStreamProvider
dependencies: GetMangaCategorieStreamFamily._dependencies, dependencies: GetMangaCategorieStreamFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
GetMangaCategorieStreamFamily._allTransitiveDependencies, GetMangaCategorieStreamFamily._allTransitiveDependencies,
isManga: isManga, itemType: itemType,
); );
GetMangaCategorieStreamProvider._internal( GetMangaCategorieStreamProvider._internal(
@ -102,10 +102,10 @@ class GetMangaCategorieStreamProvider
required super.allTransitiveDependencies, required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash, required super.debugGetCreateSourceHash,
required super.from, required super.from,
required this.isManga, required this.itemType,
}) : super.internal(); }) : super.internal();
final bool isManga; final ItemType itemType;
@override @override
Override overrideWith( Override overrideWith(
@ -120,7 +120,7 @@ class GetMangaCategorieStreamProvider
dependencies: null, dependencies: null,
allTransitiveDependencies: null, allTransitiveDependencies: null,
debugGetCreateSourceHash: null, debugGetCreateSourceHash: null,
isManga: isManga, itemType: itemType,
), ),
); );
} }
@ -132,13 +132,14 @@ class GetMangaCategorieStreamProvider
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is GetMangaCategorieStreamProvider && other.isManga == isManga; return other is GetMangaCategorieStreamProvider &&
other.itemType == itemType;
} }
@override @override
int get hashCode { int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode); var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, isManga.hashCode); hash = _SystemHash.combine(hash, itemType.hashCode);
return _SystemHash.finish(hash); return _SystemHash.finish(hash);
} }
@ -148,8 +149,8 @@ class GetMangaCategorieStreamProvider
// ignore: unused_element // ignore: unused_element
mixin GetMangaCategorieStreamRef mixin GetMangaCategorieStreamRef
on AutoDisposeStreamProviderRef<List<Category>> { on AutoDisposeStreamProviderRef<List<Category>> {
/// The parameter `isManga` of this provider. /// The parameter `itemType` of this provider.
bool get isManga; ItemType get itemType;
} }
class _GetMangaCategorieStreamProviderElement class _GetMangaCategorieStreamProviderElement
@ -158,7 +159,7 @@ class _GetMangaCategorieStreamProviderElement
_GetMangaCategorieStreamProviderElement(super.provider); _GetMangaCategorieStreamProviderElement(super.provider);
@override @override
bool get isManga => (origin as GetMangaCategorieStreamProvider).isManga; ItemType get itemType => (origin as GetMangaCategorieStreamProvider).itemType;
} }
// ignore_for_file: type=lint // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View file

@ -0,0 +1,370 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
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/track.dart';
import 'package:mangayomi/models/track_preference.dart';
import 'package:mangayomi/modules/manga/detail/providers/track_state_providers.dart';
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
import 'package:mangayomi/modules/more/settings/track/providers/track_providers.dart';
import 'package:mangayomi/services/sync_server.dart';
import 'package:mangayomi/utils/chapter_recognition.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'novel_reader_controller_provider.g.dart';
BoxFit getBoxFit(ScaleType scaleType) {
return switch (scaleType) {
ScaleType.fitHeight => BoxFit.fitHeight,
ScaleType.fitWidth => BoxFit.fitWidth,
ScaleType.fitScreen => BoxFit.contain,
ScaleType.originalSize => BoxFit.cover,
ScaleType.smartFit => BoxFit.contain,
_ => BoxFit.cover
};
}
@riverpod
class NovelReaderController extends _$NovelReaderController {
@override
void build({required Chapter chapter}) {}
Manga getManga() {
return chapter.manga.value!;
}
Chapter geChapter() {
return chapter;
}
final incognitoMode = isar.settings.getSync(227)!.incognitoMode!;
Settings getIsarSetting() {
return isar.settings.getSync(227)!;
}
void setMangaHistoryUpdate() {
if (incognitoMode) return;
isar.writeTxnSync(() {
Manga? manga = chapter.manga.value;
manga!.lastRead = DateTime.now().millisecondsSinceEpoch;
isar.mangas.putSync(manga);
});
History? history;
final empty =
isar.historys.filter().mangaIdEqualTo(getManga().id).isEmptySync();
if (empty) {
history = History(
mangaId: getManga().id,
date: DateTime.now().millisecondsSinceEpoch.toString(),
itemType: getManga().itemType,
chapterId: chapter.id)
..chapter.value = chapter;
} else {
history = (isar.historys
.filter()
.mangaIdEqualTo(getManga().id)
.findFirstSync())!
..chapterId = chapter.id
..chapter.value = chapter
..date = DateTime.now().millisecondsSinceEpoch.toString();
}
isar.writeTxnSync(() {
isar.historys.putSync(history!);
history.chapter.saveSync();
});
}
void checkAndSyncProgress() {
final syncAfterReading = ref.watch(syncAfterReadingStateProvider);
if (syncAfterReading) {
ref.read(syncServerProvider(syncId: 1).notifier).checkForSync(true);
}
}
void setChapterBookmarked() {
if (incognitoMode) return;
final isBookmarked = getChapterBookmarked();
final chap = chapter;
isar.writeTxnSync(() {
chap.isBookmarked = !isBookmarked;
ref
.read(changedItemsManagerProvider(managerId: 1).notifier)
.addUpdatedChapter(chap, false, false);
isar.chapters.putSync(chap);
});
}
bool getChapterBookmarked() {
return isar.chapters.getSync(chapter.id!)!.isBookmarked!;
}
(int, bool) getPrevChapterIndex() {
final chapters = getManga().getFilteredChapterList();
int? index;
for (var i = 0; i < chapters.length; i++) {
if (chapters[i].id == chapter.id) {
index = i + 1;
}
}
if (index == null) {
final chapters = getManga().chapters.toList().reversed.toList();
for (var i = 0; i < chapters.length; i++) {
if (chapters[i].id == chapter.id) {
index = i + 1;
}
}
return (index!, false);
}
return (index, true);
}
(int, bool) getNextChapterIndex() {
final chapters = getManga().getFilteredChapterList();
int? index;
for (var i = 0; i < chapters.length; i++) {
if (chapters[i].id == chapter.id) {
index = i - 1;
}
}
if (index == null) {
final chapters = getManga().chapters.toList().reversed.toList();
for (var i = 0; i < chapters.length; i++) {
if (chapters[i].id == chapter.id) {
index = i - 1;
}
}
return (index!, false);
}
return (index, true);
}
(int, bool) getChapterIndex() {
final chapters = getManga().getFilteredChapterList();
int? index;
for (var i = 0; i < chapters.length; i++) {
if (chapters[i].id == chapter.id) {
index = i;
}
}
if (index == null) {
final chapters = getManga().chapters.toList().reversed.toList();
for (var i = 0; i < chapters.length; i++) {
if (chapters[i].id == chapter.id) {
index = i;
}
}
return (index!, false);
}
return (index, true);
}
Chapter getPrevChapter() {
final prevChapIdx = getPrevChapterIndex();
return prevChapIdx.$2
? getManga().getFilteredChapterList()[prevChapIdx.$1]
: getManga().chapters.toList().reversed.toList()[prevChapIdx.$1];
}
Chapter getNextChapter() {
final nextChapIdx = getNextChapterIndex();
return nextChapIdx.$2
? getManga().getFilteredChapterList()[nextChapIdx.$1]
: getManga().chapters.toList().reversed.toList()[nextChapIdx.$1];
}
int getChaptersLength(bool isInFilterList) {
return isInFilterList
? getManga().getFilteredChapterList().length
: getManga().chapters.length;
}
String getMangaName() {
return getManga().name!;
}
String getSourceName() {
return getManga().source!;
}
String getChapterTitle() {
return chapter.name!;
}
}
extension ChapterExtensions on Chapter {
void updateTrackChapterRead(dynamic ref) {
if (!(ref is WidgetRef || ref is Ref)) return;
final updateProgressAfterReading =
ref.watch(updateProgressAfterReadingStateProvider);
if (!updateProgressAfterReading) return;
final manga = this.manga.value!;
final chapterNumber =
ChapterRecognition().parseChapterNumber(manga.name!, name!);
final tracks = isar.tracks
.filter()
.idIsNotNull()
.isMangaEqualTo(manga.itemType == ItemType.manga)
.mangaIdEqualTo(manga.id!)
.findAllSync();
if (tracks.isEmpty) return;
for (var track in tracks) {
final service = isar.trackPreferences
.filter()
.syncIdIsNotNull()
.syncIdEqualTo(track.syncId)
.findFirstSync();
if (!(service == null || chapterNumber <= (track.lastChapterRead ?? 0))) {
if (track.status != TrackStatus.completed) {
track.lastChapterRead = chapterNumber;
if (track.lastChapterRead == track.totalChapter &&
(track.totalChapter ?? 0) > 0) {
track.status = TrackStatus.completed;
track.finishedReadingDate = DateTime.now().millisecondsSinceEpoch;
} else {
track.status = manga.itemType == ItemType.manga
? TrackStatus.reading
: TrackStatus.watching;
if (track.lastChapterRead == 1) {
track.startedReadingDate = DateTime.now().millisecondsSinceEpoch;
}
}
}
ref
.read(trackStateProvider(
track: track, isManga: manga.itemType == ItemType.manga)
.notifier)
.updateManga();
}
}
}
}
extension MangaExtensions on Manga {
List<Chapter> getFilteredChapterList() {
final data = this.chapters.toList().reversed.toList();
final filterUnread = (isar.settings
.getSync(227)!
.chapterFilterUnreadList!
.where((element) => element.mangaId == id)
.toList()
.firstOrNull ??
ChapterFilterUnread(
mangaId: id,
type: 0,
))
.type!;
final filterBookmarked = (isar.settings
.getSync(227)!
.chapterFilterBookmarkedList!
.where((element) => element.mangaId == id)
.toList()
.firstOrNull ??
ChapterFilterBookmarked(
mangaId: id,
type: 0,
))
.type!;
final filterDownloaded = (isar.settings
.getSync(227)!
.chapterFilterDownloadedList!
.where((element) => element.mangaId == id)
.toList()
.firstOrNull ??
ChapterFilterDownloaded(
mangaId: id,
type: 0,
))
.type!;
final sortChapter = (isar.settings
.getSync(227)!
.sortChapterList!
.where((element) => element.mangaId == id)
.toList()
.firstOrNull ??
SortChapter(
mangaId: id,
index: 1,
reverse: false,
))
.index;
final filterScanlator = _getFilterScanlator(this) ?? [];
List<Chapter>? chapterList;
chapterList = data
.where((element) => filterUnread == 1
? element.isRead == false
: filterUnread == 2
? element.isRead == true
: true)
.where((element) => filterBookmarked == 1
? element.isBookmarked == true
: filterBookmarked == 2
? element.isBookmarked == false
: true)
.where((element) {
final modelChapDownload = isar.downloads
.filter()
.idIsNotNull()
.chapterIdEqualTo(element.id)
.findAllSync();
return filterDownloaded == 1
? modelChapDownload.isNotEmpty &&
modelChapDownload.first.isDownload == true
: filterDownloaded == 2
? !(modelChapDownload.isNotEmpty &&
modelChapDownload.first.isDownload == true)
: true;
})
.where((element) => !filterScanlator.contains(element.scanlator))
.toList();
List<Chapter> chapters =
sortChapter == 1 ? chapterList.reversed.toList() : chapterList;
if (sortChapter == 0) {
chapters.sort(
(a, b) {
return (a.scanlator == null ||
b.scanlator == null ||
a.dateUpload == null ||
b.dateUpload == null)
? 0
: a.scanlator!.compareTo(b.scanlator!) |
a.dateUpload!.compareTo(b.dateUpload!);
},
);
} else if (sortChapter == 2) {
chapters.sort(
(a, b) {
return (a.dateUpload == null || b.dateUpload == null)
? 0
: int.parse(a.dateUpload!).compareTo(int.parse(b.dateUpload!));
},
);
} else if (sortChapter == 3) {
chapters.sort(
(a, b) {
return (a.name == null || b.name == null)
? 0
: a.name!.compareTo(b.name!);
},
);
}
return chapterList;
}
}
List<String>? _getFilterScanlator(Manga manga) {
final scanlators = isar.settings.getSync(227)!.filterScanlatorList ?? [];
final filter =
scanlators.where((element) => element.mangaId == manga.id).toList();
return filter.firstOrNull?.scanlators;
}

View file

@ -0,0 +1,177 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'novel_reader_controller_provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$novelReaderControllerHash() =>
r'74ebbf38d60283d308646b59cfd5cfee07c85535';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
abstract class _$NovelReaderController
extends BuildlessAutoDisposeNotifier<void> {
late final Chapter chapter;
void build({
required Chapter chapter,
});
}
/// See also [NovelReaderController].
@ProviderFor(NovelReaderController)
const novelReaderControllerProvider = NovelReaderControllerFamily();
/// See also [NovelReaderController].
class NovelReaderControllerFamily extends Family<void> {
/// See also [NovelReaderController].
const NovelReaderControllerFamily();
/// See also [NovelReaderController].
NovelReaderControllerProvider call({
required Chapter chapter,
}) {
return NovelReaderControllerProvider(
chapter: chapter,
);
}
@override
NovelReaderControllerProvider getProviderOverride(
covariant NovelReaderControllerProvider provider,
) {
return call(
chapter: provider.chapter,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'novelReaderControllerProvider';
}
/// See also [NovelReaderController].
class NovelReaderControllerProvider
extends AutoDisposeNotifierProviderImpl<NovelReaderController, void> {
/// See also [NovelReaderController].
NovelReaderControllerProvider({
required Chapter chapter,
}) : this._internal(
() => NovelReaderController()..chapter = chapter,
from: novelReaderControllerProvider,
name: r'novelReaderControllerProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$novelReaderControllerHash,
dependencies: NovelReaderControllerFamily._dependencies,
allTransitiveDependencies:
NovelReaderControllerFamily._allTransitiveDependencies,
chapter: chapter,
);
NovelReaderControllerProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.chapter,
}) : super.internal();
final Chapter chapter;
@override
void runNotifierBuild(
covariant NovelReaderController notifier,
) {
return notifier.build(
chapter: chapter,
);
}
@override
Override overrideWith(NovelReaderController Function() create) {
return ProviderOverride(
origin: this,
override: NovelReaderControllerProvider._internal(
() => create()..chapter = chapter,
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
chapter: chapter,
),
);
}
@override
AutoDisposeNotifierProviderElement<NovelReaderController, void>
createElement() {
return _NovelReaderControllerProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is NovelReaderControllerProvider && other.chapter == chapter;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, chapter.hashCode);
return _SystemHash.finish(hash);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin NovelReaderControllerRef on AutoDisposeNotifierProviderRef<void> {
/// The parameter `chapter` of this provider.
Chapter get chapter;
}
class _NovelReaderControllerProviderElement
extends AutoDisposeNotifierProviderElement<NovelReaderController, void>
with NovelReaderControllerRef {
_NovelReaderControllerProviderElement(super.provider);
@override
Chapter get chapter => (origin as NovelReaderControllerProvider).chapter;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View file

@ -0,0 +1,430 @@
import 'dart:async';
import 'dart:io';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/page.dart';
import 'package:mangayomi/modules/anime/widgets/desktop.dart';
import 'package:mangayomi/modules/manga/reader/widgets/btn_chapter_list_dialog.dart';
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
import 'package:mangayomi/modules/novel/novel_reader_controller_provider.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/services/get_html_content.dart';
import 'package:mangayomi/utils/utils.dart';
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
import 'package:mangayomi/services/get_chapter_pages.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
import 'package:mangayomi/utils/global_style.dart';
import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provider.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:window_manager/window_manager.dart';
import 'package:flutter_html/flutter_html.dart';
typedef DoubleClickAnimationListener = void Function();
class NovelReaderView extends ConsumerWidget {
final Chapter chapter;
const NovelReaderView({
super.key,
required this.chapter,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final htmlContent = ref.watch(getHtmlContentProvider(chapter: chapter));
return NovelWebView(
chapter: chapter,
htmlContent: htmlContent,
);
}
}
class NovelWebView extends ConsumerStatefulWidget {
const NovelWebView({
super.key,
required this.chapter,
required this.htmlContent,
});
final Chapter chapter;
final AsyncValue<String> htmlContent;
@override
ConsumerState createState() {
return _NovelWebViewState();
}
}
class _NovelWebViewState extends ConsumerState<NovelWebView>
with TickerProviderStateMixin {
late final NovelReaderController _readerController =
ref.read(novelReaderControllerProvider(chapter: chapter).notifier);
bool isDesktop = Platform.isMacOS || Platform.isLinux || Platform.isWindows;
@override
void dispose() {
_readerController.setMangaHistoryUpdate();
_readerController.checkAndSyncProgress();
_rebuildDetail.close();
clearGestureDetailsCache();
if (isDesktop) {
setFullScreen(value: false);
} else {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
}
super.dispose();
}
late Chapter chapter = widget.chapter;
final StreamController<double> _rebuildDetail =
StreamController<double>.broadcast();
@override
void initState() {
super.initState();
}
late bool _isBookmarked = _readerController.getChapterBookmarked();
bool _isView = false;
double get pixelRatio => View.of(context).devicePixelRatio;
Size get size => View.of(context).physicalSize / pixelRatio;
Color _backgroundColor(BuildContext context) =>
Theme.of(context).scaffoldBackgroundColor.withOpacity(0.9);
void _setFullScreen({bool? value}) async {
if (isDesktop) {
value = await windowManager.isFullScreen();
setFullScreen(value: !value);
}
ref.read(fullScreenReaderStateProvider.notifier).set(!value!);
}
@override
Widget build(BuildContext context) {
final backgroundColor = ref.watch(backgroundColorStateProvider);
final fullScreenReader = ref.watch(fullScreenReaderStateProvider);
final l10n = l10nLocalizations(context)!;
return KeyboardListener(
autofocus: true,
focusNode: FocusNode(),
onKeyEvent: (event) {
bool isLogicalKeyPressed(LogicalKeyboardKey key) =>
HardwareKeyboard.instance.isLogicalKeyPressed(key);
bool hasNextChapter = _readerController.getChapterIndex().$1 != 0;
bool hasPrevChapter = _readerController.getChapterIndex().$1 + 1 !=
_readerController
.getChaptersLength(_readerController.getChapterIndex().$2);
final action = switch (event.logicalKey) {
LogicalKeyboardKey.f11 =>
(!isLogicalKeyPressed(LogicalKeyboardKey.f11))
? _setFullScreen()
: null,
LogicalKeyboardKey.escape =>
(!isLogicalKeyPressed(LogicalKeyboardKey.escape))
? _goBack(context)
: null,
LogicalKeyboardKey.backspace =>
(!isLogicalKeyPressed(LogicalKeyboardKey.backspace))
? _goBack(context)
: null,
LogicalKeyboardKey.keyN ||
LogicalKeyboardKey.pageDown =>
((!isLogicalKeyPressed(LogicalKeyboardKey.keyN) ||
!isLogicalKeyPressed(LogicalKeyboardKey.pageDown)))
? switch (hasNextChapter) {
true => pushReplacementMangaReaderView(
context: context,
chapter: _readerController.getNextChapter(),
),
_ => null
}
: null,
LogicalKeyboardKey.keyP ||
LogicalKeyboardKey.pageUp =>
((!isLogicalKeyPressed(LogicalKeyboardKey.keyP) ||
!isLogicalKeyPressed(LogicalKeyboardKey.pageUp)))
? switch (hasPrevChapter) {
true => pushReplacementMangaReaderView(
context: context,
chapter: _readerController.getPrevChapter()),
_ => null
}
: null,
_ => null
};
action;
},
child: NotificationListener<UserScrollNotification>(
onNotification: (notification) {
if (notification.direction == ScrollDirection.idle) {
if (_isView) {
_isViewFunction();
}
}
return true;
},
child: Material(
child: SafeArea(
top: !fullScreenReader,
bottom: false,
child: Stack(
children: [
widget.htmlContent.when(
data: (htmlContent) => Expanded(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Html(
data: htmlContent,
style: {
"*": Style(
backgroundColor: Colors.white,
margin: Margins.all(5))
},
shrinkWrap: true,
),
),
),
loading: () => const Center(
child: CircularProgressIndicator(),
),
error: (err, stack) => Center(
child: Text(err.toString()),
)),
_appBar(),
],
),
),
),
),
);
}
void _goBack(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context);
}
Widget _appBar() {
if (!_isView && Platform.isIOS) {
return const SizedBox.shrink();
}
final fullScreenReader = ref.watch(fullScreenReaderStateProvider);
double height = _isView
? Platform.isIOS
? 120
: !fullScreenReader && !isDesktop
? 55
: 80
: 0;
return Positioned(
top: 0,
child: AnimatedContainer(
width: context.width(1),
height: height,
curve: Curves.ease,
duration: const Duration(milliseconds: 200),
child: PreferredSize(
preferredSize: Size.fromHeight(height),
child: AppBar(
centerTitle: false,
automaticallyImplyLeading: false,
titleSpacing: 0,
leading: BackButton(
onPressed: () {
Navigator.pop(context);
},
),
title: ListTile(
dense: true,
title: SizedBox(
width: context.width(0.8),
child: Text(
'${_readerController.getMangaName()} ',
style: const TextStyle(fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
),
),
subtitle: SizedBox(
width: context.width(0.8),
child: Text(
_readerController.getChapterTitle(),
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w400,
),
overflow: TextOverflow.ellipsis,
),
),
),
actions: [
btnToShowChapterListDialog(
context, context.l10n.chapters, widget.chapter),
IconButton(
onPressed: () {
_readerController.setChapterBookmarked();
setState(() {
_isBookmarked = !_isBookmarked;
});
},
icon: Icon(_isBookmarked
? Icons.bookmark
: Icons.bookmark_border_outlined)),
if ((chapter.manga.value!.isLocalArchive ?? false) == false)
IconButton(
onPressed: () async {
final manga = chapter.manga.value!;
final source = getSource(manga.lang!, manga.source!)!;
String url = chapter.url!.startsWith('/')
? "${source.baseUrl}/${chapter.url!}"
: chapter.url!;
Map<String, dynamic> data = {
'url': url,
'sourceId': source.id.toString(),
'title': chapter.name!
};
if (Platform.isLinux) {
final urll = Uri.parse(url);
if (!await launchUrl(
urll,
mode: LaunchMode.inAppBrowserView,
)) {
if (!await launchUrl(
urll,
mode: LaunchMode.externalApplication,
)) {
throw 'Could not launch $url';
}
}
} else {
context.push("/mangawebview", extra: data);
}
},
icon: const Icon(Icons.public)),
],
backgroundColor: _backgroundColor(context),
),
),
),
);
}
void _isViewFunction() {
final fullScreenReader = ref.watch(fullScreenReaderStateProvider);
if (mounted) {
setState(() {
_isView = !_isView;
});
}
if (fullScreenReader) {
if (_isView) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
} else {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
}
}
}
}
class UChapDataPreload {
Chapter? chapter;
Directory? directory;
PageUrl? pageUrl;
bool? isLocale;
Uint8List? archiveImage;
int? index;
GetChapterPagesModel? chapterUrlModel;
int? pageIndex;
Uint8List? cropImage;
UChapDataPreload(this.chapter, this.directory, this.pageUrl, this.isLocale,
this.archiveImage, this.index, this.chapterUrlModel, this.pageIndex,
{this.cropImage});
}
class CustomPopupMenuButton<T> extends StatelessWidget {
final String label;
final String title;
final ValueChanged<T> onSelected;
final T value;
final List<T> list;
final String Function(T) itemText;
const CustomPopupMenuButton(
{super.key,
required this.label,
required this.title,
required this.onSelected,
required this.value,
required this.list,
required this.itemText});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: PopupMenuButton(
popUpAnimationStyle: popupAnimationStyle,
tooltip: "",
offset: Offset.fromDirection(1),
color: Colors.black,
onSelected: onSelected,
itemBuilder: (context) => [
for (var d in list)
PopupMenuItem(
value: d,
child: Row(
children: [
Icon(
Icons.check,
color: d == value ? Colors.white : Colors.transparent,
),
const SizedBox(width: 7),
Text(
itemText(d),
style: const TextStyle(color: Colors.white),
),
],
)),
],
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Text(
label,
style: TextStyle(
color: Theme.of(context)
.textTheme
.bodyLarge!
.color!
.withOpacity(0.9)),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
Row(
children: [
Text(title),
const SizedBox(width: 20),
const Icon(Icons.keyboard_arrow_down_outlined)
],
),
],
),
),
),
);
}
}

View file

@ -42,7 +42,11 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
.idIsNotNull() .idIsNotNull()
.favoriteEqualTo(true) .favoriteEqualTo(true)
.and() .and()
.isMangaEqualTo(_tabBarController.index == 0) .itemTypeEqualTo(_tabBarController.index == 0
? ItemType.manga
: _tabBarController.index == 1
? ItemType.anime
: ItemType.novel)
.findAllSync(); .findAllSync();
int numbers = 0; int numbers = 0;
@ -68,7 +72,7 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
@override @override
void initState() { void initState() {
_tabBarController = TabController(length: 2, vsync: this); _tabBarController = TabController(length: 3, vsync: this);
_tabBarController.animateTo(0); _tabBarController.animateTo(0);
_tabBarController.addListener(() { _tabBarController.addListener(() {
setState(() { setState(() {
@ -160,10 +164,14 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
List<Update> updates = isar.updates List<Update> updates = isar.updates
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.chapter((q) => q.manga((q) => .chapter((q) => q.manga((q) => q
q.isMangaEqualTo( .itemTypeEqualTo(_tabBarController
_tabBarController.index == .index ==
0))) 0
? ItemType.manga
: _tabBarController.index == 1
? ItemType.anime
: ItemType.novel)))
.findAllSync() .findAllSync()
.toList(); .toList();
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -191,6 +199,7 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
tabs: [ tabs: [
Tab(text: l10n.manga), Tab(text: l10n.manga),
Tab(text: l10n.anime), Tab(text: l10n.anime),
Tab(text: l10n.novel),
], ],
), ),
), ),
@ -198,11 +207,15 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
padding: const EdgeInsets.only(top: 10), padding: const EdgeInsets.only(top: 10),
child: TabBarView(controller: _tabBarController, children: [ child: TabBarView(controller: _tabBarController, children: [
UpdateTab( UpdateTab(
isManga: true, itemType: ItemType.manga,
query: _textEditingController.text, query: _textEditingController.text,
isLoading: _isLoading), isLoading: _isLoading),
UpdateTab( UpdateTab(
isManga: false, itemType: ItemType.anime,
query: _textEditingController.text,
isLoading: _isLoading),
UpdateTab(
itemType: ItemType.novel,
query: _textEditingController.text, query: _textEditingController.text,
isLoading: _isLoading) isLoading: _isLoading)
]), ]),
@ -214,10 +227,10 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
class UpdateTab extends ConsumerStatefulWidget { class UpdateTab extends ConsumerStatefulWidget {
final String query; final String query;
final bool isManga; final ItemType itemType;
final bool isLoading; final bool isLoading;
const UpdateTab( const UpdateTab(
{required this.isManga, {required this.itemType,
required this.query, required this.query,
required this.isLoading, required this.isLoading,
super.key}); super.key});
@ -231,7 +244,7 @@ class _UpdateTabState extends ConsumerState<UpdateTab> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
final update = final update =
ref.watch(getAllUpdateStreamProvider(isManga: widget.isManga)); ref.watch(getAllUpdateStreamProvider(itemType: widget.itemType));
return Scaffold( return Scaffold(
body: Stack( body: Stack(
children: [ children: [

View file

@ -19,7 +19,7 @@ import 'package:mangayomi/modules/widgets/cover_view_widget.dart';
class MangaImageCardWidget extends ConsumerWidget { class MangaImageCardWidget extends ConsumerWidget {
final Source source; final Source source;
final bool isManga; final ItemType itemType;
final bool isComfortableGrid; final bool isComfortableGrid;
final MManga? getMangaDetail; final MManga? getMangaDetail;
@ -28,7 +28,7 @@ class MangaImageCardWidget extends ConsumerWidget {
super.key, super.key,
required this.getMangaDetail, required this.getMangaDetail,
required this.isComfortableGrid, required this.isComfortableGrid,
required this.isManga}); required this.itemType});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -68,7 +68,7 @@ class MangaImageCardWidget extends ConsumerWidget {
getManga: getMangaDetail!, getManga: getMangaDetail!,
lang: source.lang!, lang: source.lang!,
source: source.name!, source: source.name!,
isManga: isManga); itemType: itemType);
}, },
onLongPress: () { onLongPress: () {
pushToMangaReaderDetail( pushToMangaReaderDetail(
@ -76,7 +76,7 @@ class MangaImageCardWidget extends ConsumerWidget {
getManga: getMangaDetail!, getManga: getMangaDetail!,
lang: source.lang!, lang: source.lang!,
source: source.name!, source: source.name!,
isManga: isManga, itemType: itemType,
addToFavourite: true); addToFavourite: true);
}, },
onSecondaryTap: () { onSecondaryTap: () {
@ -85,7 +85,7 @@ class MangaImageCardWidget extends ConsumerWidget {
getManga: getMangaDetail!, getManga: getMangaDetail!,
lang: source.lang!, lang: source.lang!,
source: source.name!, source: source.name!,
isManga: isManga, itemType: itemType,
addToFavourite: true); addToFavourite: true);
}, },
children: [ children: [
@ -121,13 +121,13 @@ class MangaImageCardWidget extends ConsumerWidget {
class MangaImageCardListTileWidget extends ConsumerWidget { class MangaImageCardListTileWidget extends ConsumerWidget {
final Source source; final Source source;
final bool isManga; final ItemType itemType;
final MManga? getMangaDetail; final MManga? getMangaDetail;
const MangaImageCardListTileWidget( const MangaImageCardListTileWidget(
{required this.source, {required this.source,
super.key, super.key,
required this.isManga, required this.itemType,
required this.getMangaDetail}); required this.getMangaDetail});
@override @override
@ -166,7 +166,7 @@ class MangaImageCardListTileWidget extends ConsumerWidget {
getManga: getMangaDetail!, getManga: getMangaDetail!,
lang: source.lang!, lang: source.lang!,
source: source.name!, source: source.name!,
isManga: isManga); itemType: itemType);
}, },
onLongPress: () { onLongPress: () {
pushToMangaReaderDetail( pushToMangaReaderDetail(
@ -174,7 +174,7 @@ class MangaImageCardListTileWidget extends ConsumerWidget {
getManga: getMangaDetail!, getManga: getMangaDetail!,
lang: source.lang!, lang: source.lang!,
source: source.name!, source: source.name!,
isManga: isManga, itemType: itemType,
addToFavourite: true); addToFavourite: true);
}, },
onSecondaryTap: () { onSecondaryTap: () {
@ -183,7 +183,7 @@ class MangaImageCardListTileWidget extends ConsumerWidget {
getManga: getMangaDetail!, getManga: getMangaDetail!,
lang: source.lang!, lang: source.lang!,
source: source.name!, source: source.name!,
isManga: isManga, itemType: itemType,
addToFavourite: true); addToFavourite: true);
}, },
child: Row( child: Row(
@ -252,7 +252,7 @@ Future<void> pushToMangaReaderDetail(
required String source, required String source,
int? archiveId, int? archiveId,
Manga? mangaM, Manga? mangaM,
bool? isManga, ItemType? itemType,
bool useMaterialRoute = false, bool useMaterialRoute = false,
bool addToFavourite = false}) async { bool addToFavourite = false}) async {
int? mangaId; int? mangaId;
@ -269,7 +269,7 @@ Future<void> pushToMangaReaderDetail(
source: source, source: source,
lang: lang, lang: lang,
lastUpdate: 0, lastUpdate: 0,
isManga: isManga ?? true, itemType: itemType ?? ItemType.manga,
artist: getManga.artist ?? ''); artist: getManga.artist ?? '');
final empty = isar.mangas final empty = isar.mangas
.filter() .filter()

View file

@ -88,19 +88,29 @@ class StorageProvider {
String scanlator = chapter.scanlator?.isNotEmpty ?? false String scanlator = chapter.scanlator?.isNotEmpty ?? false
? "${chapter.scanlator!.replaceForbiddenCharacters('_')}_" ? "${chapter.scanlator!.replaceForbiddenCharacters('_')}_"
: ""; : "";
final isManga = chapter.manga.value!.isManga!; final itemType = chapter.manga.value!.itemType;
final itemTypePath = itemType == ItemType.manga
? "Manga"
: itemType == ItemType.anime
? "Anime"
: "Novel";
final dir = await getDirectory(); final dir = await getDirectory();
return Directory( return Directory(
"${dir!.path}/downloads/${isManga ? "Manga" : "Anime"}/${manga.source} (${manga.lang!.toUpperCase()})/${manga.name!.replaceForbiddenCharacters('_')}/$scanlator${chapter.name!.replaceForbiddenCharacters('_')}/" "${dir!.path}/downloads/$itemTypePath/${manga.source} (${manga.lang!.toUpperCase()})/${manga.name!.replaceForbiddenCharacters('_')}/$scanlator${chapter.name!.replaceForbiddenCharacters('_')}/"
.fixSeparator); .fixSeparator);
} }
Future<Directory?> getMangaMainDirectory(Chapter chapter) async { Future<Directory?> getMangaMainDirectory(Chapter chapter) async {
final manga = chapter.manga.value!; final manga = chapter.manga.value!;
final isManga = chapter.manga.value!.isManga!; final itemType = chapter.manga.value!.itemType;
final itemTypePath = itemType == ItemType.manga
? "Manga"
: itemType == ItemType.anime
? "Anime"
: "Novel";
final dir = await getDirectory(); final dir = await getDirectory();
return Directory( return Directory(
"${dir!.path}/downloads/${isManga ? "Manga" : "Anime"}/${manga.source} (${manga.lang!.toUpperCase()})/${manga.name!.replaceForbiddenCharacters('_')}/" "${dir!.path}/downloads/$itemTypePath/${manga.source} (${manga.lang!.toUpperCase()})/${manga.name!.replaceForbiddenCharacters('_')}/"
.fixSeparator); .fixSeparator);
} }

View file

@ -3,6 +3,7 @@ import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/models/track_preference.dart'; import 'package:mangayomi/models/track_preference.dart';
import 'package:mangayomi/modules/anime/anime_player_view.dart'; import 'package:mangayomi/modules/anime/anime_player_view.dart';
@ -10,6 +11,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/extension_detail.dart';
import 'package:mangayomi/modules/browse/extension/widgets/create_extension.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/browse/sources/sources_filter_screen.dart';
import 'package:mangayomi/modules/novel/novel_reader_view.dart';
import 'package:mangayomi/modules/updates/updates_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/backup_and_restore/backup_and_restore.dart';
import 'package:mangayomi/modules/more/categories/categories_screen.dart'; import 'package:mangayomi/modules/more/categories/categories_screen.dart';
@ -86,12 +88,12 @@ class RouterNotifier extends ChangeNotifier {
name: "MangaLibrary", name: "MangaLibrary",
path: '/MangaLibrary', path: '/MangaLibrary',
builder: (context, state) => const LibraryScreen( builder: (context, state) => const LibraryScreen(
isManga: true, itemType: ItemType.manga,
), ),
pageBuilder: (context, state) => transitionPage( pageBuilder: (context, state) => transitionPage(
key: state.pageKey, key: state.pageKey,
child: const LibraryScreen( child: const LibraryScreen(
isManga: true, itemType: ItemType.manga,
), ),
), ),
), ),
@ -99,12 +101,25 @@ class RouterNotifier extends ChangeNotifier {
name: "AnimeLibrary", name: "AnimeLibrary",
path: '/AnimeLibrary', path: '/AnimeLibrary',
builder: (context, state) => const LibraryScreen( builder: (context, state) => const LibraryScreen(
isManga: false, itemType: ItemType.anime,
), ),
pageBuilder: (context, state) => transitionPage( pageBuilder: (context, state) => transitionPage(
key: state.pageKey, key: state.pageKey,
child: const LibraryScreen( child: const LibraryScreen(
isManga: false, itemType: ItemType.anime,
),
),
),
GoRoute(
name: "NovelLibrary",
path: '/NovelLibrary',
builder: (context, state) => const LibraryScreen(
itemType: ItemType.novel,
),
pageBuilder: (context, state) => transitionPage(
key: state.pageKey,
child: const LibraryScreen(
itemType: ItemType.novel,
), ),
), ),
), ),
@ -184,8 +199,8 @@ class RouterNotifier extends ChangeNotifier {
)); ));
}), }),
GoRoute( GoRoute(
path: "/mangareaderview", path: "/mangaReaderView",
name: "mangareaderview", name: "mangaReaderView",
builder: (context, state) { builder: (context, state) {
final chapter = state.extra as Chapter; final chapter = state.extra as Chapter;
return MangaReaderView( return MangaReaderView(
@ -221,6 +236,25 @@ class RouterNotifier extends ChangeNotifier {
); );
}, },
), ),
GoRoute(
path: "/novelReaderView",
name: "novelReaderView",
builder: (context, state) {
final chapter = state.extra as Chapter;
return NovelReaderView(
chapter: chapter,
);
},
pageBuilder: (context, state) {
final chapter = state.extra as Chapter;
return transitionPage(
key: state.pageKey,
child: NovelReaderView(
chapter: chapter,
),
);
},
),
GoRoute( GoRoute(
path: "/ExtensionLang", path: "/ExtensionLang",
name: "ExtensionLang", name: "ExtensionLang",

View file

@ -1,3 +1,4 @@
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart'; import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
import 'package:mangayomi/services/fetch_sources_list.dart'; import 'package:mangayomi/services/fetch_sources_list.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
@ -13,6 +14,6 @@ Future fetchAnimeSourcesList(Ref ref, {int? id, required bool reFresh}) async {
refresh: reFresh, refresh: reFresh,
id: id, id: id,
ref: ref, ref: ref,
isManga: false); itemType: ItemType.anime);
} }
} }

View file

@ -7,7 +7,7 @@ part of 'fetch_anime_sources.dart';
// ************************************************************************** // **************************************************************************
String _$fetchAnimeSourcesListHash() => String _$fetchAnimeSourcesListHash() =>
r'8fbe1642aee4d475583a1f04b2d236984c6fcfb4'; r'75185e008e90491987fabb55851c536de89653a4';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {

View file

@ -1,3 +1,4 @@
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart'; import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
import 'package:mangayomi/services/fetch_sources_list.dart'; import 'package:mangayomi/services/fetch_sources_list.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
@ -13,6 +14,6 @@ Future fetchMangaSourcesList(Ref ref, {int? id, required reFresh}) async {
refresh: reFresh, refresh: reFresh,
id: id, id: id,
ref: ref, ref: ref,
isManga: true); itemType: ItemType.manga);
} }
} }

View file

@ -7,7 +7,7 @@ part of 'fetch_manga_sources.dart';
// ************************************************************************** // **************************************************************************
String _$fetchMangaSourcesListHash() => String _$fetchMangaSourcesListHash() =>
r'8bc08c334cfdba887227c154e249355f33e69da4'; r'f66f3011e72a3b234d7729ef203fc5f255870db3';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {

View file

@ -0,0 +1,20 @@
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
import 'package:mangayomi/services/fetch_sources_list.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'fetch_novel_sources.g.dart';
@riverpod
Future fetchNovelSourcesList(Ref ref,
{int? id, required reFresh}) async {
if (ref.watch(checkForExtensionsUpdateStateProvider) || reFresh) {
await fetchSourcesList(
sourcesIndexUrl:
"https://raw.githubusercontent.com/Schnitzel5/mangayomi-extensions/refs/heads/main/novel_index.json",
refresh: reFresh,
id: id,
ref: ref,
itemType: ItemType.novel);
}
}

View file

@ -0,0 +1,179 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'fetch_novel_sources.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$fetchNovelSourcesListHash() =>
r'cc4b989c0248c3b16155444c0c429d1ed0025ecb';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// See also [fetchNovelSourcesList].
@ProviderFor(fetchNovelSourcesList)
const fetchNovelSourcesListProvider = FetchNovelSourcesListFamily();
/// See also [fetchNovelSourcesList].
class FetchNovelSourcesListFamily extends Family<AsyncValue> {
/// See also [fetchNovelSourcesList].
const FetchNovelSourcesListFamily();
/// See also [fetchNovelSourcesList].
FetchNovelSourcesListProvider call({
int? id,
required dynamic reFresh,
}) {
return FetchNovelSourcesListProvider(
id: id,
reFresh: reFresh,
);
}
@override
FetchNovelSourcesListProvider getProviderOverride(
covariant FetchNovelSourcesListProvider provider,
) {
return call(
id: provider.id,
reFresh: provider.reFresh,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'fetchNovelSourcesListProvider';
}
/// See also [fetchNovelSourcesList].
class FetchNovelSourcesListProvider extends AutoDisposeFutureProvider<Object?> {
/// See also [fetchNovelSourcesList].
FetchNovelSourcesListProvider({
int? id,
required dynamic reFresh,
}) : this._internal(
(ref) => fetchNovelSourcesList(
ref as FetchNovelSourcesListRef,
id: id,
reFresh: reFresh,
),
from: fetchNovelSourcesListProvider,
name: r'fetchNovelSourcesListProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$fetchNovelSourcesListHash,
dependencies: FetchNovelSourcesListFamily._dependencies,
allTransitiveDependencies:
FetchNovelSourcesListFamily._allTransitiveDependencies,
id: id,
reFresh: reFresh,
);
FetchNovelSourcesListProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.id,
required this.reFresh,
}) : super.internal();
final int? id;
final dynamic reFresh;
@override
Override overrideWith(
FutureOr<Object?> Function(FetchNovelSourcesListRef provider) create,
) {
return ProviderOverride(
origin: this,
override: FetchNovelSourcesListProvider._internal(
(ref) => create(ref as FetchNovelSourcesListRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
id: id,
reFresh: reFresh,
),
);
}
@override
AutoDisposeFutureProviderElement<Object?> createElement() {
return _FetchNovelSourcesListProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is FetchNovelSourcesListProvider &&
other.id == id &&
other.reFresh == reFresh;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, id.hashCode);
hash = _SystemHash.combine(hash, reFresh.hashCode);
return _SystemHash.finish(hash);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin FetchNovelSourcesListRef on AutoDisposeFutureProviderRef<Object?> {
/// The parameter `id` of this provider.
int? get id;
/// The parameter `reFresh` of this provider.
dynamic get reFresh;
}
class _FetchNovelSourcesListProviderElement
extends AutoDisposeFutureProviderElement<Object?>
with FetchNovelSourcesListRef {
_FetchNovelSourcesListProviderElement(super.provider);
@override
int? get id => (origin as FetchNovelSourcesListProvider).id;
@override
dynamic get reFresh => (origin as FetchNovelSourcesListProvider).reFresh;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View file

@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/eval/lib.dart'; import 'package:mangayomi/eval/lib.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart'; import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart'; import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
import 'package:mangayomi/services/http/m_client.dart'; import 'package:mangayomi/services/http/m_client.dart';
@ -13,7 +14,7 @@ Future<void> fetchSourcesList(
required bool refresh, required bool refresh,
required String sourcesIndexUrl, required String sourcesIndexUrl,
required Ref ref, required Ref ref,
required bool isManga}) async { required ItemType itemType}) async {
final http = MClient.init(reqcopyWith: {'useDartHttpClient': true}); final http = MClient.init(reqcopyWith: {'useDartHttpClient': true});
final req = await http.get(Uri.parse(sourcesIndexUrl)); final req = await http.get(Uri.parse(sourcesIndexUrl));
@ -25,7 +26,7 @@ Future<void> fetchSourcesList(
for (var source in sourceList) { for (var source in sourceList) {
if (source.appMinVerReq != null) { if (source.appMinVerReq != null) {
if (compareVersions(info.version, source.appMinVerReq!) > -1) { if (compareVersions(info.version, source.appMinVerReq!) > -1) {
if ((source.isManga ?? true) == isManga) { if (source.itemType == itemType || (!source.isManga! && itemType == ItemType.anime)) {
if (id != null) { if (id != null) {
if (id == source.id) { if (id == source.id) {
final sourc = isar.sources.getSync(id)!; final sourc = isar.sources.getSync(id)!;
@ -52,7 +53,7 @@ Future<void> fetchSourcesList(
..name = source.name ..name = source.name
..version = source.version ..version = source.version
..versionLast = source.version ..versionLast = source.version
..isManga = source.isManga ..itemType = itemType
..isFullData = source.isFullData ?? false ..isFullData = source.isFullData ?? false
..appMinVerReq = source.appMinVerReq ..appMinVerReq = source.appMinVerReq
..sourceCodeLanguage = source.sourceCodeLanguage ..sourceCodeLanguage = source.sourceCodeLanguage
@ -92,7 +93,7 @@ Future<void> fetchSourcesList(
..name = source.name ..name = source.name
..version = source.version ..version = source.version
..versionLast = source.version ..versionLast = source.version
..isManga = source.isManga ..itemType = itemType
..isFullData = source.isFullData ?? false ..isFullData = source.isFullData ?? false
..appMinVerReq = source.appMinVerReq ..appMinVerReq = source.appMinVerReq
..sourceCodeLanguage = source.sourceCodeLanguage ..sourceCodeLanguage = source.sourceCodeLanguage
@ -122,7 +123,7 @@ Future<void> fetchSourcesList(
..name = source.name ..name = source.name
..version = source.version ..version = source.version
..versionLast = source.version ..versionLast = source.version
..isManga = source.isManga ..itemType = itemType
..sourceCodeLanguage = source.sourceCodeLanguage ..sourceCodeLanguage = source.sourceCodeLanguage
..isFullData = source.isFullData ?? false ..isFullData = source.isFullData ?? false
..appMinVerReq = source.appMinVerReq ..appMinVerReq = source.appMinVerReq
@ -134,14 +135,14 @@ Future<void> fetchSourcesList(
} }
} }
}); });
checkIfSourceIsObsolete(sourceList, isManga); checkIfSourceIsObsolete(sourceList, itemType);
} }
void checkIfSourceIsObsolete(List<Source> sourceList, bool isManga) { void checkIfSourceIsObsolete(List<Source> sourceList, ItemType itemType) {
for (var source in isar.sources for (var source in isar.sources
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.isMangaEqualTo(isManga) .itemTypeEqualTo(itemType)
.findAllSync()) { .findAllSync()) {
if (sourceList.isNotEmpty && !(source.isLocal ?? false)) { if (sourceList.isNotEmpty && !(source.isLocal ?? false)) {
final ids = final ids =

View file

@ -0,0 +1,24 @@
import 'package:mangayomi/eval/dart/service.dart';
import 'package:mangayomi/eval/javascript/service.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/utils/utils.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'get_html_content.g.dart';
@riverpod
Future<String> getHtmlContent(Ref ref, {required Chapter chapter}) async {
if (!chapter.manga.isLoaded) {
chapter.manga.loadSync();
}
final source =
getSource(chapter.manga.value!.lang!, chapter.manga.value!.source!);
String? html;
if (source!.sourceCodeLanguage == SourceCodeLanguage.dart) {
html = await DartExtensionService(source).getHtmlContent(chapter.url!);
} else {
html = await JsExtensionService(source).getHtmlContent(chapter.url!);
}
return html;
}

View file

@ -0,0 +1,160 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'get_html_content.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$getHtmlContentHash() => r'709b68d8d590290081b409c22e402b7d1a7eec76';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// See also [getHtmlContent].
@ProviderFor(getHtmlContent)
const getHtmlContentProvider = GetHtmlContentFamily();
/// See also [getHtmlContent].
class GetHtmlContentFamily extends Family<AsyncValue<String>> {
/// See also [getHtmlContent].
const GetHtmlContentFamily();
/// See also [getHtmlContent].
GetHtmlContentProvider call({
required Chapter chapter,
}) {
return GetHtmlContentProvider(
chapter: chapter,
);
}
@override
GetHtmlContentProvider getProviderOverride(
covariant GetHtmlContentProvider provider,
) {
return call(
chapter: provider.chapter,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'getHtmlContentProvider';
}
/// See also [getHtmlContent].
class GetHtmlContentProvider extends AutoDisposeFutureProvider<String> {
/// See also [getHtmlContent].
GetHtmlContentProvider({
required Chapter chapter,
}) : this._internal(
(ref) => getHtmlContent(
ref as GetHtmlContentRef,
chapter: chapter,
),
from: getHtmlContentProvider,
name: r'getHtmlContentProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$getHtmlContentHash,
dependencies: GetHtmlContentFamily._dependencies,
allTransitiveDependencies:
GetHtmlContentFamily._allTransitiveDependencies,
chapter: chapter,
);
GetHtmlContentProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.chapter,
}) : super.internal();
final Chapter chapter;
@override
Override overrideWith(
FutureOr<String> Function(GetHtmlContentRef provider) create,
) {
return ProviderOverride(
origin: this,
override: GetHtmlContentProvider._internal(
(ref) => create(ref as GetHtmlContentRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
chapter: chapter,
),
);
}
@override
AutoDisposeFutureProviderElement<String> createElement() {
return _GetHtmlContentProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is GetHtmlContentProvider && other.chapter == chapter;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, chapter.hashCode);
return _SystemHash.finish(hash);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin GetHtmlContentRef on AutoDisposeFutureProviderRef<String> {
/// The parameter `chapter` of this provider.
Chapter get chapter;
}
class _GetHtmlContentProviderElement
extends AutoDisposeFutureProviderElement<String> with GetHtmlContentRef {
_GetHtmlContentProviderElement(super.provider);
@override
Chapter get chapter => (origin as GetHtmlContentProvider).chapter;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View file

@ -98,10 +98,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: build name: build
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.1" version: "2.4.2"
build_cli_annotations: build_cli_annotations:
dependency: transitive dependency: transitive
description: description:
@ -114,42 +114,42 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: build_config name: build_config
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.1.2"
build_daemon: build_daemon:
dependency: transitive dependency: transitive
description: description:
name: build_daemon name: build_daemon
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" sha256: "294a2edaf4814a378725bfe6358210196f5ea37af89ecd81bfa32960113d4948"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "4.0.3"
build_resolvers: build_resolvers:
dependency: transitive dependency: transitive
description: description:
name: build_resolvers name: build_resolvers
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" sha256: "99d3980049739a985cf9b21f30881f46db3ebc62c5b8d5e60e27440876b1ba1e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.2" version: "2.4.3"
build_runner: build_runner:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" sha256: "74691599a5bc750dc96a6b4bfd48f7d9d66453eab04c7f4063134800d6a5c573"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.13" version: "2.4.14"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
name: build_runner_core name: build_runner_core
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.3.2" version: "8.0.0"
built_collection: built_collection:
dependency: transitive dependency: transitive
description: description:
@ -162,10 +162,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: built_value name: built_value
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.9.2" version: "8.9.3"
change_case: change_case:
dependency: transitive dependency: transitive
description: description:
@ -258,10 +258,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: csslib name: csslib
sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "0.17.3"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
@ -484,6 +484,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.0" version: "0.7.0"
flutter_html:
dependency: "direct main"
description:
name: flutter_html
sha256: "02ad69e813ecfc0728a455e4bf892b9379983e050722b1dce00192ee2e41d1ee"
url: "https://pub.dev"
source: hosted
version: "3.0.0-beta.2"
flutter_inappwebview: flutter_inappwebview:
dependency: "direct main" dependency: "direct main"
description: description:
@ -573,10 +581,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: flutter_plugin_android_lifecycle name: flutter_plugin_android_lifecycle
sha256: "9b78450b89f059e96c9ebb355fa6b3df1d6b330436e0b885fb49594c41721398" sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.23" version: "2.0.24"
flutter_qjs: flutter_qjs:
dependency: "direct main" dependency: "direct main"
description: description:
@ -720,10 +728,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: html name: html
sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.15.5" version: "0.15.4"
http: http:
dependency: "direct main" dependency: "direct main"
description: description:
@ -752,10 +760,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: http_multi_server name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.1" version: "3.2.2"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
@ -916,6 +924,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.0" version: "5.1.0"
list_counter:
dependency: transitive
description:
name: list_counter
sha256: c447ae3dfcd1c55f0152867090e67e219d42fe6d4f2807db4bbe8b8d69912237
url: "https://pub.dev"
source: hosted
version: "1.0.2"
logging: logging:
dependency: transitive dependency: transitive
description: description:
@ -1535,10 +1551,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: stream_transform name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.1"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
@ -1743,10 +1759,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: watcher name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.1"
web: web:
dependency: transitive dependency: transitive
description: description:

View file

@ -78,6 +78,7 @@ dependencies:
path: packages/desktop_webview_window path: packages/desktop_webview_window
ref: main ref: main
screen_brightness: ^2.0.1 screen_brightness: ^2.0.1
flutter_html: ^3.0.0-beta.2
dependency_overrides: dependency_overrides:
http: ^1.2.2 http: ^1.2.2