Merge pull request #346 from Schnitzel5/feature/light-novel
add novel support
This commit is contained in:
commit
6a7ab3eed4
103 changed files with 6372 additions and 4365 deletions
3
devtools_options.yaml
Normal file
3
devtools_options.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
||||
|
|
@ -99,6 +99,13 @@ class $MProvider extends MProvider with $Bridge<MProvider> {
|
|||
BridgeParameter('url',
|
||||
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(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(
|
||||
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();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> getHtmlContent(String url) async =>
|
||||
await $_invoke('getHtmlContent', [$String(url)]);
|
||||
|
||||
@override
|
||||
Map<String, String> get headers {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -115,6 +115,11 @@ class DartExtensionService implements ExtensionService {
|
|||
return await _executeLib().getVideoList(url);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> getHtmlContent(String url) async {
|
||||
return await _executeLib().getHtmlContent(url);
|
||||
}
|
||||
|
||||
@override
|
||||
FilterList getFilterList() {
|
||||
List<dynamic> list;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ abstract interface class ExtensionService {
|
|||
|
||||
Future<List<Video>> getVideoList(String url);
|
||||
|
||||
Future<String> getHtmlContent(String url);
|
||||
|
||||
FilterList getFilterList();
|
||||
|
||||
List<SourcePreference> getSourcePreferences();
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ class MProvider {
|
|||
async getVideoList(url) {
|
||||
throw new Error("getVideoList not implemented");
|
||||
}
|
||||
async getHtmlContent(url) {
|
||||
throw new Error("getHtmlContent not implemented");
|
||||
}
|
||||
getFilterList() {
|
||||
throw new Error("getFilterList not implemented");
|
||||
}
|
||||
|
|
@ -135,6 +138,15 @@ var extention = new DefaultExtension();
|
|||
.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
|
||||
FilterList getFilterList() {
|
||||
List<dynamic> list;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ abstract class MProvider {
|
|||
|
||||
Future<List<Video>> getVideoList(String url);
|
||||
|
||||
Future<String> getHtmlContent(String url);
|
||||
|
||||
List<dynamic> getFilterList();
|
||||
|
||||
List<dynamic> getSourcePreferences();
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@
|
|||
"anime_sources": "Anime-Quellen",
|
||||
"anime_extensions": "Anime-Erweiterungen",
|
||||
"manga_extensions": "Manga-Erweiterungen",
|
||||
"novel": "Novel",
|
||||
"anime": "Anime",
|
||||
"manga": "Manga",
|
||||
"library_no_category_exist": "Du hast noch keine Kategorien",
|
||||
|
|
|
|||
|
|
@ -215,16 +215,22 @@
|
|||
"sync_confirm_download": "A full download will completely replace your current data with the remote one!",
|
||||
"dialog_confirm": "Confirm",
|
||||
"description": "Description",
|
||||
"hide_manga": "Hide some elements related to mangas.",
|
||||
"hide_anime": "Hide some elements related to animes.",
|
||||
"hide_novel": "Hide some elements related to (light) novels.",
|
||||
"full_screen_player": "Use Fullscreen",
|
||||
"full_screen_player_info": "Automatically use fullscreen when playing a video.",
|
||||
"episode_progress": "Progress: {n}",
|
||||
"n_episodes": "{n} episodes",
|
||||
"manga_sources": "Manga Sources",
|
||||
"anime_sources": "Anime Sources",
|
||||
"novel_sources": "Novel Sources",
|
||||
"anime_extensions": "Anime Extensions",
|
||||
"manga_extensions": "Manga Extensions",
|
||||
"novel_extensions": "Novel Extensions",
|
||||
"anime": "Anime",
|
||||
"manga": "Manga",
|
||||
"novel": "Novel",
|
||||
"library_no_category_exist": "You don't have any categories yet",
|
||||
"watching": "Watching",
|
||||
"plan_to_watch": "Plan to watch",
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@ import 'package:mangayomi/modules/more/settings/appearance/providers/blend_level
|
|||
import 'package:mangayomi/modules/more/settings/appearance/providers/flex_scheme_color_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/providers/pure_black_dark_mode_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/services/sync_server.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:mangayomi/src/rust/frb_generated.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
|
|
@ -82,10 +80,6 @@ class _MyAppState extends ConsumerState<MyApp> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final syncOnAppLaunch = ref.watch(syncOnAppLaunchStateProvider);
|
||||
if (syncOnAppLaunch) {
|
||||
ref.read(syncServerProvider(syncId: 1).notifier).checkForSync(true);
|
||||
}
|
||||
final isDarkTheme = ref.watch(themeModeStateProvider);
|
||||
final blendLevel = ref.watch(blendLevelStateProvider);
|
||||
final appFontFamily = ref.watch(appFontFamilyProvider);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
part 'category.g.dart';
|
||||
|
||||
@collection
|
||||
|
|
@ -7,17 +8,30 @@ class Category {
|
|||
Id? id;
|
||||
String? name;
|
||||
bool? forManga;
|
||||
@enumerated
|
||||
late ItemType forItemType;
|
||||
Category(
|
||||
{this.id = Isar.autoIncrement,
|
||||
required this.name,
|
||||
required this.forManga});
|
||||
this.forManga = true,
|
||||
required this.forItemType});
|
||||
|
||||
Category.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
name = json['name'];
|
||||
forManga = json['forManga'];
|
||||
forItemType = ItemType.values[json['forItemType'] ?? 0];
|
||||
}
|
||||
|
||||
Category.fromJsonV1(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
name = json['name'];
|
||||
forItemType = json['forManga'] is bool
|
||||
? json['forManga'] == true
|
||||
? ItemType.manga
|
||||
: ItemType.anime
|
||||
: ItemType.manga;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() =>
|
||||
{'id': id, 'name': name, 'forManga': forManga};
|
||||
{'id': id, 'name': name, 'forItemType': forItemType.index};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,13 +17,19 @@ const CategorySchema = CollectionSchema(
|
|||
name: r'Category',
|
||||
id: 5751694338128944171,
|
||||
properties: {
|
||||
r'forManga': PropertySchema(
|
||||
r'forItemType': PropertySchema(
|
||||
id: 0,
|
||||
name: r'forItemType',
|
||||
type: IsarType.byte,
|
||||
enumMap: _CategoryforItemTypeEnumValueMap,
|
||||
),
|
||||
r'forManga': PropertySchema(
|
||||
id: 1,
|
||||
name: r'forManga',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'name': PropertySchema(
|
||||
id: 1,
|
||||
id: 2,
|
||||
name: r'name',
|
||||
type: IsarType.string,
|
||||
)
|
||||
|
|
@ -63,8 +69,9 @@ void _categorySerialize(
|
|||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
writer.writeBool(offsets[0], object.forManga);
|
||||
writer.writeString(offsets[1], object.name);
|
||||
writer.writeByte(offsets[0], object.forItemType.index);
|
||||
writer.writeBool(offsets[1], object.forManga);
|
||||
writer.writeString(offsets[2], object.name);
|
||||
}
|
||||
|
||||
Category _categoryDeserialize(
|
||||
|
|
@ -74,9 +81,12 @@ Category _categoryDeserialize(
|
|||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
final object = Category(
|
||||
forManga: reader.readBoolOrNull(offsets[0]),
|
||||
forItemType:
|
||||
_CategoryforItemTypeValueEnumMap[reader.readByteOrNull(offsets[0])] ??
|
||||
ItemType.manga,
|
||||
forManga: reader.readBoolOrNull(offsets[1]),
|
||||
id: id,
|
||||
name: reader.readStringOrNull(offsets[1]),
|
||||
name: reader.readStringOrNull(offsets[2]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
|
@ -89,14 +99,28 @@ P _categoryDeserializeProp<P>(
|
|||
) {
|
||||
switch (propertyId) {
|
||||
case 0:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
return (_CategoryforItemTypeValueEnumMap[reader.readByteOrNull(offset)] ??
|
||||
ItemType.manga) as P;
|
||||
case 1:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 2:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
}
|
||||
}
|
||||
|
||||
const _CategoryforItemTypeEnumValueMap = {
|
||||
'manga': 0,
|
||||
'anime': 1,
|
||||
'novel': 2,
|
||||
};
|
||||
const _CategoryforItemTypeValueEnumMap = {
|
||||
0: ItemType.manga,
|
||||
1: ItemType.anime,
|
||||
2: ItemType.novel,
|
||||
};
|
||||
|
||||
Id _categoryGetId(Category object) {
|
||||
return object.id ?? Isar.autoIncrement;
|
||||
}
|
||||
|
|
@ -186,6 +210,60 @@ extension CategoryQueryWhere on QueryBuilder<Category, Category, QWhereClause> {
|
|||
|
||||
extension CategoryQueryFilter
|
||||
on QueryBuilder<Category, Category, QFilterCondition> {
|
||||
QueryBuilder<Category, Category, QAfterFilterCondition> forItemTypeEqualTo(
|
||||
ItemType value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'forItemType',
|
||||
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> forMangaIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
|
@ -434,6 +512,18 @@ extension CategoryQueryLinks
|
|||
on QueryBuilder<Category, Category, QFilterCondition> {}
|
||||
|
||||
extension CategoryQuerySortBy on QueryBuilder<Category, Category, QSortBy> {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByForItemType() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'forItemType', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByForItemTypeDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'forItemType', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> sortByForManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'forManga', Sort.asc);
|
||||
|
|
@ -461,6 +551,18 @@ extension CategoryQuerySortBy on QueryBuilder<Category, Category, QSortBy> {
|
|||
|
||||
extension CategoryQuerySortThenBy
|
||||
on QueryBuilder<Category, Category, QSortThenBy> {
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByForItemType() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'forItemType', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByForItemTypeDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'forItemType', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QAfterSortBy> thenByForManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'forManga', Sort.asc);
|
||||
|
|
@ -500,6 +602,12 @@ extension CategoryQuerySortThenBy
|
|||
|
||||
extension CategoryQueryWhereDistinct
|
||||
on QueryBuilder<Category, Category, QDistinct> {
|
||||
QueryBuilder<Category, Category, QDistinct> distinctByForItemType() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'forItemType');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, Category, QDistinct> distinctByForManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'forManga');
|
||||
|
|
@ -522,6 +630,12 @@ extension CategoryQueryProperty
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, ItemType, QQueryOperations> forItemTypeProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'forItemType');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Category, bool?, QQueryOperations> forMangaProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'forManga');
|
||||
|
|
|
|||
|
|
@ -1,86 +0,0 @@
|
|||
import 'package:isar/isar.dart';
|
||||
part 'changed_items.g.dart';
|
||||
|
||||
@collection
|
||||
@Name("Changed Items")
|
||||
class ChangedItems {
|
||||
Id? id;
|
||||
List<DeletedManga>? deletedMangas;
|
||||
List<UpdatedChapter>? updatedChapters;
|
||||
List<DeletedCategory>? deletedCategories;
|
||||
ChangedItems(
|
||||
{this.id = Isar.autoIncrement,
|
||||
this.deletedMangas = const [],
|
||||
this.updatedChapters = const [],
|
||||
this.deletedCategories = const []});
|
||||
|
||||
ChangedItems.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
deletedMangas = json['deletedMangas'];
|
||||
updatedChapters = json['updatedChapters'];
|
||||
deletedCategories = json['deletedCategories'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'deletedMangas': deletedMangas,
|
||||
'updatedChapters': updatedChapters,
|
||||
'deletedCategories': deletedCategories
|
||||
};
|
||||
}
|
||||
|
||||
@embedded
|
||||
class DeletedManga {
|
||||
int? mangaId;
|
||||
DeletedManga({this.mangaId});
|
||||
DeletedManga.fromJson(Map<String, dynamic> json) {
|
||||
mangaId = json['mangaId'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {'mangaId': mangaId};
|
||||
}
|
||||
|
||||
@embedded
|
||||
class UpdatedChapter {
|
||||
int? chapterId;
|
||||
int? mangaId;
|
||||
bool? isBookmarked;
|
||||
bool? isRead;
|
||||
String? lastPageRead;
|
||||
bool? deleted;
|
||||
UpdatedChapter(
|
||||
{this.chapterId,
|
||||
this.mangaId,
|
||||
this.isBookmarked,
|
||||
this.isRead,
|
||||
this.lastPageRead,
|
||||
this.deleted});
|
||||
UpdatedChapter.fromJson(Map<String, dynamic> json) {
|
||||
chapterId = json['chapterId'];
|
||||
mangaId = json['mangaId'];
|
||||
isBookmarked = json['isBookmarked'];
|
||||
isRead = json['isRead'];
|
||||
lastPageRead = json['lastPageRead'];
|
||||
deleted = json['deleted'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'chapterId': chapterId,
|
||||
'mangaId': mangaId,
|
||||
'isBookmarked': isBookmarked,
|
||||
'isRead': isRead,
|
||||
'lastPageRead': lastPageRead,
|
||||
'deleted': deleted
|
||||
};
|
||||
}
|
||||
|
||||
@embedded
|
||||
class DeletedCategory {
|
||||
int? categoryId;
|
||||
DeletedCategory({this.categoryId});
|
||||
DeletedCategory.fromJson(Map<String, dynamic> json) {
|
||||
categoryId = json['categoryId'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {'categoryId': categoryId};
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
part 'history.g.dart';
|
||||
|
||||
@collection
|
||||
|
|
@ -13,13 +14,17 @@ class History {
|
|||
|
||||
bool? isManga;
|
||||
|
||||
@enumerated
|
||||
late ItemType itemType;
|
||||
|
||||
final chapter = IsarLink<Chapter>();
|
||||
|
||||
String? date;
|
||||
|
||||
History({
|
||||
this.id = Isar.autoIncrement,
|
||||
required this.isManga,
|
||||
this.isManga = true,
|
||||
required this.itemType,
|
||||
required this.chapterId,
|
||||
required this.mangaId,
|
||||
required this.date,
|
||||
|
|
@ -29,7 +34,19 @@ class History {
|
|||
chapterId = json['chapterId'];
|
||||
date = json['date'];
|
||||
id = json['id'];
|
||||
isManga = json['isManga'];
|
||||
itemType = ItemType.values[json['itemType'] ?? 0];
|
||||
mangaId = json['mangaId'];
|
||||
}
|
||||
|
||||
History.fromJsonV1(Map<String, dynamic> json) {
|
||||
chapterId = json['chapterId'];
|
||||
date = json['date'];
|
||||
id = json['id'];
|
||||
itemType = json['isManga'] is bool
|
||||
? json['isManga'] == true
|
||||
? ItemType.manga
|
||||
: ItemType.anime
|
||||
: ItemType.manga;
|
||||
mangaId = json['mangaId'];
|
||||
}
|
||||
|
||||
|
|
@ -37,7 +54,7 @@ class History {
|
|||
'chapterId': chapterId,
|
||||
'date': date,
|
||||
'id': id,
|
||||
'isManga': isManga,
|
||||
'itemType': itemType.index,
|
||||
'mangaId': mangaId
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,8 +32,14 @@ const HistorySchema = CollectionSchema(
|
|||
name: r'isManga',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'mangaId': PropertySchema(
|
||||
r'itemType': PropertySchema(
|
||||
id: 3,
|
||||
name: r'itemType',
|
||||
type: IsarType.byte,
|
||||
enumMap: _HistoryitemTypeEnumValueMap,
|
||||
),
|
||||
r'mangaId': PropertySchema(
|
||||
id: 4,
|
||||
name: r'mangaId',
|
||||
type: IsarType.long,
|
||||
)
|
||||
|
|
@ -83,7 +89,8 @@ void _historySerialize(
|
|||
writer.writeLong(offsets[0], object.chapterId);
|
||||
writer.writeString(offsets[1], object.date);
|
||||
writer.writeBool(offsets[2], object.isManga);
|
||||
writer.writeLong(offsets[3], object.mangaId);
|
||||
writer.writeByte(offsets[3], object.itemType.index);
|
||||
writer.writeLong(offsets[4], object.mangaId);
|
||||
}
|
||||
|
||||
History _historyDeserialize(
|
||||
|
|
@ -97,7 +104,9 @@ History _historyDeserialize(
|
|||
date: reader.readStringOrNull(offsets[1]),
|
||||
id: id,
|
||||
isManga: reader.readBoolOrNull(offsets[2]),
|
||||
mangaId: reader.readLongOrNull(offsets[3]),
|
||||
itemType: _HistoryitemTypeValueEnumMap[reader.readByteOrNull(offsets[3])] ??
|
||||
ItemType.manga,
|
||||
mangaId: reader.readLongOrNull(offsets[4]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
|
@ -116,12 +125,26 @@ P _historyDeserializeProp<P>(
|
|||
case 2:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 3:
|
||||
return (_HistoryitemTypeValueEnumMap[reader.readByteOrNull(offset)] ??
|
||||
ItemType.manga) as P;
|
||||
case 4:
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
}
|
||||
}
|
||||
|
||||
const _HistoryitemTypeEnumValueMap = {
|
||||
'manga': 0,
|
||||
'anime': 1,
|
||||
'novel': 2,
|
||||
};
|
||||
const _HistoryitemTypeValueEnumMap = {
|
||||
0: ItemType.manga,
|
||||
1: ItemType.anime,
|
||||
2: ItemType.novel,
|
||||
};
|
||||
|
||||
Id _historyGetId(History object) {
|
||||
return object.id ?? Isar.autoIncrement;
|
||||
}
|
||||
|
|
@ -521,6 +544,59 @@ extension HistoryQueryFilter
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterFilterCondition> itemTypeEqualTo(
|
||||
ItemType value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'itemType',
|
||||
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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
|
@ -647,6 +723,18 @@ extension HistoryQuerySortBy on QueryBuilder<History, History, QSortBy> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> sortByItemType() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'itemType', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> sortByItemTypeDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'itemType', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> sortByMangaId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'mangaId', Sort.asc);
|
||||
|
|
@ -710,6 +798,18 @@ extension HistoryQuerySortThenBy
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> thenByItemType() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'itemType', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> thenByItemTypeDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'itemType', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> thenByMangaId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'mangaId', Sort.asc);
|
||||
|
|
@ -744,6 +844,12 @@ extension HistoryQueryWhereDistinct
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QDistinct> distinctByItemType() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'itemType');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QDistinct> distinctByMangaId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'mangaId');
|
||||
|
|
@ -777,6 +883,12 @@ extension HistoryQueryProperty
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, ItemType, QQueryOperations> itemTypeProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'itemType');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, int?, QQueryOperations> mangaIdProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'mangaId');
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ class Manga {
|
|||
|
||||
bool? isManga;
|
||||
|
||||
@enumerated
|
||||
late ItemType itemType;
|
||||
|
||||
List<String>? genre;
|
||||
|
||||
bool? favorite;
|
||||
|
|
@ -63,6 +66,7 @@ class Manga {
|
|||
required this.status,
|
||||
required this.description,
|
||||
this.isManga = true,
|
||||
this.itemType = ItemType.manga,
|
||||
this.dateAdded,
|
||||
this.lastUpdate,
|
||||
this.categories,
|
||||
|
|
@ -83,7 +87,34 @@ class Manga {
|
|||
id = json['id'];
|
||||
imageUrl = json['imageUrl'];
|
||||
isLocalArchive = json['isLocalArchive'];
|
||||
isManga = json['isManga'];
|
||||
itemType = ItemType.values[json['itemType'] ?? 0];
|
||||
lang = json['lang'];
|
||||
lastRead = json['lastRead'];
|
||||
lastUpdate = json['lastUpdate'];
|
||||
link = json['link'];
|
||||
name = json['name'];
|
||||
source = json['source'];
|
||||
status = Status.values[json['status']];
|
||||
customCoverFromTracker = json['customCoverFromTracker'];
|
||||
}
|
||||
|
||||
Manga.fromJsonV1(Map<String, dynamic> json) {
|
||||
author = json['author'];
|
||||
artist = json['artist'];
|
||||
categories = json['categories']?.cast<int>();
|
||||
customCoverImage = json['customCoverImage']?.cast<int>();
|
||||
dateAdded = json['dateAdded'];
|
||||
description = json['description'];
|
||||
favorite = json['favorite']!;
|
||||
genre = json['genre']?.cast<String>();
|
||||
id = json['id'];
|
||||
imageUrl = json['imageUrl'];
|
||||
isLocalArchive = json['isLocalArchive'];
|
||||
itemType = json['isManga'] is bool
|
||||
? json['isManga'] == true
|
||||
? ItemType.manga
|
||||
: ItemType.anime
|
||||
: ItemType.manga;
|
||||
lang = json['lang'];
|
||||
lastRead = json['lastRead'];
|
||||
lastUpdate = json['lastUpdate'];
|
||||
|
|
@ -106,7 +137,7 @@ class Manga {
|
|||
'id': id,
|
||||
'imageUrl': imageUrl,
|
||||
'isLocalArchive': isLocalArchive,
|
||||
'isManga': isManga,
|
||||
'itemType': itemType.index,
|
||||
'lang': lang,
|
||||
'lastRead': lastRead,
|
||||
'lastUpdate': lastUpdate,
|
||||
|
|
@ -126,3 +157,5 @@ enum Status {
|
|||
onHiatus,
|
||||
publishingFinished
|
||||
}
|
||||
|
||||
enum ItemType { manga, anime, novel }
|
||||
|
|
|
|||
|
|
@ -77,38 +77,44 @@ const MangaSchema = CollectionSchema(
|
|||
name: r'isManga',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'lang': PropertySchema(
|
||||
r'itemType': PropertySchema(
|
||||
id: 12,
|
||||
name: r'itemType',
|
||||
type: IsarType.byte,
|
||||
enumMap: _MangaitemTypeEnumValueMap,
|
||||
),
|
||||
r'lang': PropertySchema(
|
||||
id: 13,
|
||||
name: r'lang',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'lastRead': PropertySchema(
|
||||
id: 13,
|
||||
id: 14,
|
||||
name: r'lastRead',
|
||||
type: IsarType.long,
|
||||
),
|
||||
r'lastUpdate': PropertySchema(
|
||||
id: 14,
|
||||
id: 15,
|
||||
name: r'lastUpdate',
|
||||
type: IsarType.long,
|
||||
),
|
||||
r'link': PropertySchema(
|
||||
id: 15,
|
||||
id: 16,
|
||||
name: r'link',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'name': PropertySchema(
|
||||
id: 16,
|
||||
id: 17,
|
||||
name: r'name',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'source': PropertySchema(
|
||||
id: 17,
|
||||
id: 18,
|
||||
name: r'source',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'status': PropertySchema(
|
||||
id: 18,
|
||||
id: 19,
|
||||
name: r'status',
|
||||
type: IsarType.byte,
|
||||
enumMap: _MangastatusEnumValueMap,
|
||||
|
|
@ -241,13 +247,14 @@ void _mangaSerialize(
|
|||
writer.writeString(offsets[9], object.imageUrl);
|
||||
writer.writeBool(offsets[10], object.isLocalArchive);
|
||||
writer.writeBool(offsets[11], object.isManga);
|
||||
writer.writeString(offsets[12], object.lang);
|
||||
writer.writeLong(offsets[13], object.lastRead);
|
||||
writer.writeLong(offsets[14], object.lastUpdate);
|
||||
writer.writeString(offsets[15], object.link);
|
||||
writer.writeString(offsets[16], object.name);
|
||||
writer.writeString(offsets[17], object.source);
|
||||
writer.writeByte(offsets[18], object.status.index);
|
||||
writer.writeByte(offsets[12], object.itemType.index);
|
||||
writer.writeString(offsets[13], object.lang);
|
||||
writer.writeLong(offsets[14], object.lastRead);
|
||||
writer.writeLong(offsets[15], object.lastUpdate);
|
||||
writer.writeString(offsets[16], object.link);
|
||||
writer.writeString(offsets[17], object.name);
|
||||
writer.writeString(offsets[18], object.source);
|
||||
writer.writeByte(offsets[19], object.status.index);
|
||||
}
|
||||
|
||||
Manga _mangaDeserialize(
|
||||
|
|
@ -270,13 +277,15 @@ Manga _mangaDeserialize(
|
|||
imageUrl: reader.readStringOrNull(offsets[9]),
|
||||
isLocalArchive: reader.readBoolOrNull(offsets[10]),
|
||||
isManga: reader.readBoolOrNull(offsets[11]),
|
||||
lang: reader.readStringOrNull(offsets[12]),
|
||||
lastRead: reader.readLongOrNull(offsets[13]),
|
||||
lastUpdate: reader.readLongOrNull(offsets[14]),
|
||||
link: reader.readStringOrNull(offsets[15]),
|
||||
name: reader.readStringOrNull(offsets[16]),
|
||||
source: reader.readStringOrNull(offsets[17]),
|
||||
status: _MangastatusValueEnumMap[reader.readByteOrNull(offsets[18])] ??
|
||||
itemType: _MangaitemTypeValueEnumMap[reader.readByteOrNull(offsets[12])] ??
|
||||
ItemType.manga,
|
||||
lang: reader.readStringOrNull(offsets[13]),
|
||||
lastRead: reader.readLongOrNull(offsets[14]),
|
||||
lastUpdate: reader.readLongOrNull(offsets[15]),
|
||||
link: reader.readStringOrNull(offsets[16]),
|
||||
name: reader.readStringOrNull(offsets[17]),
|
||||
source: reader.readStringOrNull(offsets[18]),
|
||||
status: _MangastatusValueEnumMap[reader.readByteOrNull(offsets[19])] ??
|
||||
Status.ongoing,
|
||||
);
|
||||
return object;
|
||||
|
|
@ -314,18 +323,21 @@ P _mangaDeserializeProp<P>(
|
|||
case 11:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 12:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
return (_MangaitemTypeValueEnumMap[reader.readByteOrNull(offset)] ??
|
||||
ItemType.manga) as P;
|
||||
case 13:
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 14:
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
case 15:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
case 16:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 17:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 18:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 19:
|
||||
return (_MangastatusValueEnumMap[reader.readByteOrNull(offset)] ??
|
||||
Status.ongoing) as P;
|
||||
default:
|
||||
|
|
@ -333,6 +345,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 = {
|
||||
'ongoing': 0,
|
||||
'completed': 1,
|
||||
|
|
@ -1937,6 +1959,59 @@ extension MangaQueryFilter on QueryBuilder<Manga, Manga, QFilterCondition> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterFilterCondition> itemTypeEqualTo(
|
||||
ItemType value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'itemType',
|
||||
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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
|
@ -2875,6 +2950,18 @@ extension MangaQuerySortBy on QueryBuilder<Manga, Manga, QSortBy> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterSortBy> sortByItemType() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'itemType', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterSortBy> sortByItemTypeDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'itemType', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterSortBy> sortByLang() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'lang', Sort.asc);
|
||||
|
|
@ -3081,6 +3168,18 @@ extension MangaQuerySortThenBy on QueryBuilder<Manga, Manga, QSortThenBy> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterSortBy> thenByItemType() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'itemType', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterSortBy> thenByItemTypeDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'itemType', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterSortBy> thenByLang() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'lang', Sort.asc);
|
||||
|
|
@ -3245,6 +3344,12 @@ extension MangaQueryWhereDistinct on QueryBuilder<Manga, Manga, QDistinct> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QDistinct> distinctByItemType() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'itemType');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QDistinct> distinctByLang(
|
||||
{bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
|
|
@ -3372,6 +3477,12 @@ extension MangaQueryProperty on QueryBuilder<Manga, Manga, QQueryProperty> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, ItemType, QQueryOperations> itemTypeProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'itemType');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, String?, QQueryOperations> langProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'lang');
|
||||
|
|
|
|||
|
|
@ -135,10 +135,6 @@ class Settings {
|
|||
|
||||
List<int>? backupFrequencyOptions;
|
||||
|
||||
bool? syncOnAppLaunch;
|
||||
|
||||
bool? syncAfterReading;
|
||||
|
||||
String? autoBackupLocation;
|
||||
|
||||
bool? usePageTapZones;
|
||||
|
|
@ -187,11 +183,44 @@ class Settings {
|
|||
|
||||
int? animeGridSize;
|
||||
|
||||
int? novelGridSize;
|
||||
|
||||
@enumerated
|
||||
late SectionType disableSectionType;
|
||||
|
||||
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;
|
||||
|
||||
bool? hideManga;
|
||||
|
||||
bool? hideAnime;
|
||||
|
||||
bool? hideNovel;
|
||||
|
||||
Settings(
|
||||
{this.id = 227,
|
||||
this.displayType = DisplayType.compactGrid,
|
||||
|
|
@ -249,8 +278,6 @@ class Settings {
|
|||
this.personalPageModeList,
|
||||
this.backupFrequency,
|
||||
this.backupFrequencyOptions,
|
||||
this.syncOnAppLaunch,
|
||||
this.syncAfterReading,
|
||||
this.autoBackupLocation,
|
||||
this.startDatebackup,
|
||||
this.usePageTapZones = true,
|
||||
|
|
@ -276,7 +303,22 @@ class Settings {
|
|||
this.mangaGridSize,
|
||||
this.animeGridSize,
|
||||
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,
|
||||
this.hideManga = false,
|
||||
this.hideAnime = false,
|
||||
this.hideNovel = false});
|
||||
|
||||
Settings.fromJson(Map<String, dynamic> json) {
|
||||
animatePageTransitions = json['animatePageTransitions'];
|
||||
|
|
@ -397,8 +439,6 @@ class Settings {
|
|||
userAgent = json['userAgent'];
|
||||
backupFrequency = json['backupFrequency'];
|
||||
backupFrequencyOptions = json['backupFrequencyOptions']?.cast<int>();
|
||||
syncOnAppLaunch = json['syncOnAppLaunch'];
|
||||
syncAfterReading = json['syncAfterReading'];
|
||||
autoBackupLocation = json['autoBackupLocation'];
|
||||
startDatebackup = json['startDatebackup'];
|
||||
usePageTapZones = json['usePageTapZones'];
|
||||
|
|
@ -432,6 +472,25 @@ class Settings {
|
|||
disableSectionType =
|
||||
SectionType.values[json['disableSectionType'] ?? SectionType.all];
|
||||
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];
|
||||
hideManga = json['hideManga'];
|
||||
hideAnime = json['hideAnime'];
|
||||
hideNovel = json['hideNovel'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
|
|
@ -504,8 +563,6 @@ class Settings {
|
|||
'userAgent': userAgent,
|
||||
'backupFrequency': backupFrequency,
|
||||
'backupFrequencyOptions': backupFrequencyOptions,
|
||||
'syncOnAppLaunch': syncOnAppLaunch,
|
||||
'syncAfterReading': syncAfterReading,
|
||||
'autoBackupLocation': autoBackupLocation,
|
||||
'startDatebackup': startDatebackup,
|
||||
'usePageTapZones': usePageTapZones,
|
||||
|
|
@ -532,7 +589,23 @@ class Settings {
|
|||
'mangaGridSize': mangaGridSize,
|
||||
'animeGridSize': animeGridSize,
|
||||
'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,
|
||||
'hideManga': hideManga,
|
||||
'hideAnime': hideAnime,
|
||||
'hideNovel': hideNovel
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/eval/model/m_source.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
part 'source.g.dart';
|
||||
|
||||
@collection
|
||||
|
|
@ -49,6 +50,9 @@ class Source {
|
|||
|
||||
bool? isManga;
|
||||
|
||||
@enumerated
|
||||
late ItemType itemType;
|
||||
|
||||
String? appMinVerReq;
|
||||
|
||||
String? additionalParams;
|
||||
|
|
@ -83,6 +87,7 @@ class Source {
|
|||
this.sourceCode = '',
|
||||
this.headers = '',
|
||||
this.isManga = true,
|
||||
this.itemType = ItemType.manga,
|
||||
this.appMinVerReq = "",
|
||||
this.additionalParams = "",
|
||||
this.isLocal = false,
|
||||
|
|
@ -102,6 +107,39 @@ class Source {
|
|||
isAdded = json['isAdded'];
|
||||
isFullData = json['isFullData'];
|
||||
isManga = json['isManga'];
|
||||
itemType = ItemType.values[json['itemType'] ?? 0];
|
||||
isNsfw = json['isNsfw'];
|
||||
isPinned = json['isPinned'];
|
||||
lang = json['lang'];
|
||||
lastUsed = json['lastUsed'];
|
||||
name = json['name'];
|
||||
sourceCode = json['sourceCode'];
|
||||
sourceCodeUrl = json['sourceCodeUrl'];
|
||||
typeSource = json['typeSource'];
|
||||
version = json['version'];
|
||||
versionLast = json['versionLast'];
|
||||
additionalParams = json['additionalParams'] ?? "";
|
||||
isObsolete = json['isObsolete'];
|
||||
isLocal = json['isLocal'];
|
||||
sourceCodeLanguage =
|
||||
SourceCodeLanguage.values[json['sourceCodeLanguage'] ?? 0];
|
||||
}
|
||||
|
||||
Source.fromJsonV1(Map<String, dynamic> json) {
|
||||
apiUrl = json['apiUrl'];
|
||||
appMinVerReq = json['appMinVerReq'];
|
||||
baseUrl = json['baseUrl'];
|
||||
dateFormat = json['dateFormat'];
|
||||
dateFormatLocale = json['dateFormatLocale'];
|
||||
hasCloudflare = json['hasCloudflare'];
|
||||
headers = json['headers'];
|
||||
iconUrl = json['iconUrl'];
|
||||
id = json['id'];
|
||||
isActive = json['isActive'];
|
||||
isAdded = json['isAdded'];
|
||||
isFullData = json['isFullData'];
|
||||
isManga = json['isManga'];
|
||||
itemType = isManga == true ? ItemType.manga : ItemType.anime;
|
||||
isNsfw = json['isNsfw'];
|
||||
isPinned = json['isPinned'];
|
||||
lang = json['lang'];
|
||||
|
|
@ -133,6 +171,7 @@ class Source {
|
|||
'isAdded': isAdded,
|
||||
'isFullData': isFullData,
|
||||
'isManga': isManga,
|
||||
'itemType': itemType.index,
|
||||
'isNsfw': isNsfw,
|
||||
'isPinned': isPinned,
|
||||
'lang': lang,
|
||||
|
|
|
|||
|
|
@ -107,49 +107,55 @@ const SourceSchema = CollectionSchema(
|
|||
name: r'isTorrent',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'lang': PropertySchema(
|
||||
r'itemType': PropertySchema(
|
||||
id: 18,
|
||||
name: r'itemType',
|
||||
type: IsarType.byte,
|
||||
enumMap: _SourceitemTypeEnumValueMap,
|
||||
),
|
||||
r'lang': PropertySchema(
|
||||
id: 19,
|
||||
name: r'lang',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'lastUsed': PropertySchema(
|
||||
id: 19,
|
||||
id: 20,
|
||||
name: r'lastUsed',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'name': PropertySchema(
|
||||
id: 20,
|
||||
id: 21,
|
||||
name: r'name',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'sourceCode': PropertySchema(
|
||||
id: 21,
|
||||
id: 22,
|
||||
name: r'sourceCode',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'sourceCodeLanguage': PropertySchema(
|
||||
id: 22,
|
||||
id: 23,
|
||||
name: r'sourceCodeLanguage',
|
||||
type: IsarType.byte,
|
||||
enumMap: _SourcesourceCodeLanguageEnumValueMap,
|
||||
),
|
||||
r'sourceCodeUrl': PropertySchema(
|
||||
id: 23,
|
||||
id: 24,
|
||||
name: r'sourceCodeUrl',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'typeSource': PropertySchema(
|
||||
id: 24,
|
||||
id: 25,
|
||||
name: r'typeSource',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'version': PropertySchema(
|
||||
id: 25,
|
||||
id: 26,
|
||||
name: r'version',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'versionLast': PropertySchema(
|
||||
id: 26,
|
||||
id: 27,
|
||||
name: r'versionLast',
|
||||
type: IsarType.string,
|
||||
)
|
||||
|
|
@ -291,15 +297,16 @@ void _sourceSerialize(
|
|||
writer.writeBool(offsets[15], object.isObsolete);
|
||||
writer.writeBool(offsets[16], object.isPinned);
|
||||
writer.writeBool(offsets[17], object.isTorrent);
|
||||
writer.writeString(offsets[18], object.lang);
|
||||
writer.writeBool(offsets[19], object.lastUsed);
|
||||
writer.writeString(offsets[20], object.name);
|
||||
writer.writeString(offsets[21], object.sourceCode);
|
||||
writer.writeByte(offsets[22], object.sourceCodeLanguage.index);
|
||||
writer.writeString(offsets[23], object.sourceCodeUrl);
|
||||
writer.writeString(offsets[24], object.typeSource);
|
||||
writer.writeString(offsets[25], object.version);
|
||||
writer.writeString(offsets[26], object.versionLast);
|
||||
writer.writeByte(offsets[18], object.itemType.index);
|
||||
writer.writeString(offsets[19], object.lang);
|
||||
writer.writeBool(offsets[20], object.lastUsed);
|
||||
writer.writeString(offsets[21], object.name);
|
||||
writer.writeString(offsets[22], object.sourceCode);
|
||||
writer.writeByte(offsets[23], object.sourceCodeLanguage.index);
|
||||
writer.writeString(offsets[24], object.sourceCodeUrl);
|
||||
writer.writeString(offsets[25], object.typeSource);
|
||||
writer.writeString(offsets[26], object.version);
|
||||
writer.writeString(offsets[27], object.versionLast);
|
||||
}
|
||||
|
||||
Source _sourceDeserialize(
|
||||
|
|
@ -327,17 +334,19 @@ Source _sourceDeserialize(
|
|||
isNsfw: reader.readBoolOrNull(offsets[14]),
|
||||
isObsolete: reader.readBoolOrNull(offsets[15]),
|
||||
isPinned: reader.readBoolOrNull(offsets[16]),
|
||||
lang: reader.readStringOrNull(offsets[18]),
|
||||
lastUsed: reader.readBoolOrNull(offsets[19]),
|
||||
name: reader.readStringOrNull(offsets[20]),
|
||||
sourceCode: reader.readStringOrNull(offsets[21]),
|
||||
sourceCodeUrl: reader.readStringOrNull(offsets[23]),
|
||||
typeSource: reader.readStringOrNull(offsets[24]),
|
||||
version: reader.readStringOrNull(offsets[25]),
|
||||
versionLast: reader.readStringOrNull(offsets[26]),
|
||||
itemType: _SourceitemTypeValueEnumMap[reader.readByteOrNull(offsets[18])] ??
|
||||
ItemType.manga,
|
||||
lang: reader.readStringOrNull(offsets[19]),
|
||||
lastUsed: reader.readBoolOrNull(offsets[20]),
|
||||
name: reader.readStringOrNull(offsets[21]),
|
||||
sourceCode: reader.readStringOrNull(offsets[22]),
|
||||
sourceCodeUrl: reader.readStringOrNull(offsets[24]),
|
||||
typeSource: reader.readStringOrNull(offsets[25]),
|
||||
version: reader.readStringOrNull(offsets[26]),
|
||||
versionLast: reader.readStringOrNull(offsets[27]),
|
||||
);
|
||||
object.sourceCodeLanguage = _SourcesourceCodeLanguageValueEnumMap[
|
||||
reader.readByteOrNull(offsets[22])] ??
|
||||
reader.readByteOrNull(offsets[23])] ??
|
||||
SourceCodeLanguage.dart;
|
||||
return object;
|
||||
}
|
||||
|
|
@ -386,30 +395,43 @@ P _sourceDeserializeProp<P>(
|
|||
case 17:
|
||||
return (reader.readBool(offset)) as P;
|
||||
case 18:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
return (_SourceitemTypeValueEnumMap[reader.readByteOrNull(offset)] ??
|
||||
ItemType.manga) as P;
|
||||
case 19:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 20:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 20:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 21:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 22:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 23:
|
||||
return (_SourcesourceCodeLanguageValueEnumMap[
|
||||
reader.readByteOrNull(offset)] ??
|
||||
SourceCodeLanguage.dart) as P;
|
||||
case 23:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 24:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 25:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 26:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 27:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
default:
|
||||
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 = {
|
||||
'dart': 0,
|
||||
'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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
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(
|
||||
{bool caseSensitive = true}) {
|
||||
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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'lang');
|
||||
|
|
|
|||
|
|
@ -324,7 +324,6 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
|
|||
_currentPosition.value, _currentTotalDuration.value,
|
||||
save: save);
|
||||
_streamController.setAnimeHistoryUpdate();
|
||||
_streamController.checkAndSyncProgress();
|
||||
}
|
||||
|
||||
void _setLandscapeMode(bool state) {
|
||||
|
|
|
|||
|
|
@ -7,9 +7,7 @@ import 'package:mangayomi/models/settings.dart';
|
|||
import 'package:mangayomi/models/track.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/player/providers/player_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/services/aniskip.dart';
|
||||
import 'package:mangayomi/services/sync_server.dart';
|
||||
import 'package:mangayomi/utils/chapter_recognition.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'anime_player_controller_provider.g.dart';
|
||||
|
|
@ -133,7 +131,7 @@ class AnimeStreamController extends _$AnimeStreamController {
|
|||
history = History(
|
||||
mangaId: getAnime().id,
|
||||
date: DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
isManga: getAnime().isManga,
|
||||
itemType: getAnime().itemType,
|
||||
chapterId: episode.id)
|
||||
..chapter.value = episode;
|
||||
} else {
|
||||
|
|
@ -151,13 +149,6 @@ class AnimeStreamController extends _$AnimeStreamController {
|
|||
});
|
||||
}
|
||||
|
||||
void checkAndSyncProgress() {
|
||||
final syncAfterReading = ref.watch(syncAfterReadingStateProvider);
|
||||
if (syncAfterReading) {
|
||||
ref.read(syncServerProvider(syncId: 1).notifier).checkForSync(true);
|
||||
}
|
||||
}
|
||||
|
||||
void setCurrentPosition(Duration duration, Duration? totalDuration,
|
||||
{bool save = false}) {
|
||||
if (episode.isRead!) return;
|
||||
|
|
@ -174,9 +165,6 @@ class AnimeStreamController extends _$AnimeStreamController {
|
|||
isar.writeTxnSync(() {
|
||||
ep.isRead = isWatch;
|
||||
ep.lastPageRead = (duration.inMilliseconds).toString();
|
||||
ref
|
||||
.read(changedItemsManagerProvider(managerId: 1).notifier)
|
||||
.addUpdatedChapter(ep, false, false);
|
||||
isar.chapters.putSync(ep);
|
||||
});
|
||||
if (isWatch) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'anime_player_controller_provider.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$animeStreamControllerHash() =>
|
||||
r'0d97207a4d015d5089766ccbeeba093c55cb1ef9';
|
||||
r'57ebd35f033d51fd213763173c26cd887f5c42d7';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/providers/storage_provider.dart';
|
||||
|
|
@ -24,7 +25,7 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
_tabBarController = TabController(length: 4, vsync: this);
|
||||
_tabBarController = TabController(length: 6, vsync: this);
|
||||
_tabBarController.animateTo(0);
|
||||
_tabBarController.addListener(() {
|
||||
_chekPermission();
|
||||
|
|
@ -47,7 +48,7 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
|
|||
final l10n = l10nLocalizations(context)!;
|
||||
return DefaultTabController(
|
||||
animationDuration: Duration.zero,
|
||||
length: 4,
|
||||
length: 6,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
|
|
@ -75,8 +76,9 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
|
|||
)
|
||||
: Row(
|
||||
children: [
|
||||
if (_tabBarController.index == 2 ||
|
||||
_tabBarController.index == 3)
|
||||
if (_tabBarController.index == 3 ||
|
||||
_tabBarController.index == 4 ||
|
||||
_tabBarController.index == 5)
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
context.push('/createExtension');
|
||||
|
|
@ -87,8 +89,9 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
|
|||
? IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
if (_tabBarController.index != 1 &&
|
||||
_tabBarController.index != 0) {
|
||||
if (_tabBarController.index != 0 &&
|
||||
_tabBarController.index != 1 &&
|
||||
_tabBarController.index != 2) {
|
||||
setState(() {
|
||||
_isSearch = true;
|
||||
});
|
||||
|
|
@ -101,7 +104,8 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
|
|||
},
|
||||
icon: Icon(
|
||||
_tabBarController.index == 0 ||
|
||||
_tabBarController.index == 1
|
||||
_tabBarController.index == 1 ||
|
||||
_tabBarController.index == 2
|
||||
? Icons.travel_explore_rounded
|
||||
: Icons.search_rounded,
|
||||
color: Theme.of(context).hintColor))
|
||||
|
|
@ -116,18 +120,24 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
|
|||
} else if (_tabBarController.index == 1) {
|
||||
context.push('/sourceFilter', extra: false);
|
||||
} else if (_tabBarController.index == 2) {
|
||||
_textEditingController.clear();
|
||||
context.push('/ExtensionLang', extra: true);
|
||||
context.push('/sourceFilter', extra: false);
|
||||
} else if (_tabBarController.index == 3) {
|
||||
_textEditingController.clear();
|
||||
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 {}
|
||||
},
|
||||
icon: Icon(
|
||||
_tabBarController.index == 0 || _tabBarController.index == 1
|
||||
_tabBarController.index == 0 || _tabBarController.index == 1 || _tabBarController.index == 2
|
||||
? Icons.filter_list_sharp
|
||||
: _tabBarController.index == 2 ||
|
||||
_tabBarController.index == 3
|
||||
: _tabBarController.index == 3 ||
|
||||
_tabBarController.index == 4 ||
|
||||
_tabBarController.index == 5
|
||||
? Icons.translate_rounded
|
||||
: Icons.help_outline_outlined,
|
||||
color: Theme.of(context).hintColor)),
|
||||
|
|
@ -139,12 +149,13 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
|
|||
tabs: [
|
||||
Tab(text: l10n.manga_sources),
|
||||
Tab(text: l10n.anime_sources),
|
||||
Tab(text: l10n.novel_sources),
|
||||
Tab(
|
||||
child: Row(
|
||||
children: [
|
||||
Text(l10n.manga_extensions),
|
||||
const SizedBox(width: 8),
|
||||
_extensionUpdateNumbers(ref, true)
|
||||
_extensionUpdateNumbers(ref, ItemType.manga)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -153,7 +164,16 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
|
|||
children: [
|
||||
Text(l10n.anime_extensions),
|
||||
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: [
|
||||
SourcesScreen(
|
||||
isManga: true,
|
||||
itemType: ItemType.manga,
|
||||
tabIndex: (index) {
|
||||
_tabBarController.animateTo(index);
|
||||
},
|
||||
),
|
||||
SourcesScreen(
|
||||
isManga: false,
|
||||
itemType: ItemType.anime,
|
||||
tabIndex: (index) {
|
||||
_tabBarController.animateTo(index);
|
||||
},
|
||||
),
|
||||
SourcesScreen(
|
||||
itemType: ItemType.novel,
|
||||
tabIndex: (index) {
|
||||
_tabBarController.animateTo(index);
|
||||
},
|
||||
),
|
||||
ExtensionScreen(
|
||||
query: _textEditingController.text,
|
||||
isManga: true,
|
||||
itemType: ItemType.manga,
|
||||
),
|
||||
ExtensionScreen(
|
||||
query: _textEditingController.text,
|
||||
isManga: false,
|
||||
itemType: ItemType.anime,
|
||||
),
|
||||
ExtensionScreen(
|
||||
query: _textEditingController.text,
|
||||
itemType: ItemType.novel,
|
||||
),
|
||||
// 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(
|
||||
stream: isar.sources
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.isActiveEqualTo(true)
|
||||
.isMangaEqualTo(isManga)
|
||||
.itemTypeEqualTo(itemType)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
|
|||
("search", 2),
|
||||
("getDetail", 3),
|
||||
("getPageList", 4),
|
||||
("getVideoList", 5)
|
||||
("getVideoList", 5),
|
||||
("getHtmlContent", 6)
|
||||
];
|
||||
|
||||
int _serviceIndex = 0;
|
||||
|
|
@ -219,7 +220,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
|
|||
}),
|
||||
if (_serviceIndex == 3 ||
|
||||
_serviceIndex == 4 ||
|
||||
_serviceIndex == 5)
|
||||
_serviceIndex == 5 ||
|
||||
_serviceIndex == 6)
|
||||
_textEditing("Url", context, "ex: url of the entry",
|
||||
(v) {
|
||||
_url = v;
|
||||
|
|
@ -286,11 +288,14 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
|
|||
.map((e) => e.toJson())
|
||||
.toList(),
|
||||
};
|
||||
} else {
|
||||
} else if (_serviceIndex == 5) {
|
||||
result =
|
||||
(await service.getVideoList(_url))
|
||||
.map((e) => e.toJson())
|
||||
.toList();
|
||||
} else {
|
||||
result = (await service
|
||||
.getHtmlContent(_url));
|
||||
}
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:grouped_list/sliver_grouped_list.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/modules/browse/extension/providers/extensions_provider.dart';
|
||||
import 'package:mangayomi/services/fetch_anime_sources.dart';
|
||||
import 'package:mangayomi/services/fetch_manga_sources.dart';
|
||||
import 'package:mangayomi/modules/widgets/progress_center.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/utils/language.dart';
|
||||
import 'package:mangayomi/modules/browse/extension/widgets/extension_list_tile_widget.dart';
|
||||
|
||||
class ExtensionScreen extends ConsumerStatefulWidget {
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
final String query;
|
||||
const ExtensionScreen(
|
||||
{required this.query, required this.isManga, super.key});
|
||||
{required this.query, required this.itemType, super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<ExtensionScreen> createState() => _ExtensionScreenState();
|
||||
|
|
@ -26,19 +28,24 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final streamExtensions =
|
||||
ref.watch(getExtensionsStreamProvider(widget.isManga));
|
||||
if (widget.isManga) {
|
||||
ref.watch(getExtensionsStreamProvider(widget.itemType));
|
||||
if (widget.itemType == ItemType.manga) {
|
||||
ref.watch(fetchMangaSourcesListProvider(id: null, reFresh: false));
|
||||
} else {
|
||||
} else if (widget.itemType == ItemType.anime) {
|
||||
ref.watch(fetchAnimeSourcesListProvider(id: null, reFresh: false));
|
||||
} else {
|
||||
ref.watch(fetchNovelSourcesListProvider(id: null, reFresh: false));
|
||||
}
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return RefreshIndicator(
|
||||
onRefresh: () => widget.isManga
|
||||
onRefresh: () => widget.itemType == ItemType.manga
|
||||
? ref.refresh(
|
||||
fetchMangaSourcesListProvider(id: null, reFresh: true).future)
|
||||
: ref.refresh(
|
||||
fetchAnimeSourcesListProvider(id: null, reFresh: true).future),
|
||||
: widget.itemType == ItemType.anime
|
||||
? ref.refresh(
|
||||
fetchAnimeSourcesListProvider(id: null, reFresh: true).future) :
|
||||
ref.refresh(
|
||||
fetchNovelSourcesListProvider(id: null, reFresh: true).future),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: streamExtensions.when(
|
||||
|
|
@ -87,14 +94,19 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
|
|||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
for (var source in updateEntries) {
|
||||
source.isManga!
|
||||
source.itemType == ItemType.manga
|
||||
? await ref.watch(
|
||||
fetchMangaSourcesListProvider(
|
||||
id: source.id, reFresh: true)
|
||||
.future)
|
||||
: await ref.watch(
|
||||
: source.itemType == ItemType.anime ?
|
||||
await ref.watch(
|
||||
fetchAnimeSourcesListProvider(
|
||||
id: source.id, reFresh: true)
|
||||
.future) :
|
||||
await ref.watch(
|
||||
fetchNovelSourcesListProvider(
|
||||
id: source.id, reFresh: true)
|
||||
.future);
|
||||
}
|
||||
},
|
||||
|
|
@ -167,12 +179,15 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
|
|||
error: (error, _) => Center(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
if (widget.isManga) {
|
||||
if (widget.itemType == ItemType.manga) {
|
||||
ref.invalidate(
|
||||
fetchMangaSourcesListProvider(id: null, reFresh: true));
|
||||
} else {
|
||||
} else if (widget.itemType == ItemType.anime) {
|
||||
ref.invalidate(
|
||||
fetchAnimeSourcesListProvider(id: null, reFresh: true));
|
||||
} else {
|
||||
ref.invalidate(
|
||||
fetchNovelSourcesListProvider(id: null, reFresh: true));
|
||||
}
|
||||
},
|
||||
child: Text(context.l10n.refresh)),
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
part 'extensions_provider.g.dart';
|
||||
|
||||
@riverpod
|
||||
Stream<List<Source>> getExtensionsStream(Ref ref, bool? isManga) async* {
|
||||
Stream<List<Source>> getExtensionsStream(Ref ref, ItemType itemType) async* {
|
||||
yield* isar.sources
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.isActiveEqualTo(true)
|
||||
.isMangaEqualTo(isManga)
|
||||
.itemTypeEqualTo(itemType)
|
||||
.watch(fireImmediately: true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'extensions_provider.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$getExtensionsStreamHash() =>
|
||||
r'62f2884dd64a2f3d8928f7399c6b2547f0311078';
|
||||
r'3c5d6625c40c222f25fc8141df078dd46bcc762f';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -41,10 +41,10 @@ class GetExtensionsStreamFamily extends Family<AsyncValue<List<Source>>> {
|
|||
|
||||
/// See also [getExtensionsStream].
|
||||
GetExtensionsStreamProvider call(
|
||||
bool? isManga,
|
||||
ItemType itemType,
|
||||
) {
|
||||
return GetExtensionsStreamProvider(
|
||||
isManga,
|
||||
itemType,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ class GetExtensionsStreamFamily extends Family<AsyncValue<List<Source>>> {
|
|||
covariant GetExtensionsStreamProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.isManga,
|
||||
provider.itemType,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -77,11 +77,11 @@ class GetExtensionsStreamProvider
|
|||
extends AutoDisposeStreamProvider<List<Source>> {
|
||||
/// See also [getExtensionsStream].
|
||||
GetExtensionsStreamProvider(
|
||||
bool? isManga,
|
||||
ItemType itemType,
|
||||
) : this._internal(
|
||||
(ref) => getExtensionsStream(
|
||||
ref as GetExtensionsStreamRef,
|
||||
isManga,
|
||||
itemType,
|
||||
),
|
||||
from: getExtensionsStreamProvider,
|
||||
name: r'getExtensionsStreamProvider',
|
||||
|
|
@ -92,7 +92,7 @@ class GetExtensionsStreamProvider
|
|||
dependencies: GetExtensionsStreamFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
GetExtensionsStreamFamily._allTransitiveDependencies,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
);
|
||||
|
||||
GetExtensionsStreamProvider._internal(
|
||||
|
|
@ -102,10 +102,10 @@ class GetExtensionsStreamProvider
|
|||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.isManga,
|
||||
required this.itemType,
|
||||
}) : super.internal();
|
||||
|
||||
final bool? isManga;
|
||||
final ItemType itemType;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
|
|
@ -120,7 +120,7 @@ class GetExtensionsStreamProvider
|
|||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -132,13 +132,13 @@ class GetExtensionsStreamProvider
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is GetExtensionsStreamProvider && other.isManga == isManga;
|
||||
return other is GetExtensionsStreamProvider && other.itemType == itemType;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, isManga.hashCode);
|
||||
hash = _SystemHash.combine(hash, itemType.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
|
@ -147,8 +147,8 @@ class GetExtensionsStreamProvider
|
|||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin GetExtensionsStreamRef on AutoDisposeStreamProviderRef<List<Source>> {
|
||||
/// The parameter `isManga` of this provider.
|
||||
bool? get isManga;
|
||||
/// The parameter `itemType` of this provider.
|
||||
ItemType get itemType;
|
||||
}
|
||||
|
||||
class _GetExtensionsStreamProviderElement
|
||||
|
|
@ -157,7 +157,7 @@ class _GetExtensionsStreamProviderElement
|
|||
_GetExtensionsStreamProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
bool? get isManga => (origin as GetExtensionsStreamProvider).isManga;
|
||||
ItemType get itemType => (origin as GetExtensionsStreamProvider).itemType;
|
||||
}
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:mangayomi/eval/model/m_bridge.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
|
|
@ -13,15 +14,16 @@ class CreateExtension extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _CreateExtensionState extends State<CreateExtension> {
|
||||
bool _isManga = false;
|
||||
String _name = "";
|
||||
String _lang = "";
|
||||
String _baseUrl = "";
|
||||
String _apiUrl = "";
|
||||
String _iconUrl = "";
|
||||
int _sourceTypeIndex = 0;
|
||||
int _itemTypeIndex = 0;
|
||||
int _languageIndex = 0;
|
||||
final List<String> _sourceTypes = ["single", "multi", "torrent"];
|
||||
final List<String> _itemTypes = ["Manga", "Anime", "Novel"];
|
||||
final List<String> _languages = ["Dart", "JavaScript"];
|
||||
SourceCodeLanguage _sourceCodeLanguage = SourceCodeLanguage.dart;
|
||||
@override
|
||||
|
|
@ -129,12 +131,35 @@ class _CreateExtensionState extends State<CreateExtension> {
|
|||
],
|
||||
),
|
||||
),
|
||||
SwitchListTile(
|
||||
title: const Text("isManga"),
|
||||
value: _isManga,
|
||||
onChanged: (value) => setState(() {
|
||||
_isManga = value;
|
||||
}),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 17),
|
||||
child: Row(
|
||||
children: [
|
||||
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: const EdgeInsets.all(8.0),
|
||||
|
|
@ -159,7 +184,7 @@ class _CreateExtensionState extends State<CreateExtension> {
|
|||
apiUrl: _apiUrl,
|
||||
iconUrl: _iconUrl,
|
||||
typeSource: _sourceTypes[_sourceTypeIndex],
|
||||
isManga: _isManga,
|
||||
itemType: ItemType.values.elementAt(_itemTypeIndex),
|
||||
isAdded: true,
|
||||
isActive: true,
|
||||
version: "0.0.1",
|
||||
|
|
@ -252,6 +277,12 @@ class TestSource extends MProvider {
|
|||
// TODO: implement
|
||||
}
|
||||
|
||||
// For novel html content
|
||||
@override
|
||||
Future<String> getHtmlContent(String url) async {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
// For anime episode video list
|
||||
@override
|
||||
Future<List<MVideo>> getVideoList(String url) async {
|
||||
|
|
@ -313,6 +344,10 @@ class DefaultExtension extends MProvider {
|
|||
async getDetail(url) {
|
||||
throw new Error("getDetail not implemented");
|
||||
}
|
||||
// For novel html content
|
||||
async getHtmlContent(url) {
|
||||
throw new Error("getHtmlContent not implemented");
|
||||
}
|
||||
// For anime episode video list
|
||||
async getVideoList(url) {
|
||||
throw new Error("getVideoList not implemented");
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/services/fetch_anime_sources.dart';
|
||||
import 'package:mangayomi/services/fetch_manga_sources.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/utils/cached_network.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
|
|
@ -48,13 +50,17 @@ class _ExtensionListTileWidgetState
|
|||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
widget.source.isManga!
|
||||
widget.source.itemType == ItemType.manga
|
||||
? await ref.watch(fetchMangaSourcesListProvider(
|
||||
id: widget.source.id, reFresh: true)
|
||||
.future)
|
||||
: await ref.watch(fetchAnimeSourcesListProvider(
|
||||
id: widget.source.id, reFresh: true)
|
||||
.future);
|
||||
: widget.source.itemType == ItemType.anime
|
||||
? await ref.watch(fetchAnimeSourcesListProvider(
|
||||
id: widget.source.id, reFresh: true)
|
||||
.future)
|
||||
: await ref.watch(fetchNovelSourcesListProvider(
|
||||
id: widget.source.id, reFresh: true)
|
||||
.future);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
|
|
@ -116,13 +122,17 @@ class _ExtensionListTileWidgetState
|
|||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
widget.source.isManga!
|
||||
widget.source.itemType == ItemType.manga
|
||||
? await ref.watch(fetchMangaSourcesListProvider(
|
||||
id: widget.source.id, reFresh: true)
|
||||
.future)
|
||||
: await ref.watch(fetchAnimeSourcesListProvider(
|
||||
id: widget.source.id, reFresh: true)
|
||||
.future);
|
||||
: widget.source.itemType == ItemType.anime
|
||||
? await ref.watch(fetchAnimeSourcesListProvider(
|
||||
id: widget.source.id, reFresh: true)
|
||||
.future)
|
||||
: await ref.watch(fetchNovelSourcesListProvider(
|
||||
id: widget.source.id, reFresh: true)
|
||||
.future);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
|
|||
context: context,
|
||||
getManga: getMangaDetail,
|
||||
lang: widget.source.lang!,
|
||||
isManga: widget.source.isManga ?? true,
|
||||
itemType: widget.source.itemType,
|
||||
useMaterialRoute: true,
|
||||
source: widget.source.name!);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:grouped_list/sliver_grouped_list.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/modules/browse/sources/widgets/source_list_tile.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
|
|
@ -10,9 +11,9 @@ import 'package:mangayomi/utils/language.dart';
|
|||
|
||||
class SourcesScreen extends ConsumerStatefulWidget {
|
||||
final Function(int) tabIndex;
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
const SourcesScreen(
|
||||
{required this.tabIndex, required this.isManga, super.key});
|
||||
{required this.tabIndex, required this.itemType, super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<SourcesScreen> createState() => _SourcesScreenState();
|
||||
|
|
@ -33,7 +34,7 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
|
|||
.and()
|
||||
.isActiveEqualTo(true)
|
||||
.and()
|
||||
.isMangaEqualTo(widget.isManga)
|
||||
.itemTypeEqualTo(widget.itemType)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
|
|
@ -52,7 +53,7 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
|
|||
padding: const EdgeInsets.all(8.0),
|
||||
child: ElevatedButton.icon(
|
||||
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),
|
||||
label: Text(context.l10n.show_extensions)),
|
||||
)
|
||||
|
|
@ -91,7 +92,7 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
|
|||
itemBuilder: (context, Source element) {
|
||||
return SourceListTile(
|
||||
source: element,
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
);
|
||||
},
|
||||
groupComparator: (group1, group2) =>
|
||||
|
|
@ -118,7 +119,7 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
|
|||
itemBuilder: (context, Source element) {
|
||||
return SourceListTile(
|
||||
source: element,
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
);
|
||||
},
|
||||
groupComparator: (group1, group2) =>
|
||||
|
|
@ -146,7 +147,7 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
|
|||
itemBuilder: (context, Source element) {
|
||||
return SourceListTile(
|
||||
source: element,
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
);
|
||||
},
|
||||
groupComparator: (group1, group2) =>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.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';
|
||||
|
||||
class SourceListTile extends StatelessWidget {
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
final Source source;
|
||||
const SourceListTile(
|
||||
{super.key, required this.source, required this.isManga});
|
||||
{super.key, required this.source, required this.itemType});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -23,7 +24,7 @@ class SourceListTile extends StatelessWidget {
|
|||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.itemTypeEqualTo(itemType)
|
||||
.findAllSync();
|
||||
isar.writeTxnSync(() {
|
||||
for (var src in sources) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import 'package:mangayomi/models/chapter.dart';
|
|||
import 'package:mangayomi/models/history.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/modules/history/providers/isar_providers.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/utils/cached_network.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
|
|
@ -31,17 +31,20 @@ class HistoryScreen extends ConsumerStatefulWidget {
|
|||
class _HistoryScreenState extends ConsumerState<HistoryScreen>
|
||||
with TickerProviderStateMixin {
|
||||
late TabController _tabBarController;
|
||||
int tabs = 3;
|
||||
|
||||
void tabListener() {
|
||||
setState(() {
|
||||
_textEditingController.clear();
|
||||
_isSearch = false;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_tabBarController = TabController(length: 2, vsync: this);
|
||||
_tabBarController = TabController(length: tabs, vsync: this);
|
||||
_tabBarController.animateTo(0);
|
||||
_tabBarController.addListener(() {
|
||||
setState(() {
|
||||
_textEditingController.clear();
|
||||
_isSearch = false;
|
||||
});
|
||||
});
|
||||
_tabBarController.addListener(tabListener);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
|
@ -50,10 +53,27 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen>
|
|||
List<History> entriesData = [];
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int newTabs = 0;
|
||||
final hideManga = ref.watch(hideMangaStateProvider);
|
||||
final hideAnime = ref.watch(hideAnimeStateProvider);
|
||||
final hideNovel = ref.watch(hideNovelStateProvider);
|
||||
if (!hideManga) newTabs++;
|
||||
if (!hideAnime) newTabs++;
|
||||
if (!hideNovel) newTabs++;
|
||||
if (tabs != newTabs) {
|
||||
_tabBarController.removeListener(tabListener);
|
||||
_tabBarController.dispose();
|
||||
_tabBarController = TabController(length: newTabs, vsync: this);
|
||||
_tabBarController.animateTo(0);
|
||||
_tabBarController.addListener(tabListener);
|
||||
setState(() {
|
||||
tabs = newTabs;
|
||||
});
|
||||
}
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return DefaultTabController(
|
||||
animationDuration: Duration.zero,
|
||||
length: 2,
|
||||
length: newTabs,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
|
|
@ -119,10 +139,20 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen>
|
|||
List<History> histories = isar.historys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.chapter((q) => q.manga((q) =>
|
||||
q.isMangaEqualTo(
|
||||
_tabBarController.index ==
|
||||
0)))
|
||||
.chapter((q) => q.manga((q) => q
|
||||
.itemTypeEqualTo(_tabBarController
|
||||
.index ==
|
||||
0 &&
|
||||
!hideManga
|
||||
? ItemType.manga
|
||||
: _tabBarController.index ==
|
||||
1 -
|
||||
(hideManga
|
||||
? 1
|
||||
: 0) &&
|
||||
!hideAnime
|
||||
? ItemType.anime
|
||||
: ItemType.novel)))
|
||||
.findAllSync()
|
||||
.toList();
|
||||
isar.writeTxnSync(() {
|
||||
|
|
@ -148,22 +178,30 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen>
|
|||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
controller: _tabBarController,
|
||||
tabs: [
|
||||
Tab(text: l10n.manga),
|
||||
Tab(text: l10n.anime),
|
||||
if (!hideManga) Tab(text: l10n.manga),
|
||||
if (!hideAnime) Tab(text: l10n.anime),
|
||||
if (!hideNovel) Tab(text: l10n.novel),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: TabBarView(controller: _tabBarController, children: [
|
||||
HistoryTab(
|
||||
isManga: true,
|
||||
query: _textEditingController.text,
|
||||
),
|
||||
HistoryTab(
|
||||
isManga: false,
|
||||
query: _textEditingController.text,
|
||||
)
|
||||
if (!hideManga)
|
||||
HistoryTab(
|
||||
itemType: ItemType.manga,
|
||||
query: _textEditingController.text,
|
||||
),
|
||||
if (!hideAnime)
|
||||
HistoryTab(
|
||||
itemType: ItemType.anime,
|
||||
query: _textEditingController.text,
|
||||
),
|
||||
if (!hideNovel)
|
||||
HistoryTab(
|
||||
itemType: ItemType.novel,
|
||||
query: _textEditingController.text,
|
||||
)
|
||||
]),
|
||||
),
|
||||
),
|
||||
|
|
@ -173,8 +211,8 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen>
|
|||
|
||||
class HistoryTab extends ConsumerStatefulWidget {
|
||||
final String query;
|
||||
final bool isManga;
|
||||
const HistoryTab({required this.isManga, required this.query, super.key});
|
||||
final ItemType itemType;
|
||||
const HistoryTab({required this.itemType, required this.query, super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<HistoryTab> createState() => _HistoryTabState();
|
||||
|
|
@ -185,7 +223,7 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
|
|||
Widget build(BuildContext context) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
final history =
|
||||
ref.watch(getAllHistoryStreamProvider(isManga: widget.isManga));
|
||||
ref.watch(getAllHistoryStreamProvider(itemType: widget.itemType));
|
||||
return Scaffold(
|
||||
body: history.when(
|
||||
data: (data) {
|
||||
|
|
@ -371,29 +409,12 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
|
|||
.id!);
|
||||
for (var chapter
|
||||
in chapters) {
|
||||
await ref
|
||||
.read(changedItemsManagerProvider(
|
||||
managerId:
|
||||
1)
|
||||
.notifier)
|
||||
.addUpdatedChapterAsync(
|
||||
chapter,
|
||||
true,
|
||||
false);
|
||||
await isar
|
||||
.chapters
|
||||
.delete(
|
||||
chapter
|
||||
.id!);
|
||||
}
|
||||
await ref
|
||||
.read(changedItemsManagerProvider(
|
||||
managerId:
|
||||
1)
|
||||
.notifier)
|
||||
.addDeletedMangaAsync(
|
||||
manga,
|
||||
false);
|
||||
await isar.mangas
|
||||
.delete(manga
|
||||
.id!);
|
||||
|
|
|
|||
|
|
@ -10,22 +10,22 @@ part 'isar_providers.g.dart';
|
|||
|
||||
@riverpod
|
||||
Stream<List<History>> getAllHistoryStream(Ref ref,
|
||||
{required bool isManga}) async* {
|
||||
{required ItemType itemType}) async* {
|
||||
yield* isar.historys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.chapter((q) => q.manga((q) => q.isMangaEqualTo(isManga)))
|
||||
.chapter((q) => q.manga((q) => q.itemTypeEqualTo(itemType)))
|
||||
.watch(fireImmediately: true);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Stream<List<Update>> getAllUpdateStream(Ref ref,
|
||||
{required bool isManga}) async* {
|
||||
{required ItemType itemType}) async* {
|
||||
yield* isar.updates
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.chapter((q) => q.manga((q) => q.isMangaEqualTo(isManga)))
|
||||
.chapter((q) => q.manga((q) => q.itemTypeEqualTo(itemType)))
|
||||
.watch(fireImmediately: true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'isar_providers.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$getAllHistoryStreamHash() =>
|
||||
r'53b3a7837efab9e7d2808930e5070dbd788c59f8';
|
||||
r'42048cb03035be55b52fc501fb2309cdb2acfcb8';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -41,10 +41,10 @@ class GetAllHistoryStreamFamily extends Family<AsyncValue<List<History>>> {
|
|||
|
||||
/// See also [getAllHistoryStream].
|
||||
GetAllHistoryStreamProvider call({
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
}) {
|
||||
return GetAllHistoryStreamProvider(
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ class GetAllHistoryStreamFamily extends Family<AsyncValue<List<History>>> {
|
|||
covariant GetAllHistoryStreamProvider provider,
|
||||
) {
|
||||
return call(
|
||||
isManga: provider.isManga,
|
||||
itemType: provider.itemType,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -77,11 +77,11 @@ class GetAllHistoryStreamProvider
|
|||
extends AutoDisposeStreamProvider<List<History>> {
|
||||
/// See also [getAllHistoryStream].
|
||||
GetAllHistoryStreamProvider({
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
}) : this._internal(
|
||||
(ref) => getAllHistoryStream(
|
||||
ref as GetAllHistoryStreamRef,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
),
|
||||
from: getAllHistoryStreamProvider,
|
||||
name: r'getAllHistoryStreamProvider',
|
||||
|
|
@ -92,7 +92,7 @@ class GetAllHistoryStreamProvider
|
|||
dependencies: GetAllHistoryStreamFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
GetAllHistoryStreamFamily._allTransitiveDependencies,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
);
|
||||
|
||||
GetAllHistoryStreamProvider._internal(
|
||||
|
|
@ -102,10 +102,10 @@ class GetAllHistoryStreamProvider
|
|||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.isManga,
|
||||
required this.itemType,
|
||||
}) : super.internal();
|
||||
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
|
|
@ -120,7 +120,7 @@ class GetAllHistoryStreamProvider
|
|||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -132,13 +132,13 @@ class GetAllHistoryStreamProvider
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is GetAllHistoryStreamProvider && other.isManga == isManga;
|
||||
return other is GetAllHistoryStreamProvider && other.itemType == itemType;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, isManga.hashCode);
|
||||
hash = _SystemHash.combine(hash, itemType.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
|
@ -147,8 +147,8 @@ class GetAllHistoryStreamProvider
|
|||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin GetAllHistoryStreamRef on AutoDisposeStreamProviderRef<List<History>> {
|
||||
/// The parameter `isManga` of this provider.
|
||||
bool get isManga;
|
||||
/// The parameter `itemType` of this provider.
|
||||
ItemType get itemType;
|
||||
}
|
||||
|
||||
class _GetAllHistoryStreamProviderElement
|
||||
|
|
@ -157,11 +157,11 @@ class _GetAllHistoryStreamProviderElement
|
|||
_GetAllHistoryStreamProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
bool get isManga => (origin as GetAllHistoryStreamProvider).isManga;
|
||||
ItemType get itemType => (origin as GetAllHistoryStreamProvider).itemType;
|
||||
}
|
||||
|
||||
String _$getAllUpdateStreamHash() =>
|
||||
r'01f77807c8be11f471b6acee6e7bc358ce600a65';
|
||||
r'6a20f8feba3010c2ab7a80560f7a7f6cf10c7366';
|
||||
|
||||
/// See also [getAllUpdateStream].
|
||||
@ProviderFor(getAllUpdateStream)
|
||||
|
|
@ -174,10 +174,10 @@ class GetAllUpdateStreamFamily extends Family<AsyncValue<List<Update>>> {
|
|||
|
||||
/// See also [getAllUpdateStream].
|
||||
GetAllUpdateStreamProvider call({
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
}) {
|
||||
return GetAllUpdateStreamProvider(
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ class GetAllUpdateStreamFamily extends Family<AsyncValue<List<Update>>> {
|
|||
covariant GetAllUpdateStreamProvider provider,
|
||||
) {
|
||||
return call(
|
||||
isManga: provider.isManga,
|
||||
itemType: provider.itemType,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -210,11 +210,11 @@ class GetAllUpdateStreamProvider
|
|||
extends AutoDisposeStreamProvider<List<Update>> {
|
||||
/// See also [getAllUpdateStream].
|
||||
GetAllUpdateStreamProvider({
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
}) : this._internal(
|
||||
(ref) => getAllUpdateStream(
|
||||
ref as GetAllUpdateStreamRef,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
),
|
||||
from: getAllUpdateStreamProvider,
|
||||
name: r'getAllUpdateStreamProvider',
|
||||
|
|
@ -225,7 +225,7 @@ class GetAllUpdateStreamProvider
|
|||
dependencies: GetAllUpdateStreamFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
GetAllUpdateStreamFamily._allTransitiveDependencies,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
);
|
||||
|
||||
GetAllUpdateStreamProvider._internal(
|
||||
|
|
@ -235,10 +235,10 @@ class GetAllUpdateStreamProvider
|
|||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.isManga,
|
||||
required this.itemType,
|
||||
}) : super.internal();
|
||||
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
|
|
@ -253,7 +253,7 @@ class GetAllUpdateStreamProvider
|
|||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -265,13 +265,13 @@ class GetAllUpdateStreamProvider
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is GetAllUpdateStreamProvider && other.isManga == isManga;
|
||||
return other is GetAllUpdateStreamProvider && other.itemType == itemType;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, isManga.hashCode);
|
||||
hash = _SystemHash.combine(hash, itemType.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
|
@ -280,8 +280,8 @@ class GetAllUpdateStreamProvider
|
|||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin GetAllUpdateStreamRef on AutoDisposeStreamProviderRef<List<Update>> {
|
||||
/// The parameter `isManga` of this provider.
|
||||
bool get isManga;
|
||||
/// The parameter `itemType` of this provider.
|
||||
ItemType get itemType;
|
||||
}
|
||||
|
||||
class _GetAllUpdateStreamProviderElement
|
||||
|
|
@ -290,7 +290,7 @@ class _GetAllUpdateStreamProviderElement
|
|||
_GetAllUpdateStreamProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
bool get isManga => (origin as GetAllUpdateStreamProvider).isManga;
|
||||
ItemType get itemType => (origin as GetAllUpdateStreamProvider).itemType;
|
||||
}
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import 'package:mangayomi/modules/library/providers/add_torrent.dart';
|
|||
import 'package:mangayomi/modules/library/providers/local_archive.dart';
|
||||
import 'package:mangayomi/modules/manga/detail/providers/update_manga_detail_providers.dart';
|
||||
import 'package:mangayomi/modules/more/categories/providers/isar_providers.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/modules/widgets/custom_draggable_tabbar.dart';
|
||||
import 'package:mangayomi/modules/widgets/manga_image_card_widget.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
|
|
@ -40,8 +39,8 @@ import 'package:mangayomi/modules/widgets/progress_center.dart';
|
|||
import 'package:mangayomi/utils/global_style.dart';
|
||||
|
||||
class LibraryScreen extends ConsumerStatefulWidget {
|
||||
final bool isManga;
|
||||
const LibraryScreen({required this.isManga, super.key});
|
||||
final ItemType itemType;
|
||||
const LibraryScreen({required this.itemType, super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<LibraryScreen> createState() => _LibraryScreenState();
|
||||
|
|
@ -83,13 +82,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
final settings = settingsList.first;
|
||||
|
||||
final categories =
|
||||
ref.watch(getMangaCategorieStreamProvider(isManga: widget.isManga));
|
||||
ref.watch(getMangaCategorieStreamProvider(itemType: widget.itemType));
|
||||
final withoutCategories = ref.watch(
|
||||
getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga));
|
||||
getAllMangaWithoutCategoriesStreamProvider(
|
||||
itemType: widget.itemType));
|
||||
final showCategoryTabs = ref.watch(libraryShowCategoryTabsStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
final mangaAll = ref.watch(
|
||||
getAllMangaStreamProvider(categoryId: null, isManga: widget.isManga));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final mangaAll = ref.watch(getAllMangaStreamProvider(
|
||||
categoryId: null, itemType: widget.itemType));
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return Scaffold(
|
||||
body: mangaAll.when(
|
||||
|
|
@ -113,55 +113,63 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
return Consumer(builder: (context, ref, child) {
|
||||
bool reverse = ref
|
||||
.watch(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga, settings: settings))
|
||||
itemType: widget.itemType,
|
||||
settings: settings))
|
||||
.reverse!;
|
||||
|
||||
final continueReaderBtn = ref.watch(
|
||||
libraryShowContinueReadingButtonStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType,
|
||||
settings: settings));
|
||||
final showNumbersOfItems = ref.watch(
|
||||
libraryShowNumbersOfItemsStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType,
|
||||
settings: settings));
|
||||
final localSource = ref.watch(
|
||||
libraryLocalSourceStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType,
|
||||
settings: settings));
|
||||
final downloadedChapter = ref.watch(
|
||||
libraryDownloadedChaptersStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType,
|
||||
settings: settings));
|
||||
final language = ref.watch(
|
||||
libraryLanguageStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType,
|
||||
settings: settings));
|
||||
final displayType = ref.watch(
|
||||
libraryDisplayTypeStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType,
|
||||
settings: settings));
|
||||
final isNotFiltering = ref.watch(
|
||||
mangasFilterResultStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings));
|
||||
final downloadFilterType = ref.watch(
|
||||
mangaFilterDownloadedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings));
|
||||
final unreadFilterType = ref.watch(
|
||||
mangaFilterUnreadStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings));
|
||||
final startedFilterType = ref.watch(
|
||||
mangaFilterStartedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings));
|
||||
final bookmarkedFilterType = ref.watch(
|
||||
mangaFilterBookmarkedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings));
|
||||
final sortType = ref
|
||||
.watch(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga, settings: settings))
|
||||
itemType: widget.itemType,
|
||||
settings: settings))
|
||||
.index as int;
|
||||
final numberOfItemsList = _filterAndSortManga(
|
||||
data: man,
|
||||
|
|
@ -364,53 +372,53 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
return Consumer(builder: (context, ref, child) {
|
||||
bool reverse = ref
|
||||
.watch(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga, settings: settings))
|
||||
itemType: widget.itemType, settings: settings))
|
||||
.reverse!;
|
||||
final continueReaderBtn = ref.watch(
|
||||
libraryShowContinueReadingButtonStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final showNumbersOfItems = ref.watch(
|
||||
libraryShowNumbersOfItemsStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final localSource = ref.watch(
|
||||
libraryLocalSourceStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final downloadedChapter = ref.watch(
|
||||
libraryDownloadedChaptersStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final language = ref.watch(libraryLanguageStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final displayType = ref.watch(
|
||||
libraryDisplayTypeStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final isNotFiltering = ref.watch(
|
||||
mangasFilterResultStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings));
|
||||
final downloadFilterType = ref.watch(
|
||||
mangaFilterDownloadedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings));
|
||||
final unreadFilterType = ref.watch(
|
||||
mangaFilterUnreadStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings));
|
||||
final startedFilterType = ref.watch(
|
||||
mangaFilterStartedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings));
|
||||
final bookmarkedFilterType = ref.watch(
|
||||
mangaFilterBookmarkedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings));
|
||||
final sortType = ref
|
||||
.watch(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga, settings: settings))
|
||||
itemType: widget.itemType, settings: settings))
|
||||
.index;
|
||||
final numberOfItemsList = _filterAndSortManga(
|
||||
data: man,
|
||||
|
|
@ -518,9 +526,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
.set();
|
||||
ref.invalidate(
|
||||
getAllMangaWithoutCategoriesStreamProvider(
|
||||
isManga: widget.isManga));
|
||||
itemType: widget.itemType));
|
||||
ref.invalidate(getAllMangaStreamProvider(
|
||||
categoryId: null, isManga: widget.isManga));
|
||||
categoryId: null, itemType: widget.itemType));
|
||||
},
|
||||
child: Icon(
|
||||
Icons.done_all_sharp,
|
||||
|
|
@ -545,9 +553,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
.set();
|
||||
ref.invalidate(
|
||||
getAllMangaWithoutCategoriesStreamProvider(
|
||||
isManga: widget.isManga));
|
||||
itemType: widget.itemType));
|
||||
ref.invalidate(getAllMangaStreamProvider(
|
||||
categoryId: null, isManga: widget.isManga));
|
||||
categoryId: null, itemType: widget.itemType));
|
||||
},
|
||||
child: Icon(
|
||||
Icons.remove_done_sharp,
|
||||
|
|
@ -611,10 +619,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
required int categoryId,
|
||||
required Settings settings}) {
|
||||
final mangas = ref.watch(getAllMangaStreamProvider(
|
||||
categoryId: categoryId, isManga: widget.isManga));
|
||||
categoryId: categoryId, itemType: widget.itemType));
|
||||
final sortType = ref
|
||||
.watch(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga, settings: settings))
|
||||
itemType: widget.itemType, settings: settings))
|
||||
.index;
|
||||
return mangas.when(
|
||||
data: (data) {
|
||||
|
|
@ -661,10 +669,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
required Settings settings}) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
final mangas = ref.watch(getAllMangaStreamProvider(
|
||||
categoryId: categoryId, isManga: widget.isManga));
|
||||
categoryId: categoryId, itemType: widget.itemType));
|
||||
final sortType = ref
|
||||
.watch(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga, settings: settings))
|
||||
itemType: widget.itemType, settings: settings))
|
||||
.index;
|
||||
final mangaIdsList = ref.watch(mangasListStateProvider);
|
||||
return Scaffold(
|
||||
|
|
@ -702,7 +710,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
language: language,
|
||||
mangaIdsList: mangaIdsList,
|
||||
localSource: localSource,
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -733,13 +741,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
required Settings settings}) {
|
||||
final sortType = ref
|
||||
.watch(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga, settings: settings))
|
||||
itemType: widget.itemType, settings: settings))
|
||||
.index;
|
||||
final manga = withouCategories
|
||||
? ref.watch(
|
||||
getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga))
|
||||
? ref.watch(getAllMangaWithoutCategoriesStreamProvider(
|
||||
itemType: widget.itemType))
|
||||
: ref.watch(getAllMangaStreamProvider(
|
||||
categoryId: null, isManga: widget.isManga));
|
||||
categoryId: null, itemType: widget.itemType));
|
||||
final mangaIdsList = ref.watch(mangasListStateProvider);
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return manga.when(
|
||||
|
|
@ -776,7 +784,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
language: language,
|
||||
mangaIdsList: mangaIdsList,
|
||||
localSource: localSource,
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -954,7 +962,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.forMangaEqualTo(widget.isManga)
|
||||
.forItemTypeEqualTo(widget.itemType)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
return AlertDialog(
|
||||
|
|
@ -1004,10 +1012,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.push("/categories", extra: (
|
||||
true,
|
||||
widget.isManga ? 0 : 1
|
||||
));
|
||||
context.push("/categories",
|
||||
extra: (true, widget.itemType));
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(l10n.edit)),
|
||||
|
|
@ -1057,10 +1063,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.push("/categories", extra: (
|
||||
true,
|
||||
widget.isManga ? 0 : 1
|
||||
));
|
||||
context.push("/categories",
|
||||
extra: (true, widget.itemType));
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(
|
||||
|
|
@ -1115,7 +1119,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
type: fromLibList.isNotEmpty ? 1 : 0,
|
||||
),
|
||||
ListTileChapterFilter(
|
||||
label: widget.isManga
|
||||
label: widget.itemType != ItemType.anime
|
||||
? l10n.downloaded_chapters
|
||||
: l10n.downloaded_episodes,
|
||||
onTap: () {
|
||||
|
|
@ -1158,12 +1162,6 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
}
|
||||
|
||||
for (var chapter in manga.chapters) {
|
||||
ref
|
||||
.read(changedItemsManagerProvider(
|
||||
managerId: 1)
|
||||
.notifier)
|
||||
.addUpdatedChapter(
|
||||
chapter, true, false);
|
||||
isar.updates
|
||||
.filter()
|
||||
.mangaIdEqualTo(chapter.mangaId)
|
||||
|
|
@ -1171,11 +1169,6 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
.deleteAllSync();
|
||||
isar.chapters.deleteSync(chapter.id!);
|
||||
}
|
||||
ref
|
||||
.read(changedItemsManagerProvider(
|
||||
managerId: 1)
|
||||
.notifier)
|
||||
.addDeletedManga(manga, false);
|
||||
isar.mangas.deleteSync(manga.id!);
|
||||
} else {
|
||||
manga.favorite = false;
|
||||
|
|
@ -1272,28 +1265,30 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
ListTileChapterFilter(
|
||||
label: l10n.downloaded,
|
||||
type: ref.watch(mangaFilterDownloadedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings)),
|
||||
onTap: () {
|
||||
ref
|
||||
.read(mangaFilterDownloadedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings)
|
||||
.notifier)
|
||||
.update();
|
||||
}),
|
||||
ListTileChapterFilter(
|
||||
label: widget.isManga ? l10n.unread : l10n.unwatched,
|
||||
label: widget.itemType != ItemType.anime
|
||||
? l10n.unread
|
||||
: l10n.unwatched,
|
||||
type: ref.watch(mangaFilterUnreadStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings)),
|
||||
onTap: () {
|
||||
ref
|
||||
.read(mangaFilterUnreadStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings)
|
||||
.notifier)
|
||||
|
|
@ -1302,13 +1297,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
ListTileChapterFilter(
|
||||
label: l10n.started,
|
||||
type: ref.watch(mangaFilterStartedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings)),
|
||||
onTap: () {
|
||||
ref
|
||||
.read(mangaFilterStartedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings)
|
||||
.notifier)
|
||||
|
|
@ -1317,14 +1312,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
ListTileChapterFilter(
|
||||
label: l10n.bookmarked,
|
||||
type: ref.watch(mangaFilterBookmarkedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings)),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
ref
|
||||
.read(mangaFilterBookmarkedStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
mangaList: _entries,
|
||||
settings: settings)
|
||||
.notifier)
|
||||
|
|
@ -1337,11 +1332,11 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
Consumer(builder: (context, ref, chil) {
|
||||
final reverse = ref
|
||||
.read(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga, settings: settings)
|
||||
itemType: widget.itemType, settings: settings)
|
||||
.notifier)
|
||||
.isReverse();
|
||||
final reverseChapter = ref.watch(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
return Column(
|
||||
children: [
|
||||
for (var i = 0; i < 7; i++)
|
||||
|
|
@ -1351,7 +1346,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
onTap: () {
|
||||
ref
|
||||
.read(sortLibraryMangaStateProvider(
|
||||
isManga: widget.isManga, settings: settings)
|
||||
itemType: widget.itemType, settings: settings)
|
||||
.notifier)
|
||||
.set(i);
|
||||
},
|
||||
|
|
@ -1362,25 +1357,25 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
}),
|
||||
Consumer(builder: (context, ref, chil) {
|
||||
final display = ref.watch(libraryDisplayTypeStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final displayV = ref.read(libraryDisplayTypeStateProvider(
|
||||
isManga: widget.isManga, settings: settings)
|
||||
itemType: widget.itemType, settings: settings)
|
||||
.notifier);
|
||||
final showCategoryTabs = ref.watch(libraryShowCategoryTabsStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final continueReaderBtn = ref.watch(
|
||||
libraryShowContinueReadingButtonStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final showNumbersOfItems = ref.watch(
|
||||
libraryShowNumbersOfItemsStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final downloadedChapter = ref.watch(
|
||||
libraryDownloadedChaptersStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final language = ref.watch(libraryLanguageStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
final localSource = ref.watch(libraryLocalSourceStateProvider(
|
||||
isManga: widget.isManga, settings: settings));
|
||||
itemType: widget.itemType, settings: settings));
|
||||
return SingleChildScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
child: Column(
|
||||
|
|
@ -1453,7 +1448,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final gridSize = ref.watch(libraryGridSizeStateProvider(
|
||||
isManga: widget.isManga)) ??
|
||||
itemType: widget.itemType)) ??
|
||||
0;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 8, right: 8, top: 10),
|
||||
|
|
@ -1486,14 +1481,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
HapticFeedback.vibrate();
|
||||
ref
|
||||
.read(libraryGridSizeStateProvider(
|
||||
isManga: widget.isManga)
|
||||
itemType: widget.itemType)
|
||||
.notifier)
|
||||
.set(value.toInt());
|
||||
},
|
||||
onChangeEnd: (value) {
|
||||
ref
|
||||
.read(libraryGridSizeStateProvider(
|
||||
isManga: widget.isManga)
|
||||
itemType: widget.itemType)
|
||||
.notifier)
|
||||
.set(value.toInt(), end: true);
|
||||
},
|
||||
|
|
@ -1518,14 +1513,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
child: Column(
|
||||
children: [
|
||||
ListTileChapterFilter(
|
||||
label: widget.isManga
|
||||
label: widget.itemType != ItemType.anime
|
||||
? l10n.downloaded_chapters
|
||||
: l10n.downloaded_episodes,
|
||||
type: downloadedChapter ? 1 : 0,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(libraryDownloadedChaptersStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
settings: settings)
|
||||
.notifier)
|
||||
.set(!downloadedChapter);
|
||||
|
|
@ -1536,7 +1531,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
onTap: () {
|
||||
ref
|
||||
.read(libraryLanguageStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
settings: settings)
|
||||
.notifier)
|
||||
.set(!language);
|
||||
|
|
@ -1547,13 +1542,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
onTap: () {
|
||||
ref
|
||||
.read(libraryLocalSourceStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
settings: settings)
|
||||
.notifier)
|
||||
.set(!localSource);
|
||||
}),
|
||||
ListTileChapterFilter(
|
||||
label: widget.isManga
|
||||
label: widget.itemType != ItemType.anime
|
||||
? l10n.show_continue_reading_buttons
|
||||
: l10n.show_continue_watching_buttons,
|
||||
type: continueReaderBtn ? 1 : 0,
|
||||
|
|
@ -1561,7 +1556,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
ref
|
||||
.read(
|
||||
libraryShowContinueReadingButtonStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
settings: settings)
|
||||
.notifier)
|
||||
.set(!continueReaderBtn);
|
||||
|
|
@ -1585,7 +1580,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
onTap: () {
|
||||
ref
|
||||
.read(libraryShowCategoryTabsStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
settings: settings)
|
||||
.notifier)
|
||||
.set(!showCategoryTabs);
|
||||
|
|
@ -1596,7 +1591,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
onTap: () {
|
||||
ref
|
||||
.read(libraryShowNumbersOfItemsStateProvider(
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
settings: settings)
|
||||
.notifier)
|
||||
.set(!showNumbersOfItems);
|
||||
|
|
@ -1616,15 +1611,23 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
if (index == 0) {
|
||||
return l10n.alphabetically;
|
||||
} 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) {
|
||||
return l10n.last_update_check;
|
||||
} 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) {
|
||||
return widget.isManga ? l10n.total_chapters : l10n.total_episodes;
|
||||
return widget.itemType != ItemType.anime
|
||||
? l10n.total_chapters
|
||||
: l10n.total_episodes;
|
||||
} 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;
|
||||
}
|
||||
|
|
@ -1641,10 +1644,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
|
||||
final mangaIdsList = ref.watch(mangasListStateProvider);
|
||||
final manga = categoryId == null
|
||||
? ref.watch(
|
||||
getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga))
|
||||
? ref.watch(getAllMangaWithoutCategoriesStreamProvider(
|
||||
itemType: widget.itemType))
|
||||
: ref.watch(getAllMangaStreamProvider(
|
||||
categoryId: categoryId, isManga: widget.isManga));
|
||||
categoryId: categoryId, itemType: widget.itemType));
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return PreferredSize(
|
||||
preferredSize: Size.fromHeight(AppBar().preferredSize.height),
|
||||
|
|
@ -1714,7 +1717,11 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
: Row(
|
||||
children: [
|
||||
Text(
|
||||
widget.isManga ? l10n.manga : l10n.anime,
|
||||
widget.itemType == ItemType.manga
|
||||
? l10n.manga
|
||||
: widget.itemType == ItemType.anime
|
||||
? l10n.anime
|
||||
: l10n.novel,
|
||||
style:
|
||||
TextStyle(color: Theme.of(context).hintColor),
|
||||
),
|
||||
|
|
@ -1790,7 +1797,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
value: 1, child: Text(l10n.open_random_entry)),
|
||||
PopupMenuItem<int>(
|
||||
value: 2, child: Text(l10n.import)),
|
||||
if (!widget.isManga)
|
||||
if (widget.itemType == ItemType.anime)
|
||||
PopupMenuItem<int>(
|
||||
value: 3, child: Text(l10n.torrent_stream)),
|
||||
];
|
||||
|
|
@ -1813,8 +1820,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
source: randomManga.source!);
|
||||
});
|
||||
} else if (value == 2) {
|
||||
_importLocal(context, widget.isManga);
|
||||
} else if (value == 3 && !widget.isManga) {
|
||||
_importLocal(context, widget.itemType);
|
||||
} else if (value == 3 &&
|
||||
widget.itemType == ItemType.anime) {
|
||||
addTorrent(context);
|
||||
}
|
||||
}),
|
||||
|
|
@ -1823,7 +1831,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||
}
|
||||
}
|
||||
|
||||
void _importLocal(BuildContext context, bool isManga) {
|
||||
void _importLocal(BuildContext context, ItemType itemType) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
bool isLoading = false;
|
||||
showDialog(
|
||||
|
|
@ -1857,7 +1865,7 @@ void _importLocal(BuildContext context, bool isManga) {
|
|||
});
|
||||
await ref.watch(
|
||||
importArchivesFromFileProvider(
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
null,
|
||||
init: true)
|
||||
.future);
|
||||
|
|
@ -1872,7 +1880,7 @@ void _importLocal(BuildContext context, bool isManga) {
|
|||
children: [
|
||||
const Icon(Icons.archive_outlined),
|
||||
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(
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ Future addTorrentFromUrlOrFromFile(Ref ref, Manga? mManga,
|
|||
favorite: true,
|
||||
source: 'torrent',
|
||||
author: '',
|
||||
isManga: false,
|
||||
itemType: ItemType.anime,
|
||||
genre: [],
|
||||
imageUrl: '',
|
||||
lang: '',
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'add_torrent.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$addTorrentFromUrlOrFromFileHash() =>
|
||||
r'8102259b30765a5c5cc57870f5c583bd5d421eee';
|
||||
r'11cc239bb8b517326f9a005b0c89dd5eb1127099';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ part 'isar_providers.g.dart';
|
|||
|
||||
@riverpod
|
||||
Stream<List<Manga>> getAllMangaStream(Ref ref,
|
||||
{required int? categoryId, required bool? isManga}) async* {
|
||||
{required int? categoryId, required ItemType itemType}) async* {
|
||||
yield* categoryId == null
|
||||
? isar.mangas
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.favoriteEqualTo(true)
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.itemTypeEqualTo(itemType)
|
||||
.watch(fireImmediately: true)
|
||||
: isar.mangas
|
||||
.filter()
|
||||
|
|
@ -24,26 +24,26 @@ Stream<List<Manga>> getAllMangaStream(Ref ref,
|
|||
.categoriesIsNotEmpty()
|
||||
.categoriesElementEqualTo(categoryId)
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.itemTypeEqualTo(itemType)
|
||||
.watch(fireImmediately: true);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Stream<List<Manga>> getAllMangaWithoutCategoriesStream(Ref ref,
|
||||
{required bool? isManga}) async* {
|
||||
{required ItemType itemType}) async* {
|
||||
yield* isar.mangas
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.favoriteEqualTo(true)
|
||||
.categoriesIsEmpty()
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.itemTypeEqualTo(itemType)
|
||||
.or()
|
||||
.idIsNotNull()
|
||||
.categoriesIsNull()
|
||||
.favoriteEqualTo(true)
|
||||
.and()
|
||||
.isMangaEqualTo(isManga)
|
||||
.itemTypeEqualTo(itemType)
|
||||
.watch(fireImmediately: true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'isar_providers.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getAllMangaStreamHash() => r'1c0b5442ae86b2fa899d509a555f5d375f0ff79a';
|
||||
String _$getAllMangaStreamHash() => r'5e86a22a68ca1a52aefa9c0bc675d284369beac5';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -41,11 +41,11 @@ class GetAllMangaStreamFamily extends Family<AsyncValue<List<Manga>>> {
|
|||
/// See also [getAllMangaStream].
|
||||
GetAllMangaStreamProvider call({
|
||||
required int? categoryId,
|
||||
required bool? isManga,
|
||||
required ItemType itemType,
|
||||
}) {
|
||||
return GetAllMangaStreamProvider(
|
||||
categoryId: categoryId,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ class GetAllMangaStreamFamily extends Family<AsyncValue<List<Manga>>> {
|
|||
) {
|
||||
return call(
|
||||
categoryId: provider.categoryId,
|
||||
isManga: provider.isManga,
|
||||
itemType: provider.itemType,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -79,12 +79,12 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
|
|||
/// See also [getAllMangaStream].
|
||||
GetAllMangaStreamProvider({
|
||||
required int? categoryId,
|
||||
required bool? isManga,
|
||||
required ItemType itemType,
|
||||
}) : this._internal(
|
||||
(ref) => getAllMangaStream(
|
||||
ref as GetAllMangaStreamRef,
|
||||
categoryId: categoryId,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
),
|
||||
from: getAllMangaStreamProvider,
|
||||
name: r'getAllMangaStreamProvider',
|
||||
|
|
@ -96,7 +96,7 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
|
|||
allTransitiveDependencies:
|
||||
GetAllMangaStreamFamily._allTransitiveDependencies,
|
||||
categoryId: categoryId,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
);
|
||||
|
||||
GetAllMangaStreamProvider._internal(
|
||||
|
|
@ -107,11 +107,11 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
|
|||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.categoryId,
|
||||
required this.isManga,
|
||||
required this.itemType,
|
||||
}) : super.internal();
|
||||
|
||||
final int? categoryId;
|
||||
final bool? isManga;
|
||||
final ItemType itemType;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
|
|
@ -127,7 +127,7 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
|
|||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
categoryId: categoryId,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -141,14 +141,14 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
|
|||
bool operator ==(Object other) {
|
||||
return other is GetAllMangaStreamProvider &&
|
||||
other.categoryId == categoryId &&
|
||||
other.isManga == isManga;
|
||||
other.itemType == itemType;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, categoryId.hashCode);
|
||||
hash = _SystemHash.combine(hash, isManga.hashCode);
|
||||
hash = _SystemHash.combine(hash, itemType.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
|
@ -160,8 +160,8 @@ mixin GetAllMangaStreamRef on AutoDisposeStreamProviderRef<List<Manga>> {
|
|||
/// The parameter `categoryId` of this provider.
|
||||
int? get categoryId;
|
||||
|
||||
/// The parameter `isManga` of this provider.
|
||||
bool? get isManga;
|
||||
/// The parameter `itemType` of this provider.
|
||||
ItemType get itemType;
|
||||
}
|
||||
|
||||
class _GetAllMangaStreamProviderElement
|
||||
|
|
@ -172,11 +172,11 @@ class _GetAllMangaStreamProviderElement
|
|||
@override
|
||||
int? get categoryId => (origin as GetAllMangaStreamProvider).categoryId;
|
||||
@override
|
||||
bool? get isManga => (origin as GetAllMangaStreamProvider).isManga;
|
||||
ItemType get itemType => (origin as GetAllMangaStreamProvider).itemType;
|
||||
}
|
||||
|
||||
String _$getAllMangaWithoutCategoriesStreamHash() =>
|
||||
r'78076f291274b7defd9567e55314002d9aeecab1';
|
||||
r'61ea54070c7e87a45aeabce5fd21366faaf4ae6d';
|
||||
|
||||
/// See also [getAllMangaWithoutCategoriesStream].
|
||||
@ProviderFor(getAllMangaWithoutCategoriesStream)
|
||||
|
|
@ -191,10 +191,10 @@ class GetAllMangaWithoutCategoriesStreamFamily
|
|||
|
||||
/// See also [getAllMangaWithoutCategoriesStream].
|
||||
GetAllMangaWithoutCategoriesStreamProvider call({
|
||||
required bool? isManga,
|
||||
required ItemType itemType,
|
||||
}) {
|
||||
return GetAllMangaWithoutCategoriesStreamProvider(
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +203,7 @@ class GetAllMangaWithoutCategoriesStreamFamily
|
|||
covariant GetAllMangaWithoutCategoriesStreamProvider provider,
|
||||
) {
|
||||
return call(
|
||||
isManga: provider.isManga,
|
||||
itemType: provider.itemType,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -227,11 +227,11 @@ class GetAllMangaWithoutCategoriesStreamProvider
|
|||
extends AutoDisposeStreamProvider<List<Manga>> {
|
||||
/// See also [getAllMangaWithoutCategoriesStream].
|
||||
GetAllMangaWithoutCategoriesStreamProvider({
|
||||
required bool? isManga,
|
||||
required ItemType itemType,
|
||||
}) : this._internal(
|
||||
(ref) => getAllMangaWithoutCategoriesStream(
|
||||
ref as GetAllMangaWithoutCategoriesStreamRef,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
),
|
||||
from: getAllMangaWithoutCategoriesStreamProvider,
|
||||
name: r'getAllMangaWithoutCategoriesStreamProvider',
|
||||
|
|
@ -242,7 +242,7 @@ class GetAllMangaWithoutCategoriesStreamProvider
|
|||
dependencies: GetAllMangaWithoutCategoriesStreamFamily._dependencies,
|
||||
allTransitiveDependencies: GetAllMangaWithoutCategoriesStreamFamily
|
||||
._allTransitiveDependencies,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
);
|
||||
|
||||
GetAllMangaWithoutCategoriesStreamProvider._internal(
|
||||
|
|
@ -252,10 +252,10 @@ class GetAllMangaWithoutCategoriesStreamProvider
|
|||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.isManga,
|
||||
required this.itemType,
|
||||
}) : super.internal();
|
||||
|
||||
final bool? isManga;
|
||||
final ItemType itemType;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
|
|
@ -271,7 +271,7 @@ class GetAllMangaWithoutCategoriesStreamProvider
|
|||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -284,13 +284,13 @@ class GetAllMangaWithoutCategoriesStreamProvider
|
|||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is GetAllMangaWithoutCategoriesStreamProvider &&
|
||||
other.isManga == isManga;
|
||||
other.itemType == itemType;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, isManga.hashCode);
|
||||
hash = _SystemHash.combine(hash, itemType.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
|
@ -300,8 +300,8 @@ class GetAllMangaWithoutCategoriesStreamProvider
|
|||
// ignore: unused_element
|
||||
mixin GetAllMangaWithoutCategoriesStreamRef
|
||||
on AutoDisposeStreamProviderRef<List<Manga>> {
|
||||
/// The parameter `isManga` of this provider.
|
||||
bool? get isManga;
|
||||
/// The parameter `itemType` of this provider.
|
||||
ItemType get itemType;
|
||||
}
|
||||
|
||||
class _GetAllMangaWithoutCategoriesStreamProviderElement
|
||||
|
|
@ -310,8 +310,8 @@ class _GetAllMangaWithoutCategoriesStreamProviderElement
|
|||
_GetAllMangaWithoutCategoriesStreamProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
bool? get isManga =>
|
||||
(origin as GetAllMangaWithoutCategoriesStreamProvider).isManga;
|
||||
ItemType get itemType =>
|
||||
(origin as GetAllMangaWithoutCategoriesStreamProvider).itemType;
|
||||
}
|
||||
|
||||
String _$getSettingsStreamHash() => r'c5a51e0e3473b25d2365025832a27ed2cc029b27';
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import 'package:mangayomi/models/chapter.dart';
|
|||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'library_state_provider.g.dart';
|
||||
|
|
@ -12,8 +11,15 @@ part 'library_state_provider.g.dart';
|
|||
@riverpod
|
||||
class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
|
||||
@override
|
||||
DisplayType build({required bool isManga, required Settings settings}) {
|
||||
return isManga ? settings.displayType : settings.animeDisplayType;
|
||||
DisplayType build({required ItemType itemType, required Settings settings}) {
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.displayType;
|
||||
case ItemType.anime:
|
||||
return settings.animeDisplayType;
|
||||
default:
|
||||
return settings.novelDisplayType;
|
||||
}
|
||||
}
|
||||
|
||||
String getLibraryDisplayTypeName(
|
||||
|
|
@ -31,10 +37,16 @@ class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
|
|||
Settings appSettings = Settings();
|
||||
|
||||
state = displayType;
|
||||
if (isManga) {
|
||||
appSettings = settings..displayType = displayType;
|
||||
} else {
|
||||
appSettings = settings..animeDisplayType = displayType;
|
||||
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..displayType = displayType;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..animeDisplayType = displayType;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..novelDisplayType = displayType;
|
||||
}
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
|
|
@ -46,8 +58,15 @@ class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
|
|||
@riverpod
|
||||
class LibraryGridSizeState extends _$LibraryGridSizeState {
|
||||
@override
|
||||
int? build({required bool isManga}) {
|
||||
return isManga ? settings.mangaGridSize : settings.animeGridSize;
|
||||
int? build({required ItemType itemType}) {
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.mangaGridSize;
|
||||
case ItemType.anime:
|
||||
return settings.animeGridSize;
|
||||
default:
|
||||
return settings.novelGridSize;
|
||||
}
|
||||
}
|
||||
|
||||
Settings get settings {
|
||||
|
|
@ -59,10 +78,15 @@ class LibraryGridSizeState extends _$LibraryGridSizeState {
|
|||
|
||||
state = value;
|
||||
if (end) {
|
||||
if (isManga) {
|
||||
appSettings = settings..mangaGridSize = value;
|
||||
} else {
|
||||
appSettings = settings..animeGridSize = value;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..mangaGridSize = value;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..animeGridSize = value;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..novelGridSize = value;
|
||||
}
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
|
|
@ -77,24 +101,34 @@ class MangaFilterDownloadedState extends _$MangaFilterDownloadedState {
|
|||
@override
|
||||
int build(
|
||||
{required List<Manga> mangaList,
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
required Settings settings}) {
|
||||
state = getType();
|
||||
return getType();
|
||||
}
|
||||
|
||||
int getType() {
|
||||
return isManga
|
||||
? settings.libraryFilterMangasDownloadType!
|
||||
: settings.libraryFilterAnimeDownloadType ?? 0;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.libraryFilterMangasDownloadType!;
|
||||
case ItemType.anime:
|
||||
return settings.libraryFilterAnimeDownloadType!;
|
||||
default:
|
||||
return settings.libraryFilterNovelDownloadType ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
void setType(int type) {
|
||||
Settings appSettings = Settings();
|
||||
if (isManga) {
|
||||
appSettings = settings..libraryFilterMangasDownloadType = type;
|
||||
} else {
|
||||
appSettings = settings..libraryFilterAnimeDownloadType = type;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..libraryFilterMangasDownloadType = type;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..libraryFilterAnimeDownloadType = type;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..libraryFilterNovelDownloadType = type;
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(appSettings);
|
||||
|
|
@ -118,24 +152,34 @@ class MangaFilterUnreadState extends _$MangaFilterUnreadState {
|
|||
@override
|
||||
int build(
|
||||
{required List<Manga> mangaList,
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
required Settings settings}) {
|
||||
state = getType();
|
||||
return getType();
|
||||
}
|
||||
|
||||
int getType() {
|
||||
return isManga
|
||||
? settings.libraryFilterMangasUnreadType!
|
||||
: settings.libraryFilterAnimeUnreadType ?? 0;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.libraryFilterMangasUnreadType!;
|
||||
case ItemType.anime:
|
||||
return settings.libraryFilterAnimeUnreadType!;
|
||||
default:
|
||||
return settings.libraryFilterNovelUnreadType ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
void setType(int type) {
|
||||
Settings appSettings = Settings();
|
||||
if (isManga) {
|
||||
appSettings = settings..libraryFilterMangasUnreadType = type;
|
||||
} else {
|
||||
appSettings = settings..libraryFilterAnimeUnreadType = type;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..libraryFilterMangasUnreadType = type;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..libraryFilterAnimeUnreadType = type;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..libraryFilterNovelUnreadType = type;
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(appSettings);
|
||||
|
|
@ -208,24 +252,34 @@ class MangaFilterStartedState extends _$MangaFilterStartedState {
|
|||
@override
|
||||
int build(
|
||||
{required List<Manga> mangaList,
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
required Settings settings}) {
|
||||
state = getType();
|
||||
return getType();
|
||||
}
|
||||
|
||||
int getType() {
|
||||
return isManga
|
||||
? settings.libraryFilterMangasStartedType!
|
||||
: settings.libraryFilterAnimeStartedType ?? 0;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.libraryFilterMangasStartedType!;
|
||||
case ItemType.anime:
|
||||
return settings.libraryFilterAnimeStartedType!;
|
||||
default:
|
||||
return settings.libraryFilterNovelStartedType ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
void setType(int type) {
|
||||
Settings appSettings = Settings();
|
||||
if (isManga) {
|
||||
appSettings = settings..libraryFilterMangasStartedType = type;
|
||||
} else {
|
||||
appSettings = settings..libraryFilterAnimeStartedType = type;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..libraryFilterMangasStartedType = type;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..libraryFilterAnimeStartedType = type;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..libraryFilterNovelStartedType = type;
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(appSettings);
|
||||
|
|
@ -298,24 +352,34 @@ class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState {
|
|||
@override
|
||||
int build(
|
||||
{required List<Manga> mangaList,
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
required Settings settings}) {
|
||||
state = getType();
|
||||
return getType();
|
||||
}
|
||||
|
||||
int getType() {
|
||||
return isManga
|
||||
? settings.libraryFilterMangasBookMarkedType!
|
||||
: settings.libraryFilterAnimeBookMarkedType ?? 0;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.libraryFilterMangasBookMarkedType!;
|
||||
case ItemType.anime:
|
||||
return settings.libraryFilterAnimeBookMarkedType!;
|
||||
default:
|
||||
return settings.libraryFilterNovelBookMarkedType ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
void setType(int type) {
|
||||
Settings appSettings = Settings();
|
||||
if (isManga) {
|
||||
appSettings = settings..libraryFilterMangasBookMarkedType = type;
|
||||
} else {
|
||||
appSettings = settings..libraryFilterAnimeBookMarkedType = type;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..libraryFilterMangasBookMarkedType = type;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..libraryFilterAnimeBookMarkedType = type;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..libraryFilterNovelBookMarkedType = type;
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(appSettings);
|
||||
|
|
@ -388,16 +452,16 @@ class MangasFilterResultState extends _$MangasFilterResultState {
|
|||
@override
|
||||
bool build(
|
||||
{required List<Manga> mangaList,
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
required Settings settings}) {
|
||||
final downloadFilterType = ref.watch(mangaFilterDownloadedStateProvider(
|
||||
mangaList: mangaList, isManga: isManga, settings: settings));
|
||||
mangaList: mangaList, itemType: itemType, settings: settings));
|
||||
final unreadFilterType = ref.watch(mangaFilterUnreadStateProvider(
|
||||
mangaList: mangaList, isManga: isManga, settings: settings));
|
||||
mangaList: mangaList, itemType: itemType, settings: settings));
|
||||
final startedFilterType = ref.watch(mangaFilterStartedStateProvider(
|
||||
mangaList: mangaList, isManga: isManga, settings: settings));
|
||||
mangaList: mangaList, itemType: itemType, settings: settings));
|
||||
final bookmarkedFilterType = ref.watch(mangaFilterBookmarkedStateProvider(
|
||||
mangaList: mangaList, isManga: isManga, settings: settings));
|
||||
mangaList: mangaList, itemType: itemType, settings: settings));
|
||||
return downloadFilterType == 0 &&
|
||||
unreadFilterType == 0 &&
|
||||
startedFilterType == 0 &&
|
||||
|
|
@ -408,18 +472,28 @@ class MangasFilterResultState extends _$MangasFilterResultState {
|
|||
@riverpod
|
||||
class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
|
||||
@override
|
||||
bool build({required bool isManga, required Settings settings}) {
|
||||
return isManga
|
||||
? settings.libraryShowCategoryTabs!
|
||||
: settings.animeLibraryShowCategoryTabs ?? false;
|
||||
bool build({required ItemType itemType, required Settings settings}) {
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.libraryShowCategoryTabs!;
|
||||
case ItemType.anime:
|
||||
return settings.animeLibraryShowCategoryTabs!;
|
||||
default:
|
||||
return settings.novelLibraryShowCategoryTabs ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
Settings appSettings = Settings();
|
||||
if (isManga) {
|
||||
appSettings = settings..libraryShowCategoryTabs = value;
|
||||
} else {
|
||||
appSettings = settings..animeLibraryShowCategoryTabs = value;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..libraryShowCategoryTabs = value;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..animeLibraryShowCategoryTabs = value;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..novelLibraryShowCategoryTabs = value;
|
||||
}
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
|
|
@ -431,18 +505,28 @@ class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
|
|||
@riverpod
|
||||
class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
|
||||
@override
|
||||
bool build({required bool isManga, required Settings settings}) {
|
||||
return isManga
|
||||
? settings.libraryDownloadedChapters!
|
||||
: settings.animeLibraryDownloadedChapters ?? false;
|
||||
bool build({required ItemType itemType, required Settings settings}) {
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.libraryDownloadedChapters!;
|
||||
case ItemType.anime:
|
||||
return settings.animeLibraryDownloadedChapters!;
|
||||
default:
|
||||
return settings.novelLibraryDownloadedChapters ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
Settings appSettings = Settings();
|
||||
if (isManga) {
|
||||
appSettings = settings..libraryDownloadedChapters = value;
|
||||
} else {
|
||||
appSettings = settings..animeLibraryDownloadedChapters = value;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..libraryDownloadedChapters = value;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..animeLibraryDownloadedChapters = value;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..novelLibraryDownloadedChapters = value;
|
||||
}
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
|
|
@ -454,18 +538,28 @@ class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
|
|||
@riverpod
|
||||
class LibraryLanguageState extends _$LibraryLanguageState {
|
||||
@override
|
||||
bool build({required bool isManga, required Settings settings}) {
|
||||
return isManga
|
||||
? settings.libraryShowLanguage!
|
||||
: settings.animeLibraryShowLanguage ?? false;
|
||||
bool build({required ItemType itemType, required Settings settings}) {
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.libraryShowLanguage!;
|
||||
case ItemType.anime:
|
||||
return settings.animeLibraryShowLanguage!;
|
||||
default:
|
||||
return settings.novelLibraryShowLanguage ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
Settings appSettings = Settings();
|
||||
if (isManga) {
|
||||
appSettings = settings..libraryShowLanguage = value;
|
||||
} else {
|
||||
appSettings = settings..animeLibraryShowLanguage = value;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..libraryShowLanguage = value;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..animeLibraryShowLanguage = value;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..novelLibraryShowLanguage = value;
|
||||
}
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
|
|
@ -477,18 +571,28 @@ class LibraryLanguageState extends _$LibraryLanguageState {
|
|||
@riverpod
|
||||
class LibraryLocalSourceState extends _$LibraryLocalSourceState {
|
||||
@override
|
||||
bool build({required bool isManga, required Settings settings}) {
|
||||
return isManga
|
||||
? settings.libraryLocalSource ?? false
|
||||
: settings.animeLibraryLocalSource ?? false;
|
||||
bool build({required ItemType itemType, required Settings settings}) {
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.libraryLocalSource ?? false;
|
||||
case ItemType.anime:
|
||||
return settings.animeLibraryLocalSource ?? false;
|
||||
default:
|
||||
return settings.novelLibraryLocalSource ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
Settings appSettings = Settings();
|
||||
if (isManga) {
|
||||
appSettings = settings..libraryLocalSource = value;
|
||||
} else {
|
||||
appSettings = settings..animeLibraryLocalSource = value;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..libraryLocalSource = value;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..animeLibraryLocalSource = value;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..novelLibraryLocalSource = value;
|
||||
}
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
|
|
@ -500,18 +604,28 @@ class LibraryLocalSourceState extends _$LibraryLocalSourceState {
|
|||
@riverpod
|
||||
class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
|
||||
@override
|
||||
bool build({required bool isManga, required Settings settings}) {
|
||||
return isManga
|
||||
? settings.libraryShowNumbersOfItems!
|
||||
: settings.animeLibraryShowNumbersOfItems ?? false;
|
||||
bool build({required ItemType itemType, required Settings settings}) {
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.libraryShowNumbersOfItems!;
|
||||
case ItemType.anime:
|
||||
return settings.animeLibraryShowNumbersOfItems!;
|
||||
default:
|
||||
return settings.novelLibraryShowNumbersOfItems ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
Settings appSettings = Settings();
|
||||
if (isManga) {
|
||||
appSettings = settings..libraryShowNumbersOfItems = value;
|
||||
} else {
|
||||
appSettings = settings..animeLibraryShowNumbersOfItems = value;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..libraryShowNumbersOfItems = value;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..animeLibraryShowNumbersOfItems = value;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..novelLibraryShowNumbersOfItems = value;
|
||||
}
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
|
|
@ -524,18 +638,28 @@ class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
|
|||
class LibraryShowContinueReadingButtonState
|
||||
extends _$LibraryShowContinueReadingButtonState {
|
||||
@override
|
||||
bool build({required bool isManga, required Settings settings}) {
|
||||
return isManga
|
||||
? settings.libraryShowContinueReadingButton!
|
||||
: settings.animeLibraryShowContinueReadingButton ?? false;
|
||||
bool build({required ItemType itemType, required Settings settings}) {
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.libraryShowContinueReadingButton!;
|
||||
case ItemType.anime:
|
||||
return settings.animeLibraryShowContinueReadingButton!;
|
||||
default:
|
||||
return settings.novelLibraryShowContinueReadingButton ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
Settings appSettings = Settings();
|
||||
if (isManga) {
|
||||
appSettings = settings..libraryShowContinueReadingButton = value;
|
||||
} else {
|
||||
appSettings = settings..animeLibraryShowContinueReadingButton = value;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..libraryShowContinueReadingButton = value;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..animeLibraryShowContinueReadingButton = value;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..novelLibraryShowContinueReadingButton = value;
|
||||
}
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
|
|
@ -547,10 +671,15 @@ class LibraryShowContinueReadingButtonState
|
|||
@riverpod
|
||||
class SortLibraryMangaState extends _$SortLibraryMangaState {
|
||||
@override
|
||||
SortLibraryManga build({required bool isManga, required Settings settings}) {
|
||||
return isManga
|
||||
? settings.sortLibraryManga ?? SortLibraryManga()
|
||||
: settings.sortLibraryAnime ?? SortLibraryManga();
|
||||
SortLibraryManga build({required ItemType itemType, required Settings settings}) {
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
return settings.sortLibraryManga ?? SortLibraryManga();
|
||||
case ItemType.anime:
|
||||
return settings.sortLibraryAnime ?? SortLibraryManga();
|
||||
default:
|
||||
return settings.sortLibraryNovel ?? SortLibraryManga();
|
||||
}
|
||||
}
|
||||
|
||||
void update(bool reverse, int index) {
|
||||
|
|
@ -559,10 +688,15 @@ class SortLibraryMangaState extends _$SortLibraryMangaState {
|
|||
..index = index
|
||||
..reverse = state.index == index ? !reverse : reverse;
|
||||
|
||||
if (isManga) {
|
||||
appSettings = settings..sortLibraryManga = value;
|
||||
} else {
|
||||
appSettings = settings..sortLibraryAnime = value;
|
||||
switch (itemType) {
|
||||
case ItemType.manga:
|
||||
appSettings = settings..sortLibraryManga = value;
|
||||
break;
|
||||
case ItemType.anime:
|
||||
appSettings = settings..sortLibraryAnime = value;
|
||||
break;
|
||||
default:
|
||||
appSettings = settings..sortLibraryNovel = value;
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.settings.putSync(appSettings);
|
||||
|
|
@ -651,9 +785,6 @@ class MangasSetIsReadState extends _$MangasSetIsReadState {
|
|||
for (var chapter in chapters) {
|
||||
chapter.isRead = true;
|
||||
chapter.lastPageRead = "1";
|
||||
ref
|
||||
.read(changedItemsManagerProvider(managerId: 1).notifier)
|
||||
.addUpdatedChapter(chapter, false, false);
|
||||
isar.chapters.putSync(chapter..manga.value = manga);
|
||||
chapter.manga.saveSync();
|
||||
}
|
||||
|
|
@ -678,9 +809,6 @@ class MangasSetUnReadState extends _$MangasSetUnReadState {
|
|||
isar.writeTxnSync(() {
|
||||
for (var chapter in chapters) {
|
||||
chapter.isRead = false;
|
||||
ref
|
||||
.read(changedItemsManagerProvider(managerId: 1).notifier)
|
||||
.addUpdatedChapter(chapter, false, false);
|
||||
isar.chapters.putSync(chapter..manga.value = manga);
|
||||
chapter.manga.saveSync();
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -11,11 +11,11 @@ part 'local_archive.g.dart';
|
|||
|
||||
@riverpod
|
||||
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(
|
||||
allowMultiple: true,
|
||||
type: FileType.custom,
|
||||
allowedExtensions: isManga
|
||||
allowedExtensions: itemType == ItemType.manga
|
||||
? ['cbz', 'zip']
|
||||
: ['mp4', 'mov', 'avi', 'flv', 'wmv', 'mpeg', 'mkv']);
|
||||
if (result != null) {
|
||||
|
|
@ -25,7 +25,7 @@ Future importArchivesFromFile(Ref ref, Manga? mManga,
|
|||
favorite: true,
|
||||
source: 'archive',
|
||||
author: '',
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
genre: [],
|
||||
imageUrl: '',
|
||||
lang: '',
|
||||
|
|
@ -39,20 +39,20 @@ Future importArchivesFromFile(Ref ref, Manga? mManga,
|
|||
artist: '',
|
||||
);
|
||||
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)
|
||||
: null;
|
||||
String name = _getName(file.path!);
|
||||
|
||||
if (init) {
|
||||
manga.customCoverImage = isManga ? data!.$3 : null;
|
||||
manga.customCoverImage = itemType == ItemType.manga ? data!.$3 : null;
|
||||
}
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
isar.mangas.putSync(manga);
|
||||
final chapters = Chapter(
|
||||
name: isManga ? data!.$1 : name,
|
||||
archivePath: isManga ? data!.$4 : file.path,
|
||||
name: itemType == ItemType.manga ? data!.$1 : name,
|
||||
archivePath: itemType == ItemType.manga ? data!.$4 : file.path,
|
||||
mangaId: manga.id)
|
||||
..manga.value = manga;
|
||||
isar.chapters.putSync(chapters);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'local_archive.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$importArchivesFromFileHash() =>
|
||||
r'8be95f0947ab5247e3305a355a6f17f0aaecad00';
|
||||
r'8e6e592c927ad080e93d54dac1144ef8637a7e52';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -42,12 +42,12 @@ class ImportArchivesFromFileFamily extends Family<AsyncValue> {
|
|||
/// See also [importArchivesFromFile].
|
||||
ImportArchivesFromFileProvider call(
|
||||
Manga? mManga, {
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
required bool init,
|
||||
}) {
|
||||
return ImportArchivesFromFileProvider(
|
||||
mManga,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
init: init,
|
||||
);
|
||||
}
|
||||
|
|
@ -58,7 +58,7 @@ class ImportArchivesFromFileFamily extends Family<AsyncValue> {
|
|||
) {
|
||||
return call(
|
||||
provider.mManga,
|
||||
isManga: provider.isManga,
|
||||
itemType: provider.itemType,
|
||||
init: provider.init,
|
||||
);
|
||||
}
|
||||
|
|
@ -84,13 +84,13 @@ class ImportArchivesFromFileProvider
|
|||
/// See also [importArchivesFromFile].
|
||||
ImportArchivesFromFileProvider(
|
||||
Manga? mManga, {
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
required bool init,
|
||||
}) : this._internal(
|
||||
(ref) => importArchivesFromFile(
|
||||
ref as ImportArchivesFromFileRef,
|
||||
mManga,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
init: init,
|
||||
),
|
||||
from: importArchivesFromFileProvider,
|
||||
|
|
@ -103,7 +103,7 @@ class ImportArchivesFromFileProvider
|
|||
allTransitiveDependencies:
|
||||
ImportArchivesFromFileFamily._allTransitiveDependencies,
|
||||
mManga: mManga,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
init: init,
|
||||
);
|
||||
|
||||
|
|
@ -115,12 +115,12 @@ class ImportArchivesFromFileProvider
|
|||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.mManga,
|
||||
required this.isManga,
|
||||
required this.itemType,
|
||||
required this.init,
|
||||
}) : super.internal();
|
||||
|
||||
final Manga? mManga;
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
final bool init;
|
||||
|
||||
@override
|
||||
|
|
@ -137,7 +137,7 @@ class ImportArchivesFromFileProvider
|
|||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
mManga: mManga,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
init: init,
|
||||
),
|
||||
);
|
||||
|
|
@ -152,7 +152,7 @@ class ImportArchivesFromFileProvider
|
|||
bool operator ==(Object other) {
|
||||
return other is ImportArchivesFromFileProvider &&
|
||||
other.mManga == mManga &&
|
||||
other.isManga == isManga &&
|
||||
other.itemType == itemType &&
|
||||
other.init == init;
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ class ImportArchivesFromFileProvider
|
|||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.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);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
|
|
@ -173,8 +173,8 @@ mixin ImportArchivesFromFileRef on AutoDisposeFutureProviderRef<Object?> {
|
|||
/// The parameter `mManga` of this provider.
|
||||
Manga? get mManga;
|
||||
|
||||
/// The parameter `isManga` of this provider.
|
||||
bool get isManga;
|
||||
/// The parameter `itemType` of this provider.
|
||||
ItemType get itemType;
|
||||
|
||||
/// The parameter `init` of this provider.
|
||||
bool get init;
|
||||
|
|
@ -188,7 +188,7 @@ class _ImportArchivesFromFileProviderElement
|
|||
@override
|
||||
Manga? get mManga => (origin as ImportArchivesFromFileProvider).mManga;
|
||||
@override
|
||||
bool get isManga => (origin as ImportArchivesFromFileProvider).isManga;
|
||||
ItemType get itemType => (origin as ImportArchivesFromFileProvider).itemType;
|
||||
@override
|
||||
bool get init => (origin as ImportArchivesFromFileProvider).init;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class LibraryGridViewWidget extends StatefulWidget {
|
|||
final bool downloadedChapter;
|
||||
final bool continueReaderBtn;
|
||||
final bool localSource;
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
const LibraryGridViewWidget(
|
||||
{super.key,
|
||||
required this.entriesManga,
|
||||
|
|
@ -40,7 +40,7 @@ class LibraryGridViewWidget extends StatefulWidget {
|
|||
required this.continueReaderBtn,
|
||||
required this.mangaIdsList,
|
||||
required this.localSource,
|
||||
required this.isManga});
|
||||
required this.itemType});
|
||||
|
||||
@override
|
||||
State<LibraryGridViewWidget> createState() => _LibraryGridViewWidgetState();
|
||||
|
|
@ -51,10 +51,10 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
|
|||
Widget build(BuildContext context) {
|
||||
return Consumer(builder: (context, ref, child) {
|
||||
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
|
||||
final isManga = widget.isManga;
|
||||
final itemType = widget.itemType;
|
||||
|
||||
final gridSize =
|
||||
ref.watch(libraryGridSizeStateProvider(isManga: isManga));
|
||||
ref.watch(libraryGridSizeStateProvider(itemType: itemType));
|
||||
return GridViewWidget(
|
||||
gridSize: gridSize,
|
||||
childAspectRatio: widget.isComfortableGrid ? 0.642 : 0.69,
|
||||
|
|
@ -97,9 +97,9 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
|
|||
mangaM: entry,
|
||||
source: entry.source!);
|
||||
ref.invalidate(getAllMangaWithoutCategoriesStreamProvider(
|
||||
isManga: widget.isManga));
|
||||
itemType: widget.itemType));
|
||||
ref.invalidate(getAllMangaStreamProvider(
|
||||
categoryId: null, isManga: widget.isManga));
|
||||
categoryId: null, itemType: widget.itemType));
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
|
|
@ -279,7 +279,7 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
|
|||
.idIsNotNull()
|
||||
.and()
|
||||
.chapter((q) => q.manga((q) =>
|
||||
q.isMangaEqualTo(entry.isManga!)))
|
||||
q.itemTypeEqualTo(entry.itemType)))
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData &&
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
mangaM: entry,
|
||||
source: entry.source!);
|
||||
ref.invalidate(getAllMangaWithoutCategoriesStreamProvider(
|
||||
isManga: entry.isManga));
|
||||
itemType: entry.itemType));
|
||||
ref.invalidate(getAllMangaStreamProvider(
|
||||
categoryId: null, isManga: entry.isManga));
|
||||
categoryId: null, itemType: entry.itemType));
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
|
|
@ -264,7 +264,7 @@ class LibraryListViewWidget extends StatelessWidget {
|
|||
.idIsNotNull()
|
||||
.and()
|
||||
.chapter((q) => q.manga((q) =>
|
||||
q.isMangaEqualTo(entry.isManga!)))
|
||||
q.itemTypeEqualTo(entry.itemType)))
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData &&
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:isar/isar.dart';
|
|||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/update.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
|
||||
import 'package:mangayomi/modules/widgets/loading_icon.dart';
|
||||
import 'package:mangayomi/services/fetch_anime_sources.dart';
|
||||
import 'package:mangayomi/services/fetch_manga_sources.dart';
|
||||
|
|
@ -54,16 +55,34 @@ class MainScreen extends ConsumerWidget {
|
|||
final location = ref.watch(
|
||||
routerCurrentLocationStateProvider(context),
|
||||
);
|
||||
bool isReadingScreen =
|
||||
location == '/mangareaderview' || location == '/animePlayerView';
|
||||
int currentIndex = switch (location) {
|
||||
null || '/MangaLibrary' => 0,
|
||||
'/AnimeLibrary' => 1,
|
||||
'/updates' => 2,
|
||||
'/history' => 3,
|
||||
'/browse' => 4,
|
||||
_ => 5,
|
||||
};
|
||||
final hideManga = ref.watch(hideMangaStateProvider);
|
||||
final hideAnime = ref.watch(hideAnimeStateProvider);
|
||||
final hideNovel = ref.watch(hideNovelStateProvider);
|
||||
bool isReadingScreen = location == '/mangaReaderView' ||
|
||||
location == '/animePlayerView' ||
|
||||
location == '/novelReaderView';
|
||||
final dest = [
|
||||
'/MangaLibrary',
|
||||
'/AnimeLibrary',
|
||||
'/NovelLibrary',
|
||||
'/updates',
|
||||
'/history',
|
||||
'/browse',
|
||||
'/more'
|
||||
];
|
||||
if (hideManga) {
|
||||
dest.removeWhere((d) => d == "/MangaLibrary");
|
||||
}
|
||||
if (hideAnime) {
|
||||
dest.removeWhere((d) => d == "/AnimeLibrary");
|
||||
}
|
||||
if (hideNovel) {
|
||||
dest.removeWhere((d) => d == "/NovelLibrary");
|
||||
}
|
||||
int currentIndex = dest.indexOf(location ?? "/more");
|
||||
if (currentIndex == -1) {
|
||||
currentIndex = dest.length - 1;
|
||||
}
|
||||
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
|
||||
|
|
@ -111,6 +130,7 @@ class MainScreen extends ConsumerWidget {
|
|||
null => 100,
|
||||
!= '/MangaLibrary' &&
|
||||
!= '/AnimeLibrary' &&
|
||||
!= '/NovelLibrary' &&
|
||||
!= '/history' &&
|
||||
!= '/updates' &&
|
||||
!= '/browse' &&
|
||||
|
|
@ -132,29 +152,50 @@ class MainScreen extends ConsumerWidget {
|
|||
labelType: NavigationRailLabelType.all,
|
||||
useIndicator: true,
|
||||
destinations: [
|
||||
if (!hideManga)
|
||||
NavigationRailDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.collections_bookmark),
|
||||
icon: const Icon(Icons
|
||||
.collections_bookmark_outlined),
|
||||
label: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(
|
||||
top: 5),
|
||||
child: Text(l10n.manga))),
|
||||
if (!hideAnime)
|
||||
NavigationRailDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.video_collection),
|
||||
icon: const Icon(Icons
|
||||
.video_collection_outlined),
|
||||
label: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(
|
||||
top: 5),
|
||||
child: Text(l10n.anime))),
|
||||
if (!hideNovel)
|
||||
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(
|
||||
selectedIcon: const Icon(
|
||||
Icons.collections_bookmark),
|
||||
icon: const Icon(Icons
|
||||
.collections_bookmark_outlined),
|
||||
label: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 5),
|
||||
child: Text(l10n.manga))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.video_collection),
|
||||
icon: const Icon(Icons
|
||||
.video_collection_outlined),
|
||||
label: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 5),
|
||||
child: Text(l10n.anime))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.new_releases),
|
||||
icon: const Icon(
|
||||
Icons.new_releases_outlined),
|
||||
selectedIcon: Badge(
|
||||
label: _updatesTotalNumbers(ref),
|
||||
child: const Icon(
|
||||
Icons.new_releases),
|
||||
),
|
||||
icon: Badge(
|
||||
label: _updatesTotalNumbers(ref),
|
||||
child: const Icon(
|
||||
Icons.new_releases_outlined),
|
||||
),
|
||||
label: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 5),
|
||||
|
|
@ -183,10 +224,19 @@ class MainScreen extends ConsumerWidget {
|
|||
top: 5),
|
||||
child: Text(l10n.history))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.explore),
|
||||
icon: const Icon(
|
||||
Icons.explore_outlined),
|
||||
selectedIcon: Badge(
|
||||
label:
|
||||
_extensionUpdateTotalNumbers(
|
||||
ref),
|
||||
child: const Icon(Icons.explore),
|
||||
),
|
||||
icon: Badge(
|
||||
label:
|
||||
_extensionUpdateTotalNumbers(
|
||||
ref),
|
||||
child: const Icon(
|
||||
Icons.explore_outlined),
|
||||
),
|
||||
label: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 5),
|
||||
|
|
@ -203,27 +253,34 @@ class MainScreen extends ConsumerWidget {
|
|||
],
|
||||
selectedIndex: currentIndex,
|
||||
onDestinationSelected: (newIndex) {
|
||||
final fn = switch (newIndex) {
|
||||
0 => route.go('/MangaLibrary'),
|
||||
1 => route.go('/AnimeLibrary'),
|
||||
2 => route.go('/updates'),
|
||||
3 => route.go('/history'),
|
||||
4 => route.go('/browse'),
|
||||
_ => route.go('/more'),
|
||||
};
|
||||
fn;
|
||||
final dest = [
|
||||
'/MangaLibrary',
|
||||
'/AnimeLibrary',
|
||||
'/NovelLibrary',
|
||||
'/updates',
|
||||
'/history',
|
||||
'/browse',
|
||||
'/more'
|
||||
];
|
||||
if (hideManga) {
|
||||
dest.removeWhere(
|
||||
(d) => d == "/MangaLibrary");
|
||||
}
|
||||
if (hideAnime) {
|
||||
dest.removeWhere(
|
||||
(d) => d == "/AnimeLibrary");
|
||||
}
|
||||
if (hideNovel) {
|
||||
dest.removeWhere(
|
||||
(d) => d == "/NovelLibrary");
|
||||
}
|
||||
route.go(dest[newIndex >= dest.length
|
||||
? dest.length - 1
|
||||
: newIndex]);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
Positioned(
|
||||
right: 18,
|
||||
top: 140,
|
||||
child: _updatesTotalNumbers(ref)),
|
||||
Positioned(
|
||||
right: 18,
|
||||
top: 275,
|
||||
child: _extensionUpdateTotalNumbers(ref)),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -242,6 +299,7 @@ class MainScreen extends ConsumerWidget {
|
|||
null => null,
|
||||
!= '/MangaLibrary' &&
|
||||
!= '/AnimeLibrary' &&
|
||||
!= '/NovelLibrary' &&
|
||||
!= '/history' &&
|
||||
!= '/updates' &&
|
||||
!= '/browse' &&
|
||||
|
|
@ -260,63 +318,76 @@ class MainScreen extends ConsumerWidget {
|
|||
const Duration(milliseconds: 500),
|
||||
selectedIndex: currentIndex,
|
||||
destinations: [
|
||||
if (!hideManga)
|
||||
NavigationDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.collections_bookmark),
|
||||
icon: const Icon(
|
||||
Icons.collections_bookmark_outlined),
|
||||
label: l10n.manga),
|
||||
if (!hideAnime)
|
||||
NavigationDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.video_collection),
|
||||
icon: const Icon(
|
||||
Icons.video_collection_outlined),
|
||||
label: l10n.anime),
|
||||
if (!hideNovel)
|
||||
NavigationDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.local_library),
|
||||
icon: const Icon(
|
||||
Icons.local_library_outlined),
|
||||
label: l10n.novel),
|
||||
NavigationDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.collections_bookmark),
|
||||
icon: const Icon(
|
||||
Icons.collections_bookmark_outlined),
|
||||
label: l10n.manga),
|
||||
NavigationDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.video_collection),
|
||||
icon: const Icon(
|
||||
Icons.video_collection_outlined),
|
||||
label: l10n.anime),
|
||||
Stack(
|
||||
children: [
|
||||
NavigationDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.new_releases),
|
||||
icon: const Icon(
|
||||
Icons.new_releases_outlined),
|
||||
label: l10n.updates),
|
||||
Positioned(
|
||||
right: 14,
|
||||
top: 3,
|
||||
child: _updatesTotalNumbers(ref)),
|
||||
],
|
||||
),
|
||||
selectedIcon: Badge(
|
||||
label: _updatesTotalNumbers(ref),
|
||||
child: const Icon(Icons.new_releases),
|
||||
),
|
||||
icon: Badge(
|
||||
label: _updatesTotalNumbers(ref),
|
||||
child: const Icon(Icons.new_releases),
|
||||
),
|
||||
label: l10n.updates),
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(Icons.history),
|
||||
icon: const Icon(Icons.history_outlined),
|
||||
label: l10n.history),
|
||||
Stack(
|
||||
children: [
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(Icons.explore),
|
||||
icon: const Icon(Icons.explore_outlined),
|
||||
label: l10n.browse),
|
||||
Positioned(
|
||||
right: 14,
|
||||
top: 3,
|
||||
child: _extensionUpdateTotalNumbers(ref)),
|
||||
],
|
||||
),
|
||||
NavigationDestination(
|
||||
selectedIcon: Badge(
|
||||
label: _extensionUpdateTotalNumbers(ref),
|
||||
child: const Icon(Icons.explore)),
|
||||
icon: Badge(
|
||||
label: _extensionUpdateTotalNumbers(ref),
|
||||
child: const Icon(Icons.explore)),
|
||||
label: l10n.browse),
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(Icons.more_horiz),
|
||||
icon: const Icon(Icons.more_horiz_outlined),
|
||||
label: l10n.more),
|
||||
],
|
||||
onDestinationSelected: (newIndex) {
|
||||
final fn = switch (newIndex) {
|
||||
0 => route.go('/MangaLibrary'),
|
||||
1 => route.go('/AnimeLibrary'),
|
||||
2 => route.go('/updates'),
|
||||
3 => route.go('/history'),
|
||||
4 => route.go('/browse'),
|
||||
_ => route.go('/more'),
|
||||
};
|
||||
fn;
|
||||
final dest = [
|
||||
'/MangaLibrary',
|
||||
'/AnimeLibrary',
|
||||
'/NovelLibrary',
|
||||
'/updates',
|
||||
'/history',
|
||||
'/browse',
|
||||
'/more'
|
||||
];
|
||||
if (hideManga) {
|
||||
dest.removeWhere((d) => d == "/MangaLibrary");
|
||||
}
|
||||
if (hideAnime) {
|
||||
dest.removeWhere((d) => d == "/AnimeLibrary");
|
||||
}
|
||||
if (hideNovel) {
|
||||
dest.removeWhere((d) => d == "/NovelLibrary");
|
||||
}
|
||||
route.go(dest[newIndex >= dest.length
|
||||
? dest.length - 1
|
||||
: newIndex]);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
@ -348,25 +419,9 @@ Widget _extensionUpdateTotalNumbers(WidgetRef ref) {
|
|||
.where((element) =>
|
||||
compareVersions(element.version!, element.versionLast!) < 0)
|
||||
.toList();
|
||||
return entries.isEmpty
|
||||
? Container()
|
||||
: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: const Color.fromARGB(255, 176, 46, 37)),
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 5, vertical: 3),
|
||||
child: Text(
|
||||
entries.length.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Theme.of(context).textTheme.bodySmall!.color),
|
||||
),
|
||||
),
|
||||
);
|
||||
return entries.isEmpty ? Text("0") : Text("${entries.length}");
|
||||
}
|
||||
return Container();
|
||||
return Text("0");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -381,24 +436,8 @@ Widget _updatesTotalNumbers(WidgetRef ref) {
|
|||
}
|
||||
return !(element.chapter.value?.isRead ?? false);
|
||||
}).toList();
|
||||
return entries.isEmpty
|
||||
? Container()
|
||||
: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: const Color.fromARGB(255, 176, 46, 37)),
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 5, vertical: 3),
|
||||
child: Text(
|
||||
entries.length.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Theme.of(context).textTheme.bodySmall!.color),
|
||||
),
|
||||
),
|
||||
);
|
||||
return entries.isEmpty ? Text("0") : Text("${entries.length}");
|
||||
}
|
||||
return Container();
|
||||
return Text("0");
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,8 @@ Future<void> migration(Ref ref) async {
|
|||
.chapterIdIsNull()
|
||||
.or()
|
||||
.idIsNotNull()
|
||||
.isMangaIsNull()
|
||||
.findAllSync();
|
||||
final tracks =
|
||||
isar.tracks.filter().idIsNotNull().isMangaIsNull().findAllSync();
|
||||
final tracks = isar.tracks.filter().idIsNotNull().findAllSync();
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
//mangaId in chapter
|
||||
|
|
@ -40,14 +38,17 @@ Future<void> migration(Ref ref) async {
|
|||
//chapterId and isManga in History
|
||||
for (var history in histories) {
|
||||
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
|
||||
..chapterId = chapterId
|
||||
..isManga = isManga);
|
||||
..itemType = itemType);
|
||||
}
|
||||
// isManga in Track
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'migration.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$migrationHash() => r'a302c6da3c1545c952a28e76a6d0b7af3fde1e7a';
|
||||
String _$migrationHash() => r'403da626b6a797854dde7ae77b4ea452300c40e6';
|
||||
|
||||
/// See also [migration].
|
||||
@ProviderFor(migration)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import 'package:mangayomi/modules/manga/detail/widgets/tracker_search_widget.dar
|
|||
import 'package:mangayomi/modules/manga/detail/widgets/tracker_widget.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/providers/pure_black_dark_mode_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/modules/more/settings/track/widgets/track_listile.dart';
|
||||
import 'package:mangayomi/modules/widgets/custom_draggable_tabbar.dart';
|
||||
import 'package:mangayomi/modules/widgets/custom_extended_image_provider.dart';
|
||||
|
|
@ -59,7 +58,7 @@ class MangaDetailView extends ConsumerStatefulWidget {
|
|||
final Manga? manga;
|
||||
final bool sourceExist;
|
||||
final Function(bool) checkForUpdate;
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
|
||||
const MangaDetailView(
|
||||
{super.key,
|
||||
|
|
@ -70,7 +69,7 @@ class MangaDetailView extends ConsumerStatefulWidget {
|
|||
required this.sourceExist,
|
||||
required this.manga,
|
||||
required this.checkForUpdate,
|
||||
required this.isManga});
|
||||
required this.itemType});
|
||||
|
||||
@override
|
||||
ConsumerState<MangaDetailView> createState() => _MangaDetailViewState();
|
||||
|
|
@ -382,30 +381,35 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
return [
|
||||
PopupMenuItem<int>(
|
||||
value: 0,
|
||||
child: Text(widget.isManga
|
||||
child: Text(widget.itemType !=
|
||||
ItemType.anime
|
||||
? context.l10n.next_chapter
|
||||
: context.l10n.next_episode)),
|
||||
PopupMenuItem<int>(
|
||||
value: 1,
|
||||
child: Text(widget.isManga
|
||||
child: Text(widget.itemType !=
|
||||
ItemType.anime
|
||||
? context.l10n.next_5_chapters
|
||||
: context
|
||||
.l10n.next_5_episodes)),
|
||||
PopupMenuItem<int>(
|
||||
value: 2,
|
||||
child: Text(widget.isManga
|
||||
child: Text(widget.itemType !=
|
||||
ItemType.anime
|
||||
? context.l10n.next_10_chapters
|
||||
: context
|
||||
.l10n.next_10_episodes)),
|
||||
PopupMenuItem<int>(
|
||||
value: 3,
|
||||
child: Text(widget.isManga
|
||||
child: Text(widget.itemType !=
|
||||
ItemType.anime
|
||||
? context.l10n.next_25_chapters
|
||||
: context
|
||||
.l10n.next_25_episodes)),
|
||||
PopupMenuItem<int>(
|
||||
value: 4,
|
||||
child: Text(widget.isManga
|
||||
child: Text(widget.itemType !=
|
||||
ItemType.anime
|
||||
? context.l10n.unread
|
||||
: context.l10n.unwatched)),
|
||||
];
|
||||
|
|
@ -521,7 +525,12 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
if (value == 0) {
|
||||
context.push("/categories", extra: (
|
||||
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 == 2) {
|
||||
|
|
@ -593,7 +602,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
8),
|
||||
child: Text(
|
||||
widget.manga!
|
||||
.isManga!
|
||||
.itemType !=
|
||||
ItemType
|
||||
.anime
|
||||
? l10n.n_chapters(
|
||||
chapters
|
||||
.length)
|
||||
|
|
@ -622,7 +633,10 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
color: context
|
||||
.secondaryColor),
|
||||
label: Text(
|
||||
widget.manga!.isManga!
|
||||
widget.manga!
|
||||
.itemType !=
|
||||
ItemType
|
||||
.anime
|
||||
? l10n
|
||||
.add_chapters
|
||||
: l10n
|
||||
|
|
@ -644,8 +658,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
manga: manga);
|
||||
} else {
|
||||
await ref.watch(importArchivesFromFileProvider(
|
||||
isManga: manga
|
||||
.isManga!,
|
||||
itemType:
|
||||
manga
|
||||
.itemType,
|
||||
manga,
|
||||
init:
|
||||
false)
|
||||
|
|
@ -717,11 +732,6 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
isar.writeTxnSync(() {
|
||||
for (var chapter in chapters) {
|
||||
chapter.isBookmarked = !chapter.isBookmarked!;
|
||||
ref
|
||||
.read(changedItemsManagerProvider(
|
||||
managerId: 1)
|
||||
.notifier)
|
||||
.addUpdatedChapter(chapter, false, false);
|
||||
isar.chapters.putSync(
|
||||
chapter..manga.value = widget.manga);
|
||||
chapter.manga.saveSync();
|
||||
|
|
@ -762,11 +772,6 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
if (!chapter.isRead!) {
|
||||
chapter.lastPageRead = "1";
|
||||
}
|
||||
ref
|
||||
.read(changedItemsManagerProvider(
|
||||
managerId: 1)
|
||||
.notifier)
|
||||
.addUpdatedChapter(chapter, false, false);
|
||||
isar.chapters.putSync(
|
||||
chapter..manga.value = widget.manga);
|
||||
chapter.manga.saveSync();
|
||||
|
|
@ -812,12 +817,6 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
if (!chapters[i].isRead!) {
|
||||
chapters[i].isRead = true;
|
||||
chapters[i].lastPageRead = "1";
|
||||
ref
|
||||
.read(changedItemsManagerProvider(
|
||||
managerId: 1)
|
||||
.notifier)
|
||||
.addUpdatedChapter(
|
||||
chapters[i], false, false);
|
||||
isar.chapters.putSync(chapters[i]
|
||||
..manga.value = widget.manga);
|
||||
chapters[i].manga.saveSync();
|
||||
|
|
@ -996,7 +995,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
.update();
|
||||
}),
|
||||
ListTileChapterFilter(
|
||||
label: widget.isManga ? l10n.unread : l10n.unwatched,
|
||||
label: widget.itemType != ItemType.anime
|
||||
? l10n.unread
|
||||
: l10n.unwatched,
|
||||
type: ref.watch(chapterFilterUnreadStateProvider(
|
||||
mangaId: widget.manga!.id!)),
|
||||
onTap: () {
|
||||
|
|
@ -1193,8 +1194,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
),
|
||||
RadioListTile(
|
||||
dense: true,
|
||||
title: Text(
|
||||
widget.isManga ? l10n.chapter_number : l10n.episode_number),
|
||||
title: Text(widget.itemType != ItemType.anime
|
||||
? l10n.chapter_number
|
||||
: l10n.episode_number),
|
||||
value: "ej",
|
||||
groupValue: "e",
|
||||
selected: false,
|
||||
|
|
@ -1211,7 +1213,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
if (index == 0) {
|
||||
return l10n.by_scanlator;
|
||||
} 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) {
|
||||
return l10n.by_upload_date;
|
||||
}
|
||||
|
|
@ -1373,7 +1377,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Text(
|
||||
widget.manga!.isManga!
|
||||
widget.manga!.itemType != ItemType.anime
|
||||
? l10n.n_chapters(chapterLength)
|
||||
: l10n.n_episodes(chapterLength),
|
||||
style: const TextStyle(
|
||||
|
|
@ -1390,7 +1394,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
icon: Icon(Icons.add,
|
||||
color: context.secondaryColor),
|
||||
label: Text(
|
||||
widget.manga!.isManga!
|
||||
widget.manga!.itemType != ItemType.anime
|
||||
? l10n.add_chapters
|
||||
: l10n.add_episodes,
|
||||
style: TextStyle(
|
||||
|
|
@ -1404,7 +1408,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
} else {
|
||||
await ref.watch(
|
||||
importArchivesFromFileProvider(
|
||||
isManga: manga.isManga!,
|
||||
itemType: manga.itemType,
|
||||
manga,
|
||||
init: false)
|
||||
.future);
|
||||
|
|
@ -1652,7 +1656,8 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
final trackSearch =
|
||||
await trackersSearchraggableMenu(
|
||||
context,
|
||||
isManga: widget.manga!.isManga!,
|
||||
isManga: widget.manga!.itemType !=
|
||||
ItemType.anime,
|
||||
track: Track(
|
||||
status:
|
||||
TrackStatus.planToRead,
|
||||
|
|
@ -1975,14 +1980,16 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
mangaId: widget.manga!.id!,
|
||||
syncId: entries[index].syncId!,
|
||||
trackRes: trackRes.first,
|
||||
isManga: widget.manga!.isManga!)
|
||||
isManga:
|
||||
widget.manga!.itemType == ItemType.manga)
|
||||
: TrackListile(
|
||||
text: l10nLocalizations(context)!.add_tracker,
|
||||
onTap: () async {
|
||||
final trackSearch =
|
||||
await trackersSearchraggableMenu(
|
||||
context,
|
||||
isManga: widget.manga!.isManga!,
|
||||
isManga: widget.manga!.itemType !=
|
||||
ItemType.anime,
|
||||
track: Track(
|
||||
status: TrackStatus.planToRead,
|
||||
syncId: entries[index].syncId!,
|
||||
|
|
@ -1992,7 +1999,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
await ref
|
||||
.read(trackStateProvider(
|
||||
track: null,
|
||||
isManga: widget.manga!.isManga!)
|
||||
isManga:
|
||||
widget.manga!.itemType !=
|
||||
ItemType.anime)
|
||||
.notifier)
|
||||
.setTrackSearch(
|
||||
trackSearch,
|
||||
|
|
|
|||
|
|
@ -69,11 +69,13 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
.idIsNotNull()
|
||||
.and()
|
||||
.chapter((q) => q.manga(
|
||||
(q) => q.isMangaEqualTo(widget.manga.isManga!)))
|
||||
(q) => q.itemTypeEqualTo(widget.manga.itemType)))
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
String buttonLabel =
|
||||
widget.manga.isManga! ? l10n.read : l10n.watch;
|
||||
widget.manga.itemType != ItemType.anime
|
||||
? l10n.read
|
||||
: l10n.watch;
|
||||
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
|
||||
final incognitoMode =
|
||||
ref.watch(incognitoModeStateProvider);
|
||||
|
|
@ -224,7 +226,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.forMangaEqualTo(widget.manga.isManga)
|
||||
.forItemTypeEqualTo(widget.manga.itemType)
|
||||
.isNotEmptySync();
|
||||
if (checkCategoryList) {
|
||||
_openCategory(widget.manga);
|
||||
|
|
@ -262,7 +264,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
},
|
||||
sourceExist: widget.sourceExist,
|
||||
checkForUpdate: widget.checkForUpdate,
|
||||
isManga: widget.manga.isManga!,
|
||||
itemType: widget.manga.itemType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -286,7 +288,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.forMangaEqualTo(widget.manga.isManga)
|
||||
.forItemTypeEqualTo(widget.manga.itemType)
|
||||
.watch(fireImmediately: true),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
|
||||
|
|
@ -323,8 +325,14 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.push("/categories",
|
||||
extra: (true, widget.manga.isManga! ? 0 : 1));
|
||||
context.push("/categories", extra: (
|
||||
true,
|
||||
widget.manga.itemType == ItemType.manga
|
||||
? 0
|
||||
: widget.manga.itemType == ItemType.anime
|
||||
? 1
|
||||
: 2
|
||||
));
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(l10n.edit)),
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import 'package:mangayomi/models/download.dart';
|
|||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/modules/manga/download/providers/download_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'state_providers.g.dart';
|
||||
|
||||
|
|
@ -310,9 +309,6 @@ class ChapterSetIsBookmarkState extends _$ChapterSetIsBookmarkState {
|
|||
isar.writeTxnSync(() {
|
||||
for (var chapter in chapters) {
|
||||
chapter.isBookmarked = !chapter.isBookmarked!;
|
||||
ref
|
||||
.read(changedItemsManagerProvider(managerId: 1).notifier)
|
||||
.addUpdatedChapter(chapter, false, false);
|
||||
isar.chapters.putSync(chapter..manga.value = manga);
|
||||
chapter.manga.saveSync();
|
||||
}
|
||||
|
|
@ -332,9 +328,6 @@ class ChapterSetIsReadState extends _$ChapterSetIsReadState {
|
|||
isar.writeTxnSync(() {
|
||||
for (var chapter in chapters) {
|
||||
chapter.isRead = !chapter.isRead!;
|
||||
ref
|
||||
.read(changedItemsManagerProvider(managerId: 1).notifier)
|
||||
.addUpdatedChapter(chapter, false, false);
|
||||
isar.chapters.putSync(chapter..manga.value = manga);
|
||||
chapter.manga.saveSync();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -816,7 +816,7 @@ class _ChapterFilterResultStateProviderElement
|
|||
}
|
||||
|
||||
String _$chapterSetIsBookmarkStateHash() =>
|
||||
r'48d4f203ba51616e9d1142e0dd482d3ae065a4f4';
|
||||
r'113131bb13e50566390ee3e34aa2f08820a8870c';
|
||||
|
||||
abstract class _$ChapterSetIsBookmarkState
|
||||
extends BuildlessAutoDisposeNotifier<void> {
|
||||
|
|
@ -963,7 +963,7 @@ class _ChapterSetIsBookmarkStateProviderElement
|
|||
}
|
||||
|
||||
String _$chapterSetIsReadStateHash() =>
|
||||
r'1e219dd68898fc30b6cb64d294377776516775d4';
|
||||
r'c319f81ec30565ad81a28cb0a8ce7fddcb47cd77';
|
||||
|
||||
abstract class _$ChapterSetIsReadState
|
||||
extends BuildlessAutoDisposeNotifier<void> {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import 'package:mangayomi/main.dart';
|
|||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/update.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/services/get_detail.dart';
|
||||
import 'package:mangayomi/utils/utils.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
|
@ -49,7 +48,7 @@ Future<dynamic> updateMangaDetail(Ref ref,
|
|||
..link = getManga.link?.trim().trimLeft().trimRight() ?? manga.link
|
||||
..source = manga.source
|
||||
..lang = manga.lang
|
||||
..isManga = source.isManga
|
||||
..itemType = source.itemType
|
||||
..lastUpdate = DateTime.now().millisecondsSinceEpoch;
|
||||
final checkManga = isar.mangas.getSync(mangaId);
|
||||
if (checkManga!.chapters.isNotEmpty && isInit) {
|
||||
|
|
@ -80,9 +79,6 @@ Future<dynamic> updateMangaDetail(Ref ref,
|
|||
}
|
||||
if (chapters.isNotEmpty) {
|
||||
for (var chap in chapters.reversed.toList()) {
|
||||
ref
|
||||
.read(changedItemsManagerProvider(managerId: 1).notifier)
|
||||
.addUpdatedChapter(chap, false, false);
|
||||
isar.chapters.putSync(chap);
|
||||
chap.manga.saveSync();
|
||||
if (manga.chapters.isNotEmpty) {
|
||||
|
|
@ -105,9 +101,6 @@ Future<dynamic> updateMangaDetail(Ref ref,
|
|||
oldChap.name = newChap.name;
|
||||
oldChap.url = newChap.url;
|
||||
oldChap.scanlator = newChap.scanlator;
|
||||
ref
|
||||
.read(changedItemsManagerProvider(managerId: 1).notifier)
|
||||
.addUpdatedChapter(oldChap, false, false);
|
||||
isar.chapters.putSync(oldChap);
|
||||
oldChap.manga.saveSync();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'update_manga_detail_providers.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$updateMangaDetailHash() => r'82c52aa8760fb455e6558be925d05f5f0703af98';
|
||||
String _$updateMangaDetailHash() => r'a86fe8fea46e411203182287c970cd80cc9a1a0c';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/utils/date.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
|
|
@ -90,13 +91,16 @@ class ChapterListTileWidget extends ConsumerWidget {
|
|||
children: [
|
||||
const Text(' • '),
|
||||
Text(
|
||||
!chapter.manga.value!.isManga!
|
||||
chapter.manga.value!.itemType == ItemType.anime
|
||||
? l10n.episode_progress(Duration(
|
||||
milliseconds:
|
||||
int.parse(chapter.lastPageRead!))
|
||||
.toString()
|
||||
.substringBefore("."))
|
||||
: l10n.page(chapter.lastPageRead!),
|
||||
: l10n.page(chapter.manga.value!.itemType ==
|
||||
ItemType.manga
|
||||
? chapter.lastPageRead!
|
||||
: "${((double.tryParse(chapter.lastPageRead!) ?? 0) * 100).toStringAsFixed(0)} %"),
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: context.isLight
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/page.dart';
|
||||
import 'package:mangayomi/services/background_downloader/background_downloader.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
|
@ -46,10 +47,16 @@ Future<List<PageUrl>> downloadChapter(
|
|||
: "";
|
||||
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 = [
|
||||
"downloads",
|
||||
isManga ? "Manga" : "Anime",
|
||||
itemTypePath,
|
||||
"${manga.source} (${manga.lang!.toUpperCase()})",
|
||||
manga.name!.replaceForbiddenCharacters('_'),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'download_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$downloadChapterHash() => r'19e094ae3e51346012c43320b59ae99107fedf57';
|
||||
String _$downloadChapterHash() => r'de8e2d5b952071bc0d014fc3aa5c9b0714fbcee0';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mangayomi/eval/model/m_manga.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/source.dart';
|
||||
import 'package:mangayomi/modules/library/providers/library_state_provider.dart';
|
||||
|
|
@ -520,14 +521,14 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
|
|||
return buildProgressIndicator();
|
||||
}
|
||||
return MangaHomeImageCardListTile(
|
||||
isManga: source.isManga ?? true,
|
||||
itemType: source.itemType,
|
||||
manga: _mangaList[index],
|
||||
source: source);
|
||||
})
|
||||
: Consumer(builder: (context, ref, child) {
|
||||
final gridSize = ref.watch(
|
||||
libraryGridSizeStateProvider(
|
||||
isManga: source.isManga!));
|
||||
itemType: source.itemType));
|
||||
|
||||
return GridViewWidget(
|
||||
gridSize: gridSize,
|
||||
|
|
@ -540,7 +541,7 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
|
|||
return buildProgressIndicator();
|
||||
}
|
||||
return MangaHomeImageCard(
|
||||
isManga: source.isManga ?? true,
|
||||
itemType: source.itemType,
|
||||
manga: _mangaList[index],
|
||||
source: source,
|
||||
isComfortableGrid: isComfortableGrid,
|
||||
|
|
@ -639,14 +640,14 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
|
|||
|
||||
class MangaHomeImageCard extends ConsumerStatefulWidget {
|
||||
final MManga manga;
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
final Source source;
|
||||
final bool isComfortableGrid;
|
||||
const MangaHomeImageCard(
|
||||
{super.key,
|
||||
required this.manga,
|
||||
required this.source,
|
||||
required this.isManga,
|
||||
required this.itemType,
|
||||
required this.isComfortableGrid});
|
||||
|
||||
@override
|
||||
|
|
@ -662,7 +663,7 @@ class _MangaHomeImageCardState extends ConsumerState<MangaHomeImageCard>
|
|||
return MangaImageCardWidget(
|
||||
getMangaDetail: widget.manga,
|
||||
source: widget.source,
|
||||
isManga: widget.isManga,
|
||||
itemType: widget.itemType,
|
||||
isComfortableGrid: widget.isComfortableGrid);
|
||||
}
|
||||
|
||||
|
|
@ -672,13 +673,13 @@ class _MangaHomeImageCardState extends ConsumerState<MangaHomeImageCard>
|
|||
|
||||
class MangaHomeImageCardListTile extends ConsumerStatefulWidget {
|
||||
final MManga manga;
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
final Source source;
|
||||
const MangaHomeImageCardListTile(
|
||||
{super.key,
|
||||
required this.manga,
|
||||
required this.source,
|
||||
required this.isManga});
|
||||
required this.itemType});
|
||||
|
||||
@override
|
||||
ConsumerState<MangaHomeImageCardListTile> createState() =>
|
||||
|
|
@ -695,7 +696,7 @@ class _MangaHomeImageCardListTileState
|
|||
return MangaImageCardListTileWidget(
|
||||
getMangaDetail: widget.manga,
|
||||
source: widget.source,
|
||||
isManga: widget.isManga);
|
||||
itemType: widget.itemType);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'package:go_router/go_router.dart';
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
|
||||
Future<void> pushMangaReaderView({
|
||||
|
|
@ -23,19 +24,31 @@ Future<void> pushMangaReaderView({
|
|||
.findAllSync()
|
||||
.isNotEmpty;
|
||||
if (sourceExist || chapter.manga.value!.isLocalArchive!) {
|
||||
if (chapter.manga.value!.isManga!) {
|
||||
await context.push('/mangareaderview', extra: chapter);
|
||||
} else {
|
||||
await context.push('/animePlayerView', extra: chapter);
|
||||
switch (chapter.manga.value!.itemType) {
|
||||
case ItemType.manga:
|
||||
await context.push('/mangaReaderView', 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(
|
||||
{required BuildContext context, required Chapter chapter}) {
|
||||
if (chapter.manga.value!.isManga!) {
|
||||
context.pushReplacement('/mangareaderview', extra: chapter);
|
||||
} else {
|
||||
context.pushReplacement('/animePlayerView', extra: chapter);
|
||||
}
|
||||
switch (chapter.manga.value!.itemType) {
|
||||
case ItemType.manga:
|
||||
context.pushReplacement('/mangaReaderView', extra: chapter);
|
||||
break;
|
||||
case ItemType.anime:
|
||||
context.pushReplacement('/animePlayerView', extra: chapter);
|
||||
break;
|
||||
case ItemType.novel:
|
||||
context.pushReplacement('/novelReaderView', extra: chapter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@ 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/providers/incognito_mode_state_provider.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 'reader_controller_provider.g.dart';
|
||||
|
|
@ -171,7 +169,7 @@ class ReaderController extends _$ReaderController {
|
|||
history = History(
|
||||
mangaId: getManga().id,
|
||||
date: DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
isManga: getManga().isManga,
|
||||
itemType: getManga().itemType,
|
||||
chapterId: chapter.id)
|
||||
..chapter.value = chapter;
|
||||
} else {
|
||||
|
|
@ -189,22 +187,12 @@ class ReaderController extends _$ReaderController {
|
|||
});
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
|
@ -342,9 +330,6 @@ class ReaderController extends _$ReaderController {
|
|||
getIsarSetting()..chapterPageIndexList = chapterPageIndexs);
|
||||
chap.isRead = isRead;
|
||||
chap.lastPageRead = isRead ? '1' : (newIndex + 1).toString();
|
||||
ref
|
||||
.read(changedItemsManagerProvider(managerId: 1).notifier)
|
||||
.addUpdatedChapter(chap, false, false);
|
||||
isar.chapters.putSync(chap);
|
||||
});
|
||||
if (isRead) {
|
||||
|
|
@ -379,7 +364,7 @@ extension ChapterExtensions on Chapter {
|
|||
final tracks = isar.tracks
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.isMangaEqualTo(manga.isManga)
|
||||
.isMangaEqualTo(manga.itemType == ItemType.manga)
|
||||
.mangaIdEqualTo(manga.id!)
|
||||
.findAllSync();
|
||||
|
||||
|
|
@ -398,15 +383,17 @@ extension ChapterExtensions on Chapter {
|
|||
track.status = TrackStatus.completed;
|
||||
track.finishedReadingDate = DateTime.now().millisecondsSinceEpoch;
|
||||
} else {
|
||||
track.status =
|
||||
manga.isManga! ? TrackStatus.reading : TrackStatus.watching;
|
||||
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.isManga)
|
||||
.read(trackStateProvider(
|
||||
track: track, isManga: manga.itemType == ItemType.manga)
|
||||
.notifier)
|
||||
.updateManga();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ class _CurrentIndexProviderElement
|
|||
Chapter get chapter => (origin as CurrentIndexProvider).chapter;
|
||||
}
|
||||
|
||||
String _$readerControllerHash() => r'cc4f5fbe4192def4d19d9150340d305ba0ecf463';
|
||||
String _$readerControllerHash() => r'471617bf6fa730d837c8e0d9504bde17cfb635a8';
|
||||
|
||||
abstract class _$ReaderController extends BuildlessAutoDisposeNotifier<void> {
|
||||
late final Chapter chapter;
|
||||
|
|
|
|||
|
|
@ -143,7 +143,6 @@ class _MangaChapterPageGalleryState
|
|||
@override
|
||||
void dispose() {
|
||||
_readerController.setMangaHistoryUpdate();
|
||||
_readerController.checkAndSyncProgress();
|
||||
_readerController.setPageIndex(
|
||||
_geCurrentIndex(_uChapDataPreload[_currentIndex!].index!), true);
|
||||
_rebuildDetail.close();
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import 'package:mangayomi/main.dart';
|
|||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/utils/date.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
import 'package:super_sliver_list/super_sliver_list.dart';
|
||||
|
|
@ -138,7 +137,7 @@ class _ChapterListTileState extends State<ChapterListTile> {
|
|||
if (!chapter.isRead!)
|
||||
if (chapter.lastPageRead!.isNotEmpty &&
|
||||
chapter.lastPageRead != "1")
|
||||
if (chapter.scanlator!.isNotEmpty)
|
||||
if (chapter.scanlator != null && chapter.scanlator!.isNotEmpty)
|
||||
Row(
|
||||
children: [
|
||||
const Text(' • '),
|
||||
|
|
@ -160,8 +159,6 @@ class _ChapterListTileState extends State<ChapterListTile> {
|
|||
isBookmarked = !isBookmarked;
|
||||
});
|
||||
isar.writeTxnSync(() => {
|
||||
addUpdatedChapterIndependentProvider.call(
|
||||
chapter, false, false),
|
||||
isar.chapters.putSync(chapter..isBookmarked = isBookmarked),
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -385,7 +385,8 @@ List<String> _getList(BuildContext context) {
|
|||
l10n.tracking,
|
||||
l10n.history,
|
||||
l10n.settings,
|
||||
l10n.extensions
|
||||
l10n.extensions,
|
||||
l10n.updates
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import 'package:mangayomi/models/settings.dart';
|
|||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/models/track.dart';
|
||||
import 'package:mangayomi/models/track_preference.dart';
|
||||
import 'package:mangayomi/models/update.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
|
@ -28,7 +29,7 @@ void doBackUp(Ref ref,
|
|||
required String path,
|
||||
required BuildContext? context}) {
|
||||
Map<String, dynamic> datas = {};
|
||||
datas.addAll({"version": "1"});
|
||||
datas.addAll({"version": "2"});
|
||||
if (list.contains(0)) {
|
||||
final res = isar.mangas
|
||||
.filter()
|
||||
|
|
@ -116,6 +117,15 @@ void doBackUp(Ref ref,
|
|||
.toList();
|
||||
datas.addAll({"extensions_preferences": resSourePref});
|
||||
}
|
||||
if (list.contains(7)) {
|
||||
final res = isar.updates
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.findAllSync()
|
||||
.map((e) => e.toJson())
|
||||
.toList();
|
||||
datas.addAll({"updates": res});
|
||||
}
|
||||
final regExp = RegExp(r'[^a-zA-Z0-9 .()\-\s]');
|
||||
final name =
|
||||
'mangayomi_${DateTime.now().toString().replaceAll(regExp, '_').replaceAll(' ', '_')}';
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'backup.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$doBackUpHash() => r'1082dfee2a9c9e5655a04d027fde40c29d634a6d';
|
||||
String _$doBackUpHash() => r'98c1eb56bd4937033c82accf71beb84c85a2acc6';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -32,143 +32,274 @@ void doRestore(Ref ref, {required String path, required BuildContext context}) {
|
|||
final backup = jsonDecode(utf8.decode(archive.files.first.content))
|
||||
as Map<String, dynamic>;
|
||||
if (backup['version'] == "1") {
|
||||
try {
|
||||
final manga =
|
||||
(backup["manga"] as List?)?.map((e) => Manga.fromJson(e)).toList();
|
||||
final chapters = (backup["chapters"] as List?)
|
||||
?.map((e) => Chapter.fromJson(e))
|
||||
.toList();
|
||||
final categories = (backup["categories"] as List?)
|
||||
?.map((e) => Category.fromJson(e))
|
||||
.toList();
|
||||
final track =
|
||||
(backup["tracks"] as List?)?.map((e) => Track.fromJson(e)).toList();
|
||||
final trackPreferences = (backup["trackPreferences"] as List?)
|
||||
?.map((e) => TrackPreference.fromJson(e))
|
||||
.toList();
|
||||
final history = (backup["history"] as List?)
|
||||
?.map((e) => History.fromJson(e))
|
||||
.toList();
|
||||
final downloads = (backup["downloads"] as List?)
|
||||
?.map((e) => Download.fromJson(e))
|
||||
.toList();
|
||||
final settings = (backup["settings"] as List?)
|
||||
?.map((e) => Settings.fromJson(e))
|
||||
.toList();
|
||||
final extensions = (backup["extensions"] as List?)
|
||||
?.map((e) => Source.fromJson(e))
|
||||
.toList();
|
||||
final extensionsPref = (backup["extensions_preferences"] as List?)
|
||||
?.map((e) => SourcePreference.fromJson(e))
|
||||
.toList();
|
||||
final updates =
|
||||
(backup["updates"] as List?)?.map((e) => Update.fromJson(e)).toList();
|
||||
restoreV1(ref, backup);
|
||||
} else if (backup['version'] == "2") {
|
||||
restoreV2(ref, backup);
|
||||
}
|
||||
BotToast.showNotification(
|
||||
animationDuration: const Duration(milliseconds: 200),
|
||||
animationReverseDuration: const Duration(milliseconds: 200),
|
||||
duration: const Duration(seconds: 5),
|
||||
backButtonBehavior: BackButtonBehavior.none,
|
||||
leading: (_) => Image.asset('assets/app_icons/icon-red.png', height: 40),
|
||||
title: (_) => const Text(
|
||||
"Backup restored!",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
enableSlideOff: true,
|
||||
onlyOne: true,
|
||||
crossPage: true);
|
||||
}
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
isar.mangas.clearSync();
|
||||
if (manga != null) {
|
||||
isar.mangas.putAllSync(manga);
|
||||
if (chapters != null) {
|
||||
isar.chapters.clearSync();
|
||||
for (var chapter in chapters) {
|
||||
final manga = isar.mangas.getSync(chapter.mangaId!);
|
||||
if (manga != null) {
|
||||
isar.chapters.putSync(chapter..manga.value = manga);
|
||||
chapter.manga.saveSync();
|
||||
}
|
||||
@riverpod
|
||||
void restoreV1(Ref ref, Map<String, dynamic> backup) {
|
||||
try {
|
||||
final manga =
|
||||
(backup["manga"] as List?)?.map((e) => Manga.fromJsonV1(e)).toList();
|
||||
final chapters =
|
||||
(backup["chapters"] as List?)?.map((e) => Chapter.fromJson(e)).toList();
|
||||
final categories = (backup["categories"] as List?)
|
||||
?.map((e) => Category.fromJsonV1(e))
|
||||
.toList();
|
||||
final track =
|
||||
(backup["tracks"] as List?)?.map((e) => Track.fromJson(e)).toList();
|
||||
final trackPreferences = (backup["trackPreferences"] as List?)
|
||||
?.map((e) => TrackPreference.fromJson(e))
|
||||
.toList();
|
||||
final history = (backup["history"] as List?)
|
||||
?.map((e) => History.fromJsonV1(e))
|
||||
.toList();
|
||||
final downloads = (backup["downloads"] as List?)
|
||||
?.map((e) => Download.fromJson(e))
|
||||
.toList();
|
||||
final settings = (backup["settings"] as List?)
|
||||
?.map((e) => Settings.fromJson(e))
|
||||
.toList();
|
||||
final extensions = (backup["extensions"] as List?)
|
||||
?.map((e) => Source.fromJsonV1(e))
|
||||
.toList();
|
||||
final extensionsPref = (backup["extensions_preferences"] as List?)
|
||||
?.map((e) => SourcePreference.fromJson(e))
|
||||
.toList();
|
||||
final updates =
|
||||
(backup["updates"] as List?)?.map((e) => Update.fromJson(e)).toList();
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
isar.mangas.clearSync();
|
||||
if (manga != null) {
|
||||
isar.mangas.putAllSync(manga);
|
||||
if (chapters != null) {
|
||||
isar.chapters.clearSync();
|
||||
for (var chapter in chapters) {
|
||||
final manga = isar.mangas.getSync(chapter.mangaId!);
|
||||
if (manga != null) {
|
||||
isar.chapters.putSync(chapter..manga.value = manga);
|
||||
chapter.manga.saveSync();
|
||||
}
|
||||
}
|
||||
|
||||
isar.downloads.clearSync();
|
||||
if (downloads != null) {
|
||||
for (var download in downloads) {
|
||||
final chapter = isar.chapters.getSync(download.chapterId!);
|
||||
if (chapter != null) {
|
||||
isar.downloads.putSync(download..chapter.value = chapter);
|
||||
download.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.historys.clearSync();
|
||||
if (history != null) {
|
||||
for (var element in history) {
|
||||
final chapter = isar.chapters.getSync(element.chapterId!);
|
||||
if (chapter != null) {
|
||||
isar.historys.putSync(element..chapter.value = chapter);
|
||||
element.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.updates.clearSync();
|
||||
if (updates != null) {
|
||||
final tempChapters =
|
||||
isar.chapters.filter().idIsNotNull().findAllSync().toList();
|
||||
for (var update in updates) {
|
||||
final matchingChapter = tempChapters
|
||||
.where((chapter) =>
|
||||
chapter.mangaId == update.mangaId &&
|
||||
chapter.name == update.chapterName)
|
||||
.firstOrNull;
|
||||
if (matchingChapter != null) {
|
||||
isar.updates.putSync(update..chapter.value = matchingChapter);
|
||||
update.chapter.saveSync();
|
||||
}
|
||||
isar.downloads.clearSync();
|
||||
if (downloads != null) {
|
||||
for (var download in downloads) {
|
||||
final chapter = isar.chapters.getSync(download.chapterId!);
|
||||
if (chapter != null) {
|
||||
isar.downloads.putSync(download..chapter.value = chapter);
|
||||
download.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.categorys.clearSync();
|
||||
if (categories != null) {
|
||||
isar.categorys.putAllSync(categories);
|
||||
isar.historys.clearSync();
|
||||
if (history != null) {
|
||||
for (var element in history) {
|
||||
final chapter = isar.chapters.getSync(element.chapterId!);
|
||||
if (chapter != null) {
|
||||
isar.historys.putSync(element..chapter.value = chapter);
|
||||
element.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.updates.clearSync();
|
||||
if (updates != null) {
|
||||
final tempChapters =
|
||||
isar.chapters.filter().idIsNotNull().findAllSync().toList();
|
||||
for (var update in updates) {
|
||||
final matchingChapter = tempChapters
|
||||
.where((chapter) =>
|
||||
chapter.mangaId == update.mangaId &&
|
||||
chapter.name == update.chapterName)
|
||||
.firstOrNull;
|
||||
if (matchingChapter != null) {
|
||||
isar.updates.putSync(update..chapter.value = matchingChapter);
|
||||
update.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.tracks.clearSync();
|
||||
if (track != null) {
|
||||
isar.tracks.putAllSync(track);
|
||||
isar.categorys.clearSync();
|
||||
if (categories != null) {
|
||||
isar.categorys.putAllSync(categories);
|
||||
}
|
||||
}
|
||||
|
||||
isar.trackPreferences.clearSync();
|
||||
if (trackPreferences != null) {
|
||||
isar.trackPreferences.putAllSync(trackPreferences);
|
||||
}
|
||||
isar.tracks.clearSync();
|
||||
if (track != null) {
|
||||
isar.tracks.putAllSync(track);
|
||||
}
|
||||
|
||||
isar.sources.clearSync();
|
||||
if (extensions != null) {
|
||||
isar.sources.putAllSync(extensions);
|
||||
}
|
||||
isar.trackPreferences.clearSync();
|
||||
if (trackPreferences != null) {
|
||||
isar.trackPreferences.putAllSync(trackPreferences);
|
||||
}
|
||||
|
||||
isar.sourcePreferences.clearSync();
|
||||
if (extensionsPref != null) {
|
||||
isar.sourcePreferences.putAllSync(extensionsPref);
|
||||
}
|
||||
isar.settings.clearSync();
|
||||
if (settings != null) {
|
||||
isar.settings.putAllSync(settings);
|
||||
}
|
||||
ref.invalidate(themeModeStateProvider);
|
||||
ref.invalidate(blendLevelStateProvider);
|
||||
ref.invalidate(flexSchemeColorStateProvider);
|
||||
ref.invalidate(pureBlackDarkModeStateProvider);
|
||||
ref.invalidate(l10nLocaleStateProvider);
|
||||
});
|
||||
} catch (e) {
|
||||
botToast(e.toString());
|
||||
}
|
||||
BotToast.showNotification(
|
||||
animationDuration: const Duration(milliseconds: 200),
|
||||
animationReverseDuration: const Duration(milliseconds: 200),
|
||||
duration: const Duration(seconds: 5),
|
||||
backButtonBehavior: BackButtonBehavior.none,
|
||||
leading: (_) =>
|
||||
Image.asset('assets/app_icons/icon-red.png', height: 40),
|
||||
title: (_) => const Text(
|
||||
"Backup restored!",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
enableSlideOff: true,
|
||||
onlyOne: true,
|
||||
crossPage: true);
|
||||
isar.sources.clearSync();
|
||||
if (extensions != null) {
|
||||
isar.sources.putAllSync(extensions);
|
||||
}
|
||||
|
||||
isar.sourcePreferences.clearSync();
|
||||
if (extensionsPref != null) {
|
||||
isar.sourcePreferences.putAllSync(extensionsPref);
|
||||
}
|
||||
isar.settings.clearSync();
|
||||
if (settings != null) {
|
||||
isar.settings.putAllSync(settings);
|
||||
}
|
||||
ref.invalidate(themeModeStateProvider);
|
||||
ref.invalidate(blendLevelStateProvider);
|
||||
ref.invalidate(flexSchemeColorStateProvider);
|
||||
ref.invalidate(pureBlackDarkModeStateProvider);
|
||||
ref.invalidate(l10nLocaleStateProvider);
|
||||
});
|
||||
} catch (e) {
|
||||
botToast(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
void restoreV2(Ref ref, Map<String, dynamic> backup) {
|
||||
try {
|
||||
final manga =
|
||||
(backup["manga"] as List?)?.map((e) => Manga.fromJson(e)).toList();
|
||||
final chapters =
|
||||
(backup["chapters"] as List?)?.map((e) => Chapter.fromJson(e)).toList();
|
||||
final categories = (backup["categories"] as List?)
|
||||
?.map((e) => Category.fromJson(e))
|
||||
.toList();
|
||||
final track =
|
||||
(backup["tracks"] as List?)?.map((e) => Track.fromJson(e)).toList();
|
||||
final trackPreferences = (backup["trackPreferences"] as List?)
|
||||
?.map((e) => TrackPreference.fromJson(e))
|
||||
.toList();
|
||||
final history =
|
||||
(backup["history"] as List?)?.map((e) => History.fromJson(e)).toList();
|
||||
final downloads = (backup["downloads"] as List?)
|
||||
?.map((e) => Download.fromJson(e))
|
||||
.toList();
|
||||
final settings = (backup["settings"] as List?)
|
||||
?.map((e) => Settings.fromJson(e))
|
||||
.toList();
|
||||
final extensions = (backup["extensions"] as List?)
|
||||
?.map((e) => Source.fromJson(e))
|
||||
.toList();
|
||||
final extensionsPref = (backup["extensions_preferences"] as List?)
|
||||
?.map((e) => SourcePreference.fromJson(e))
|
||||
.toList();
|
||||
final updates =
|
||||
(backup["updates"] as List?)?.map((e) => Update.fromJson(e)).toList();
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
isar.mangas.clearSync();
|
||||
if (manga != null) {
|
||||
isar.mangas.putAllSync(manga);
|
||||
if (chapters != null) {
|
||||
isar.chapters.clearSync();
|
||||
for (var chapter in chapters) {
|
||||
final manga = isar.mangas.getSync(chapter.mangaId!);
|
||||
if (manga != null) {
|
||||
isar.chapters.putSync(chapter..manga.value = manga);
|
||||
chapter.manga.saveSync();
|
||||
}
|
||||
}
|
||||
|
||||
isar.downloads.clearSync();
|
||||
if (downloads != null) {
|
||||
for (var download in downloads) {
|
||||
final chapter = isar.chapters.getSync(download.chapterId!);
|
||||
if (chapter != null) {
|
||||
isar.downloads.putSync(download..chapter.value = chapter);
|
||||
download.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.historys.clearSync();
|
||||
if (history != null) {
|
||||
for (var element in history) {
|
||||
final chapter = isar.chapters.getSync(element.chapterId!);
|
||||
if (chapter != null) {
|
||||
isar.historys.putSync(element..chapter.value = chapter);
|
||||
element.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.updates.clearSync();
|
||||
if (updates != null) {
|
||||
final tempChapters =
|
||||
isar.chapters.filter().idIsNotNull().findAllSync().toList();
|
||||
for (var update in updates) {
|
||||
final matchingChapter = tempChapters
|
||||
.where((chapter) =>
|
||||
chapter.mangaId == update.mangaId &&
|
||||
chapter.name == update.chapterName)
|
||||
.firstOrNull;
|
||||
if (matchingChapter != null) {
|
||||
isar.updates.putSync(update..chapter.value = matchingChapter);
|
||||
update.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.categorys.clearSync();
|
||||
if (categories != null) {
|
||||
isar.categorys.putAllSync(categories);
|
||||
}
|
||||
}
|
||||
|
||||
isar.tracks.clearSync();
|
||||
if (track != null) {
|
||||
isar.tracks.putAllSync(track);
|
||||
}
|
||||
|
||||
isar.trackPreferences.clearSync();
|
||||
if (trackPreferences != null) {
|
||||
isar.trackPreferences.putAllSync(trackPreferences);
|
||||
}
|
||||
|
||||
isar.sources.clearSync();
|
||||
if (extensions != null) {
|
||||
isar.sources.putAllSync(extensions);
|
||||
}
|
||||
|
||||
isar.sourcePreferences.clearSync();
|
||||
if (extensionsPref != null) {
|
||||
isar.sourcePreferences.putAllSync(extensionsPref);
|
||||
}
|
||||
isar.settings.clearSync();
|
||||
if (settings != null) {
|
||||
isar.settings.putAllSync(settings);
|
||||
}
|
||||
ref.invalidate(themeModeStateProvider);
|
||||
ref.invalidate(blendLevelStateProvider);
|
||||
ref.invalidate(flexSchemeColorStateProvider);
|
||||
ref.invalidate(pureBlackDarkModeStateProvider);
|
||||
ref.invalidate(l10nLocaleStateProvider);
|
||||
});
|
||||
} catch (e) {
|
||||
botToast(e.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'restore.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$doRestoreHash() => r'15a02b8de4cc4c7f5185a9f645b734a75f5950ca';
|
||||
String _$doRestoreHash() => r'508725e75a03ac5f561c2cf8bf4943052d605d5b';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -172,5 +172,263 @@ class _DoRestoreProviderElement extends AutoDisposeProviderElement<void>
|
|||
@override
|
||||
BuildContext get context => (origin as DoRestoreProvider).context;
|
||||
}
|
||||
|
||||
String _$restoreV1Hash() => r'4dca1ac4cec79fdc78bec4d71367e77caf696f17';
|
||||
|
||||
/// See also [restoreV1].
|
||||
@ProviderFor(restoreV1)
|
||||
const restoreV1Provider = RestoreV1Family();
|
||||
|
||||
/// See also [restoreV1].
|
||||
class RestoreV1Family extends Family<void> {
|
||||
/// See also [restoreV1].
|
||||
const RestoreV1Family();
|
||||
|
||||
/// See also [restoreV1].
|
||||
RestoreV1Provider call(
|
||||
Map<String, dynamic> backup,
|
||||
) {
|
||||
return RestoreV1Provider(
|
||||
backup,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
RestoreV1Provider getProviderOverride(
|
||||
covariant RestoreV1Provider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.backup,
|
||||
);
|
||||
}
|
||||
|
||||
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'restoreV1Provider';
|
||||
}
|
||||
|
||||
/// See also [restoreV1].
|
||||
class RestoreV1Provider extends AutoDisposeProvider<void> {
|
||||
/// See also [restoreV1].
|
||||
RestoreV1Provider(
|
||||
Map<String, dynamic> backup,
|
||||
) : this._internal(
|
||||
(ref) => restoreV1(
|
||||
ref as RestoreV1Ref,
|
||||
backup,
|
||||
),
|
||||
from: restoreV1Provider,
|
||||
name: r'restoreV1Provider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$restoreV1Hash,
|
||||
dependencies: RestoreV1Family._dependencies,
|
||||
allTransitiveDependencies: RestoreV1Family._allTransitiveDependencies,
|
||||
backup: backup,
|
||||
);
|
||||
|
||||
RestoreV1Provider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.backup,
|
||||
}) : super.internal();
|
||||
|
||||
final Map<String, dynamic> backup;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
void Function(RestoreV1Ref provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: RestoreV1Provider._internal(
|
||||
(ref) => create(ref as RestoreV1Ref),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
backup: backup,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeProviderElement<void> createElement() {
|
||||
return _RestoreV1ProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is RestoreV1Provider && other.backup == backup;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, backup.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin RestoreV1Ref on AutoDisposeProviderRef<void> {
|
||||
/// The parameter `backup` of this provider.
|
||||
Map<String, dynamic> get backup;
|
||||
}
|
||||
|
||||
class _RestoreV1ProviderElement extends AutoDisposeProviderElement<void>
|
||||
with RestoreV1Ref {
|
||||
_RestoreV1ProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> get backup => (origin as RestoreV1Provider).backup;
|
||||
}
|
||||
|
||||
String _$restoreV2Hash() => r'fbdd1978f8be7512277620e351b9a0eee1827bfc';
|
||||
|
||||
/// See also [restoreV2].
|
||||
@ProviderFor(restoreV2)
|
||||
const restoreV2Provider = RestoreV2Family();
|
||||
|
||||
/// See also [restoreV2].
|
||||
class RestoreV2Family extends Family<void> {
|
||||
/// See also [restoreV2].
|
||||
const RestoreV2Family();
|
||||
|
||||
/// See also [restoreV2].
|
||||
RestoreV2Provider call(
|
||||
Map<String, dynamic> backup,
|
||||
) {
|
||||
return RestoreV2Provider(
|
||||
backup,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
RestoreV2Provider getProviderOverride(
|
||||
covariant RestoreV2Provider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.backup,
|
||||
);
|
||||
}
|
||||
|
||||
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'restoreV2Provider';
|
||||
}
|
||||
|
||||
/// See also [restoreV2].
|
||||
class RestoreV2Provider extends AutoDisposeProvider<void> {
|
||||
/// See also [restoreV2].
|
||||
RestoreV2Provider(
|
||||
Map<String, dynamic> backup,
|
||||
) : this._internal(
|
||||
(ref) => restoreV2(
|
||||
ref as RestoreV2Ref,
|
||||
backup,
|
||||
),
|
||||
from: restoreV2Provider,
|
||||
name: r'restoreV2Provider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$restoreV2Hash,
|
||||
dependencies: RestoreV2Family._dependencies,
|
||||
allTransitiveDependencies: RestoreV2Family._allTransitiveDependencies,
|
||||
backup: backup,
|
||||
);
|
||||
|
||||
RestoreV2Provider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.backup,
|
||||
}) : super.internal();
|
||||
|
||||
final Map<String, dynamic> backup;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
void Function(RestoreV2Ref provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: RestoreV2Provider._internal(
|
||||
(ref) => create(ref as RestoreV2Ref),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
backup: backup,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeProviderElement<void> createElement() {
|
||||
return _RestoreV2ProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is RestoreV2Provider && other.backup == backup;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, backup.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin RestoreV2Ref on AutoDisposeProviderRef<void> {
|
||||
/// The parameter `backup` of this provider.
|
||||
Map<String, dynamic> get backup;
|
||||
}
|
||||
|
||||
class _RestoreV2ProviderElement extends AutoDisposeProviderElement<void>
|
||||
with RestoreV2Ref {
|
||||
_RestoreV2ProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> get backup => (origin as RestoreV2Provider).backup;
|
||||
}
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/main.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/widgets/custom_textfield.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
|
||||
import 'package:mangayomi/modules/widgets/progress_center.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
|
||||
|
|
@ -19,9 +20,10 @@ class CategoriesScreen extends ConsumerStatefulWidget {
|
|||
class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
|
||||
with TickerProviderStateMixin {
|
||||
late TabController _tabBarController;
|
||||
int tabs = 3;
|
||||
@override
|
||||
void initState() {
|
||||
_tabBarController = TabController(length: 2, vsync: this);
|
||||
_tabBarController = TabController(length: tabs, vsync: this);
|
||||
_tabBarController.animateTo(widget.data.$2);
|
||||
|
||||
super.initState();
|
||||
|
|
@ -29,10 +31,25 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int newTabs = 0;
|
||||
final hideManga = ref.watch(hideMangaStateProvider);
|
||||
final hideAnime = ref.watch(hideAnimeStateProvider);
|
||||
final hideNovel = ref.watch(hideNovelStateProvider);
|
||||
if (!hideManga) newTabs++;
|
||||
if (!hideAnime) newTabs++;
|
||||
if (!hideNovel) newTabs++;
|
||||
if (tabs != newTabs) {
|
||||
_tabBarController.dispose();
|
||||
_tabBarController = TabController(length: newTabs, vsync: this);
|
||||
_tabBarController.animateTo(0);
|
||||
setState(() {
|
||||
tabs = newTabs;
|
||||
});
|
||||
}
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return DefaultTabController(
|
||||
animationDuration: Duration.zero,
|
||||
length: 2,
|
||||
length: newTabs,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
|
|
@ -45,18 +62,25 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
|
|||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
controller: _tabBarController,
|
||||
tabs: [
|
||||
Tab(text: l10n.manga),
|
||||
Tab(text: l10n.anime),
|
||||
if (!hideManga) Tab(text: l10n.manga),
|
||||
if (!hideAnime) Tab(text: l10n.anime),
|
||||
if (!hideNovel) Tab(text: l10n.novel),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: TabBarView(controller: _tabBarController, children: const [
|
||||
CategoriesTab(
|
||||
isManga: true,
|
||||
),
|
||||
CategoriesTab(
|
||||
isManga: false,
|
||||
)
|
||||
body: TabBarView(controller: _tabBarController, children: [
|
||||
if (!hideManga)
|
||||
CategoriesTab(
|
||||
itemType: ItemType.manga,
|
||||
),
|
||||
if (!hideAnime)
|
||||
CategoriesTab(
|
||||
itemType: ItemType.anime,
|
||||
),
|
||||
if (!hideNovel)
|
||||
CategoriesTab(
|
||||
itemType: ItemType.novel,
|
||||
)
|
||||
]),
|
||||
),
|
||||
);
|
||||
|
|
@ -64,8 +88,8 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
|
|||
}
|
||||
|
||||
class CategoriesTab extends ConsumerStatefulWidget {
|
||||
final bool isManga;
|
||||
const CategoriesTab({required this.isManga, super.key});
|
||||
final ItemType itemType;
|
||||
const CategoriesTab({required this.itemType, super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<CategoriesTab> createState() => _CategoriesTabState();
|
||||
|
|
@ -77,7 +101,7 @@ class _CategoriesTabState extends ConsumerState<CategoriesTab> {
|
|||
Widget build(BuildContext context) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
final categories =
|
||||
ref.watch(getMangaCategorieStreamProvider(isManga: widget.isManga));
|
||||
ref.watch(getMangaCategorieStreamProvider(itemType: widget.itemType));
|
||||
return Scaffold(
|
||||
body: categories.when(
|
||||
data: (data) {
|
||||
|
|
@ -178,15 +202,6 @@ class _CategoriesTabState extends ConsumerState<CategoriesTab> {
|
|||
onPressed: () async {
|
||||
await isar.writeTxn(
|
||||
() async {
|
||||
await ref
|
||||
.read(changedItemsManagerProvider(
|
||||
managerId:
|
||||
1)
|
||||
.notifier)
|
||||
.addDeletedCategoryAsync(
|
||||
_entries[
|
||||
index],
|
||||
false);
|
||||
await isar
|
||||
.categorys
|
||||
.delete(_entries[
|
||||
|
|
@ -280,7 +295,7 @@ class _CategoriesTabState extends ConsumerState<CategoriesTab> {
|
|||
: () async {
|
||||
await isar.writeTxn(() async {
|
||||
await isar.categorys.put(Category(
|
||||
forManga: widget.isManga,
|
||||
forItemType: widget.itemType,
|
||||
name: controller.text,
|
||||
));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/category.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
part 'isar_providers.g.dart';
|
||||
|
||||
@riverpod
|
||||
Stream<List<Category>> getMangaCategorieStream(Ref ref,
|
||||
{required bool isManga}) async* {
|
||||
{required ItemType itemType}) async* {
|
||||
yield* isar.categorys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.and()
|
||||
.forMangaEqualTo(isManga)
|
||||
.forItemTypeEqualTo(itemType)
|
||||
.watch(fireImmediately: true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'isar_providers.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$getMangaCategorieStreamHash() =>
|
||||
r'97e90977f4696eedcf597c655a40dd6ccd47ed37';
|
||||
r'1dcf15018a6467eef7a26c1728b9e531ebd984d0';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -41,10 +41,10 @@ class GetMangaCategorieStreamFamily extends Family<AsyncValue<List<Category>>> {
|
|||
|
||||
/// See also [getMangaCategorieStream].
|
||||
GetMangaCategorieStreamProvider call({
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
}) {
|
||||
return GetMangaCategorieStreamProvider(
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ class GetMangaCategorieStreamFamily extends Family<AsyncValue<List<Category>>> {
|
|||
covariant GetMangaCategorieStreamProvider provider,
|
||||
) {
|
||||
return call(
|
||||
isManga: provider.isManga,
|
||||
itemType: provider.itemType,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -77,11 +77,11 @@ class GetMangaCategorieStreamProvider
|
|||
extends AutoDisposeStreamProvider<List<Category>> {
|
||||
/// See also [getMangaCategorieStream].
|
||||
GetMangaCategorieStreamProvider({
|
||||
required bool isManga,
|
||||
required ItemType itemType,
|
||||
}) : this._internal(
|
||||
(ref) => getMangaCategorieStream(
|
||||
ref as GetMangaCategorieStreamRef,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
),
|
||||
from: getMangaCategorieStreamProvider,
|
||||
name: r'getMangaCategorieStreamProvider',
|
||||
|
|
@ -92,7 +92,7 @@ class GetMangaCategorieStreamProvider
|
|||
dependencies: GetMangaCategorieStreamFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
GetMangaCategorieStreamFamily._allTransitiveDependencies,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
);
|
||||
|
||||
GetMangaCategorieStreamProvider._internal(
|
||||
|
|
@ -102,10 +102,10 @@ class GetMangaCategorieStreamProvider
|
|||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.isManga,
|
||||
required this.itemType,
|
||||
}) : super.internal();
|
||||
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
|
|
@ -120,7 +120,7 @@ class GetMangaCategorieStreamProvider
|
|||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -132,13 +132,14 @@ class GetMangaCategorieStreamProvider
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is GetMangaCategorieStreamProvider && other.isManga == isManga;
|
||||
return other is GetMangaCategorieStreamProvider &&
|
||||
other.itemType == itemType;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, isManga.hashCode);
|
||||
hash = _SystemHash.combine(hash, itemType.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
|
@ -148,8 +149,8 @@ class GetMangaCategorieStreamProvider
|
|||
// ignore: unused_element
|
||||
mixin GetMangaCategorieStreamRef
|
||||
on AutoDisposeStreamProviderRef<List<Category>> {
|
||||
/// The parameter `isManga` of this provider.
|
||||
bool get isManga;
|
||||
/// The parameter `itemType` of this provider.
|
||||
ItemType get itemType;
|
||||
}
|
||||
|
||||
class _GetMangaCategorieStreamProviderElement
|
||||
|
|
@ -158,7 +159,7 @@ class _GetMangaCategorieStreamProviderElement
|
|||
_GetMangaCategorieStreamProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
bool get isManga => (origin as GetMangaCategorieStreamProvider).isManga;
|
||||
ItemType get itemType => (origin as GetMangaCategorieStreamProvider).itemType;
|
||||
}
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/modules/more/settings/player/providers/player_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
import 'package:numberpicker/numberpicker.dart';
|
||||
|
|
@ -20,6 +21,7 @@ class PlayerScreen extends ConsumerWidget {
|
|||
final enableAutoSkip = ref.watch(enableAutoSkipStateProvider);
|
||||
final aniSkipTimeoutLength = ref.watch(aniSkipTimeoutLengthStateProvider);
|
||||
final useLibass = ref.watch(useLibassStateProvider);
|
||||
final hideAnime = ref.watch(hideAnimeStateProvider);
|
||||
final fullScreenPlayer = ref.watch(fullScreenPlayerStateProvider);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
|
|
@ -28,6 +30,12 @@ class PlayerScreen extends ConsumerWidget {
|
|||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
SwitchListTile(
|
||||
value: hideAnime,
|
||||
title: Text(context.l10n.hide_anime),
|
||||
onChanged: (value) {
|
||||
ref.read(hideAnimeStateProvider.notifier).set(value);
|
||||
}),
|
||||
ListTile(
|
||||
onTap: () {
|
||||
final values = [100, 95, 90, 85, 80, 75, 70];
|
||||
|
|
|
|||
|
|
@ -137,3 +137,48 @@ class FullScreenReaderState extends _$FullScreenReaderState {
|
|||
() => isar.settings.putSync(settings!..fullScreenReader = value));
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class HideMangaState extends _$HideMangaState {
|
||||
@override
|
||||
bool build() {
|
||||
return isar.settings.getSync(227)!.hideManga ?? false;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
final settings = isar.settings.getSync(227);
|
||||
state = value;
|
||||
isar.writeTxnSync(
|
||||
() => isar.settings.putSync(settings!..hideManga = value));
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class HideAnimeState extends _$HideAnimeState {
|
||||
@override
|
||||
bool build() {
|
||||
return isar.settings.getSync(227)!.hideAnime ?? false;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
final settings = isar.settings.getSync(227);
|
||||
state = value;
|
||||
isar.writeTxnSync(
|
||||
() => isar.settings.putSync(settings!..hideAnime = value));
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class HideNovelState extends _$HideNovelState {
|
||||
@override
|
||||
bool build() {
|
||||
return isar.settings.getSync(227)!.hideNovel ?? false;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
final settings = isar.settings.getSync(227);
|
||||
state = value;
|
||||
isar.writeTxnSync(
|
||||
() => isar.settings.putSync(settings!..hideNovel = value));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,5 +157,53 @@ final fullScreenReaderStateProvider =
|
|||
);
|
||||
|
||||
typedef _$FullScreenReaderState = AutoDisposeNotifier<bool>;
|
||||
String _$hideMangaStateHash() => r'fd24207581798fd1634ff6df2c85b8895053d14c';
|
||||
|
||||
/// See also [HideMangaState].
|
||||
@ProviderFor(HideMangaState)
|
||||
final hideMangaStateProvider =
|
||||
AutoDisposeNotifierProvider<HideMangaState, bool>.internal(
|
||||
HideMangaState.new,
|
||||
name: r'hideMangaStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$hideMangaStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$HideMangaState = AutoDisposeNotifier<bool>;
|
||||
String _$hideAnimeStateHash() => r'3e8748d9312b9ea84364959b7de17fed2204d303';
|
||||
|
||||
/// See also [HideAnimeState].
|
||||
@ProviderFor(HideAnimeState)
|
||||
final hideAnimeStateProvider =
|
||||
AutoDisposeNotifierProvider<HideAnimeState, bool>.internal(
|
||||
HideAnimeState.new,
|
||||
name: r'hideAnimeStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$hideAnimeStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$HideAnimeState = AutoDisposeNotifier<bool>;
|
||||
String _$hideNovelStateHash() => r'697efab85819783a7c1982797927feb397770191';
|
||||
|
||||
/// See also [HideNovelState].
|
||||
@ProviderFor(HideNovelState)
|
||||
final hideNovelStateProvider =
|
||||
AutoDisposeNotifierProvider<HideNovelState, bool>.internal(
|
||||
HideNovelState.new,
|
||||
name: r'hideNovelStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$hideNovelStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$HideNovelState = AutoDisposeNotifier<bool>;
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ class ReaderScreen extends ConsumerWidget {
|
|||
final backgroundColor = ref.watch(backgroundColorStateProvider);
|
||||
final usePageTapZones = ref.watch(usePageTapZonesStateProvider);
|
||||
final fullScreenReader = ref.watch(fullScreenReaderStateProvider);
|
||||
final hideManga = ref.watch(hideMangaStateProvider);
|
||||
final hideNovel = ref.watch(hideNovelStateProvider);
|
||||
final cropBorders = ref.watch(cropBordersStateProvider);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
|
|
@ -328,6 +330,18 @@ class ReaderScreen extends ConsumerWidget {
|
|||
style: TextStyle(fontSize: 11, color: context.secondaryColor),
|
||||
),
|
||||
),
|
||||
SwitchListTile(
|
||||
value: hideManga,
|
||||
title: Text(context.l10n.hide_manga),
|
||||
onChanged: (value) {
|
||||
ref.read(hideMangaStateProvider.notifier).set(value);
|
||||
}),
|
||||
SwitchListTile(
|
||||
value: hideNovel,
|
||||
title: Text(context.l10n.hide_novel),
|
||||
onChanged: (value) {
|
||||
ref.read(hideNovelStateProvider.notifier).set(value);
|
||||
}),
|
||||
SwitchListTile(
|
||||
value: fullScreenReader,
|
||||
title: Text(context.l10n.fullscreen),
|
||||
|
|
|
|||
|
|
@ -1,210 +1,8 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/category.dart';
|
||||
import 'package:mangayomi/models/changed_items.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/models/sync_preference.dart';
|
||||
import 'package:mangayomi/services/sync_server.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
part 'sync_providers.g.dart';
|
||||
|
||||
@riverpod
|
||||
void addUpdatedChapterIndependent(
|
||||
Ref ref, Chapter chapter, bool deleted, bool txn) {
|
||||
final changedItems = isar.changedItems.getSync(1) ?? ChangedItems();
|
||||
bool updated = false;
|
||||
changedItems.updatedChapters = changedItems.updatedChapters?.map((e) {
|
||||
if (e.chapterId == chapter.id) {
|
||||
e.isBookmarked = chapter.isBookmarked;
|
||||
e.isRead = chapter.isRead;
|
||||
e.lastPageRead = chapter.lastPageRead;
|
||||
e.deleted = deleted;
|
||||
updated = true;
|
||||
}
|
||||
return e;
|
||||
}).toList();
|
||||
if (!updated) {
|
||||
final updatedChapter = UpdatedChapter(
|
||||
chapterId: chapter.id,
|
||||
isBookmarked: chapter.isBookmarked,
|
||||
isRead: chapter.isRead,
|
||||
lastPageRead: chapter.lastPageRead,
|
||||
deleted: deleted);
|
||||
changedItems.updatedChapters = changedItems.updatedChapters?.toList()
|
||||
?..add(updatedChapter);
|
||||
}
|
||||
if (!txn) {
|
||||
isar.changedItems.putSync(changedItems);
|
||||
} else {
|
||||
isar.writeTxnSync(() {
|
||||
isar.changedItems.putSync(changedItems);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
void checkForSyncIndependent(Ref ref, bool silent) {
|
||||
ref.read(SyncServerProvider(syncId: 1).notifier).checkForSync(silent);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class ChangedItemsManager extends _$ChangedItemsManager {
|
||||
@override
|
||||
ChangedItems? build({required int? managerId}) {
|
||||
return isar.changedItems.getSync(managerId!);
|
||||
}
|
||||
|
||||
void cleanChangedItems(bool txn) {
|
||||
final changedItems =
|
||||
isar.changedItems.getSync(managerId!) ?? ChangedItems(id: managerId);
|
||||
changedItems.deletedMangas = [];
|
||||
changedItems.updatedChapters = [];
|
||||
changedItems.deletedCategories = [];
|
||||
if (!txn) {
|
||||
isar.changedItems.putSync(changedItems);
|
||||
} else {
|
||||
isar.writeTxnSync(() {
|
||||
isar.changedItems.putSync(changedItems);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void addDeletedManga(Manga manga, bool txn) {
|
||||
final changedItems =
|
||||
isar.changedItems.getSync(managerId!) ?? ChangedItems(id: managerId);
|
||||
log("DEBUG");
|
||||
log(jsonEncode(changedItems));
|
||||
final deletedManga = DeletedManga(mangaId: manga.id);
|
||||
changedItems.deletedMangas = changedItems.deletedMangas?.toList()
|
||||
?..add(deletedManga);
|
||||
if (!txn) {
|
||||
isar.changedItems.putSync(changedItems);
|
||||
} else {
|
||||
isar.writeTxnSync(() {
|
||||
isar.changedItems.putSync(changedItems);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future addDeletedMangaAsync(Manga manga, bool txn) async {
|
||||
final changedItems =
|
||||
await isar.changedItems.get(managerId!) ?? ChangedItems(id: managerId);
|
||||
final deletedManga = DeletedManga(mangaId: manga.id);
|
||||
changedItems.deletedMangas = changedItems.deletedMangas?.toList()
|
||||
?..add(deletedManga);
|
||||
if (!txn) {
|
||||
await isar.changedItems.put(changedItems);
|
||||
} else {
|
||||
await isar.writeTxn(() async {
|
||||
await isar.changedItems.put(changedItems);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void addUpdatedChapter(Chapter chapter, bool deleted, bool txn) {
|
||||
final changedItems =
|
||||
isar.changedItems.getSync(managerId!) ?? ChangedItems(id: managerId);
|
||||
bool updated = false;
|
||||
changedItems.updatedChapters = changedItems.updatedChapters?.map((e) {
|
||||
if (e.chapterId == chapter.id && e.mangaId == chapter.mangaId) {
|
||||
e.isBookmarked = chapter.isBookmarked;
|
||||
e.isRead = chapter.isRead;
|
||||
e.lastPageRead = chapter.lastPageRead;
|
||||
e.deleted = deleted;
|
||||
updated = true;
|
||||
}
|
||||
return e;
|
||||
}).toList();
|
||||
if (!updated) {
|
||||
final updatedChapter = UpdatedChapter(
|
||||
chapterId: chapter.id,
|
||||
mangaId: chapter.mangaId,
|
||||
isBookmarked: chapter.isBookmarked,
|
||||
isRead: chapter.isRead,
|
||||
lastPageRead: chapter.lastPageRead,
|
||||
deleted: deleted);
|
||||
changedItems.updatedChapters = changedItems.updatedChapters?.toList()
|
||||
?..add(updatedChapter);
|
||||
}
|
||||
if (!txn) {
|
||||
isar.changedItems.putSync(changedItems);
|
||||
} else {
|
||||
isar.writeTxnSync(() {
|
||||
isar.changedItems.putSync(changedItems);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future addUpdatedChapterAsync(Chapter chapter, bool deleted, bool txn) async {
|
||||
final changedItems =
|
||||
await isar.changedItems.get(managerId!) ?? ChangedItems(id: managerId);
|
||||
bool updated = false;
|
||||
changedItems.updatedChapters = changedItems.updatedChapters?.map((e) {
|
||||
if (e.chapterId == chapter.id && e.mangaId == chapter.mangaId) {
|
||||
e.isBookmarked = chapter.isBookmarked;
|
||||
e.isRead = chapter.isRead;
|
||||
e.lastPageRead = chapter.lastPageRead;
|
||||
e.deleted = deleted;
|
||||
updated = true;
|
||||
}
|
||||
return e;
|
||||
}).toList();
|
||||
if (!updated) {
|
||||
final updatedChapter = UpdatedChapter(
|
||||
chapterId: chapter.id,
|
||||
mangaId: chapter.mangaId,
|
||||
isBookmarked: chapter.isBookmarked,
|
||||
isRead: chapter.isRead,
|
||||
lastPageRead: chapter.lastPageRead,
|
||||
deleted: deleted);
|
||||
changedItems.updatedChapters = changedItems.updatedChapters?.toList()
|
||||
?..add(updatedChapter);
|
||||
}
|
||||
if (!txn) {
|
||||
await isar.changedItems.put(changedItems);
|
||||
} else {
|
||||
await isar.writeTxn(() async {
|
||||
await isar.changedItems.put(changedItems);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void addDeletedCategory(Category category, bool txn) {
|
||||
final changedItems =
|
||||
isar.changedItems.getSync(managerId!) ?? ChangedItems(id: managerId);
|
||||
final deletedCategory = DeletedCategory(categoryId: category.id);
|
||||
changedItems.deletedCategories = changedItems.deletedCategories?.toList()
|
||||
?..add(deletedCategory);
|
||||
if (!txn) {
|
||||
isar.changedItems.putSync(changedItems);
|
||||
} else {
|
||||
isar.writeTxnSync(() {
|
||||
isar.changedItems.putSync(changedItems);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future addDeletedCategoryAsync(Category category, bool txn) async {
|
||||
final changedItems =
|
||||
await isar.changedItems.get(managerId!) ?? ChangedItems(id: managerId);
|
||||
final deletedCategory = DeletedCategory(categoryId: category.id);
|
||||
changedItems.deletedCategories = changedItems.deletedCategories?.toList()
|
||||
?..add(deletedCategory);
|
||||
if (!txn) {
|
||||
await isar.changedItems.put(changedItems);
|
||||
} else {
|
||||
await isar.writeTxn(() async {
|
||||
await isar.changedItems.put(changedItems);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class Synching extends _$Synching {
|
||||
@override
|
||||
|
|
@ -224,13 +22,6 @@ class Synching extends _$Synching {
|
|||
});
|
||||
}
|
||||
|
||||
void setLastSync(int timestamp) {
|
||||
isar.writeTxnSync(() {
|
||||
isar.syncPreferences.putSync(
|
||||
isar.syncPreferences.getSync(syncId!)!..lastSync = timestamp);
|
||||
});
|
||||
}
|
||||
|
||||
void setLastUpload(int timestamp) {
|
||||
isar.writeTxnSync(() {
|
||||
isar.syncPreferences.putSync(
|
||||
|
|
@ -252,33 +43,3 @@ class Synching extends _$Synching {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class SyncOnAppLaunchState extends _$SyncOnAppLaunchState {
|
||||
@override
|
||||
bool build() {
|
||||
return isar.settings.getSync(227)!.syncOnAppLaunch ?? false;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
final settings = isar.settings.getSync(227);
|
||||
state = value;
|
||||
isar.writeTxnSync(
|
||||
() => isar.settings.putSync(settings!..syncOnAppLaunch = value));
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class SyncAfterReadingState extends _$SyncAfterReadingState {
|
||||
@override
|
||||
bool build() {
|
||||
return isar.settings.getSync(227)!.syncAfterReading ?? false;
|
||||
}
|
||||
|
||||
void set(bool value) {
|
||||
final settings = isar.settings.getSync(227);
|
||||
state = value;
|
||||
isar.writeTxnSync(
|
||||
() => isar.settings.putSync(settings!..syncAfterReading = value));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ part of 'sync_providers.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$addUpdatedChapterIndependentHash() =>
|
||||
r'7abb8f085a229ec0573c730234fa4fc4ff86d794';
|
||||
String _$synchingHash() => r'3ab44d9e753f2d4b51fd10af6c98ffac78cbf201';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -30,450 +29,6 @@ class _SystemHash {
|
|||
}
|
||||
}
|
||||
|
||||
/// See also [addUpdatedChapterIndependent].
|
||||
@ProviderFor(addUpdatedChapterIndependent)
|
||||
const addUpdatedChapterIndependentProvider =
|
||||
AddUpdatedChapterIndependentFamily();
|
||||
|
||||
/// See also [addUpdatedChapterIndependent].
|
||||
class AddUpdatedChapterIndependentFamily extends Family<void> {
|
||||
/// See also [addUpdatedChapterIndependent].
|
||||
const AddUpdatedChapterIndependentFamily();
|
||||
|
||||
/// See also [addUpdatedChapterIndependent].
|
||||
AddUpdatedChapterIndependentProvider call(
|
||||
Chapter chapter,
|
||||
bool deleted,
|
||||
bool txn,
|
||||
) {
|
||||
return AddUpdatedChapterIndependentProvider(
|
||||
chapter,
|
||||
deleted,
|
||||
txn,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AddUpdatedChapterIndependentProvider getProviderOverride(
|
||||
covariant AddUpdatedChapterIndependentProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.chapter,
|
||||
provider.deleted,
|
||||
provider.txn,
|
||||
);
|
||||
}
|
||||
|
||||
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'addUpdatedChapterIndependentProvider';
|
||||
}
|
||||
|
||||
/// See also [addUpdatedChapterIndependent].
|
||||
class AddUpdatedChapterIndependentProvider extends AutoDisposeProvider<void> {
|
||||
/// See also [addUpdatedChapterIndependent].
|
||||
AddUpdatedChapterIndependentProvider(
|
||||
Chapter chapter,
|
||||
bool deleted,
|
||||
bool txn,
|
||||
) : this._internal(
|
||||
(ref) => addUpdatedChapterIndependent(
|
||||
ref as AddUpdatedChapterIndependentRef,
|
||||
chapter,
|
||||
deleted,
|
||||
txn,
|
||||
),
|
||||
from: addUpdatedChapterIndependentProvider,
|
||||
name: r'addUpdatedChapterIndependentProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$addUpdatedChapterIndependentHash,
|
||||
dependencies: AddUpdatedChapterIndependentFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
AddUpdatedChapterIndependentFamily._allTransitiveDependencies,
|
||||
chapter: chapter,
|
||||
deleted: deleted,
|
||||
txn: txn,
|
||||
);
|
||||
|
||||
AddUpdatedChapterIndependentProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.chapter,
|
||||
required this.deleted,
|
||||
required this.txn,
|
||||
}) : super.internal();
|
||||
|
||||
final Chapter chapter;
|
||||
final bool deleted;
|
||||
final bool txn;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
void Function(AddUpdatedChapterIndependentRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: AddUpdatedChapterIndependentProvider._internal(
|
||||
(ref) => create(ref as AddUpdatedChapterIndependentRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
chapter: chapter,
|
||||
deleted: deleted,
|
||||
txn: txn,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeProviderElement<void> createElement() {
|
||||
return _AddUpdatedChapterIndependentProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is AddUpdatedChapterIndependentProvider &&
|
||||
other.chapter == chapter &&
|
||||
other.deleted == deleted &&
|
||||
other.txn == txn;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, chapter.hashCode);
|
||||
hash = _SystemHash.combine(hash, deleted.hashCode);
|
||||
hash = _SystemHash.combine(hash, txn.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin AddUpdatedChapterIndependentRef on AutoDisposeProviderRef<void> {
|
||||
/// The parameter `chapter` of this provider.
|
||||
Chapter get chapter;
|
||||
|
||||
/// The parameter `deleted` of this provider.
|
||||
bool get deleted;
|
||||
|
||||
/// The parameter `txn` of this provider.
|
||||
bool get txn;
|
||||
}
|
||||
|
||||
class _AddUpdatedChapterIndependentProviderElement
|
||||
extends AutoDisposeProviderElement<void>
|
||||
with AddUpdatedChapterIndependentRef {
|
||||
_AddUpdatedChapterIndependentProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Chapter get chapter =>
|
||||
(origin as AddUpdatedChapterIndependentProvider).chapter;
|
||||
@override
|
||||
bool get deleted => (origin as AddUpdatedChapterIndependentProvider).deleted;
|
||||
@override
|
||||
bool get txn => (origin as AddUpdatedChapterIndependentProvider).txn;
|
||||
}
|
||||
|
||||
String _$checkForSyncIndependentHash() =>
|
||||
r'3a3658a67cd6cb210e76126b33592bd1ea67e3f0';
|
||||
|
||||
/// See also [checkForSyncIndependent].
|
||||
@ProviderFor(checkForSyncIndependent)
|
||||
const checkForSyncIndependentProvider = CheckForSyncIndependentFamily();
|
||||
|
||||
/// See also [checkForSyncIndependent].
|
||||
class CheckForSyncIndependentFamily extends Family<void> {
|
||||
/// See also [checkForSyncIndependent].
|
||||
const CheckForSyncIndependentFamily();
|
||||
|
||||
/// See also [checkForSyncIndependent].
|
||||
CheckForSyncIndependentProvider call(
|
||||
bool silent,
|
||||
) {
|
||||
return CheckForSyncIndependentProvider(
|
||||
silent,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
CheckForSyncIndependentProvider getProviderOverride(
|
||||
covariant CheckForSyncIndependentProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.silent,
|
||||
);
|
||||
}
|
||||
|
||||
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'checkForSyncIndependentProvider';
|
||||
}
|
||||
|
||||
/// See also [checkForSyncIndependent].
|
||||
class CheckForSyncIndependentProvider extends AutoDisposeProvider<void> {
|
||||
/// See also [checkForSyncIndependent].
|
||||
CheckForSyncIndependentProvider(
|
||||
bool silent,
|
||||
) : this._internal(
|
||||
(ref) => checkForSyncIndependent(
|
||||
ref as CheckForSyncIndependentRef,
|
||||
silent,
|
||||
),
|
||||
from: checkForSyncIndependentProvider,
|
||||
name: r'checkForSyncIndependentProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$checkForSyncIndependentHash,
|
||||
dependencies: CheckForSyncIndependentFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
CheckForSyncIndependentFamily._allTransitiveDependencies,
|
||||
silent: silent,
|
||||
);
|
||||
|
||||
CheckForSyncIndependentProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.silent,
|
||||
}) : super.internal();
|
||||
|
||||
final bool silent;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
void Function(CheckForSyncIndependentRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: CheckForSyncIndependentProvider._internal(
|
||||
(ref) => create(ref as CheckForSyncIndependentRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
silent: silent,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeProviderElement<void> createElement() {
|
||||
return _CheckForSyncIndependentProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is CheckForSyncIndependentProvider && other.silent == silent;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, silent.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin CheckForSyncIndependentRef on AutoDisposeProviderRef<void> {
|
||||
/// The parameter `silent` of this provider.
|
||||
bool get silent;
|
||||
}
|
||||
|
||||
class _CheckForSyncIndependentProviderElement
|
||||
extends AutoDisposeProviderElement<void> with CheckForSyncIndependentRef {
|
||||
_CheckForSyncIndependentProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
bool get silent => (origin as CheckForSyncIndependentProvider).silent;
|
||||
}
|
||||
|
||||
String _$changedItemsManagerHash() =>
|
||||
r'a4f0363ab430ddb6c2a23fde6f5671ba8ec252cf';
|
||||
|
||||
abstract class _$ChangedItemsManager
|
||||
extends BuildlessAutoDisposeNotifier<ChangedItems?> {
|
||||
late final int? managerId;
|
||||
|
||||
ChangedItems? build({
|
||||
required int? managerId,
|
||||
});
|
||||
}
|
||||
|
||||
/// See also [ChangedItemsManager].
|
||||
@ProviderFor(ChangedItemsManager)
|
||||
const changedItemsManagerProvider = ChangedItemsManagerFamily();
|
||||
|
||||
/// See also [ChangedItemsManager].
|
||||
class ChangedItemsManagerFamily extends Family<ChangedItems?> {
|
||||
/// See also [ChangedItemsManager].
|
||||
const ChangedItemsManagerFamily();
|
||||
|
||||
/// See also [ChangedItemsManager].
|
||||
ChangedItemsManagerProvider call({
|
||||
required int? managerId,
|
||||
}) {
|
||||
return ChangedItemsManagerProvider(
|
||||
managerId: managerId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ChangedItemsManagerProvider getProviderOverride(
|
||||
covariant ChangedItemsManagerProvider provider,
|
||||
) {
|
||||
return call(
|
||||
managerId: provider.managerId,
|
||||
);
|
||||
}
|
||||
|
||||
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'changedItemsManagerProvider';
|
||||
}
|
||||
|
||||
/// See also [ChangedItemsManager].
|
||||
class ChangedItemsManagerProvider extends AutoDisposeNotifierProviderImpl<
|
||||
ChangedItemsManager, ChangedItems?> {
|
||||
/// See also [ChangedItemsManager].
|
||||
ChangedItemsManagerProvider({
|
||||
required int? managerId,
|
||||
}) : this._internal(
|
||||
() => ChangedItemsManager()..managerId = managerId,
|
||||
from: changedItemsManagerProvider,
|
||||
name: r'changedItemsManagerProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$changedItemsManagerHash,
|
||||
dependencies: ChangedItemsManagerFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ChangedItemsManagerFamily._allTransitiveDependencies,
|
||||
managerId: managerId,
|
||||
);
|
||||
|
||||
ChangedItemsManagerProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.managerId,
|
||||
}) : super.internal();
|
||||
|
||||
final int? managerId;
|
||||
|
||||
@override
|
||||
ChangedItems? runNotifierBuild(
|
||||
covariant ChangedItemsManager notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
managerId: managerId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(ChangedItemsManager Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: ChangedItemsManagerProvider._internal(
|
||||
() => create()..managerId = managerId,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
managerId: managerId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeNotifierProviderElement<ChangedItemsManager, ChangedItems?>
|
||||
createElement() {
|
||||
return _ChangedItemsManagerProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ChangedItemsManagerProvider && other.managerId == managerId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, managerId.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin ChangedItemsManagerRef on AutoDisposeNotifierProviderRef<ChangedItems?> {
|
||||
/// The parameter `managerId` of this provider.
|
||||
int? get managerId;
|
||||
}
|
||||
|
||||
class _ChangedItemsManagerProviderElement
|
||||
extends AutoDisposeNotifierProviderElement<ChangedItemsManager,
|
||||
ChangedItems?> with ChangedItemsManagerRef {
|
||||
_ChangedItemsManagerProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
int? get managerId => (origin as ChangedItemsManagerProvider).managerId;
|
||||
}
|
||||
|
||||
String _$synchingHash() => r'2ef7fd99da4292ed236252d2b727cff9a69f43a9';
|
||||
|
||||
abstract class _$Synching
|
||||
extends BuildlessAutoDisposeNotifier<SyncPreference?> {
|
||||
late final int? syncId;
|
||||
|
|
@ -616,40 +171,5 @@ class _SynchingProviderElement
|
|||
@override
|
||||
int? get syncId => (origin as SynchingProvider).syncId;
|
||||
}
|
||||
|
||||
String _$syncOnAppLaunchStateHash() =>
|
||||
r'dc7f3243e38a748462628229066c8fc0653c908b';
|
||||
|
||||
/// See also [SyncOnAppLaunchState].
|
||||
@ProviderFor(SyncOnAppLaunchState)
|
||||
final syncOnAppLaunchStateProvider =
|
||||
AutoDisposeNotifierProvider<SyncOnAppLaunchState, bool>.internal(
|
||||
SyncOnAppLaunchState.new,
|
||||
name: r'syncOnAppLaunchStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$syncOnAppLaunchStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$SyncOnAppLaunchState = AutoDisposeNotifier<bool>;
|
||||
String _$syncAfterReadingStateHash() =>
|
||||
r'e507acd490b5aea7fc1a8fd7a369ec01f4c47192';
|
||||
|
||||
/// See also [SyncAfterReadingState].
|
||||
@ProviderFor(SyncAfterReadingState)
|
||||
final syncAfterReadingStateProvider =
|
||||
AutoDisposeNotifierProvider<SyncAfterReadingState, bool>.internal(
|
||||
SyncAfterReadingState.new,
|
||||
name: r'syncAfterReadingStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$syncAfterReadingStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$SyncAfterReadingState = AutoDisposeNotifier<bool>;
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import 'package:isar/isar.dart';
|
|||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/utils/date.dart';
|
||||
import 'package:mangayomi/models/sync_preference.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/widgets/sync_listile.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/services/sync_server.dart';
|
||||
|
|
@ -15,8 +14,6 @@ class SyncScreen extends ConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final syncAfterReading = ref.watch(syncAfterReadingStateProvider);
|
||||
final syncOnAppLaunch = ref.watch(syncOnAppLaunchStateProvider);
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
|
|
@ -36,26 +33,6 @@ class SyncScreen extends ConsumerWidget {
|
|||
syncPreference.authToken?.isNotEmpty ?? false;
|
||||
return Column(
|
||||
children: [
|
||||
SwitchListTile(
|
||||
value: syncAfterReading,
|
||||
title: Text(context.l10n.syncAfterReading),
|
||||
onChanged: !isLogged
|
||||
? null
|
||||
: (value) {
|
||||
ref
|
||||
.read(syncAfterReadingStateProvider.notifier)
|
||||
.set(value);
|
||||
}),
|
||||
SwitchListTile(
|
||||
value: syncOnAppLaunch,
|
||||
title: Text(context.l10n.syncOnAppLaunch),
|
||||
onChanged: !isLogged
|
||||
? null
|
||||
: (value) {
|
||||
ref
|
||||
.read(syncOnAppLaunchStateProvider.notifier)
|
||||
.set(value);
|
||||
}),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 15, right: 15, bottom: 10, top: 5),
|
||||
|
|
@ -103,12 +80,6 @@ class SyncScreen extends ConsumerWidget {
|
|||
const SizedBox(width: 10),
|
||||
Column(children: [
|
||||
const SizedBox(width: 20),
|
||||
Text(
|
||||
"${l10n.last_sync}: ${dateFormat((syncPreference.lastSync ?? 0).toString(), ref: ref, context: context)} ${dateFormatHour((syncPreference.lastSync ?? 0).toString(), context)}",
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: context.secondaryColor)),
|
||||
const SizedBox(width: 20),
|
||||
Text(
|
||||
"${l10n.last_upload}: ${dateFormat((syncPreference.lastUpload ?? 0).toString(), ref: ref, context: context)} ${dateFormatHour((syncPreference.lastUpload ?? 0).toString(), context)}",
|
||||
style: TextStyle(
|
||||
|
|
@ -127,27 +98,6 @@ class SyncScreen extends ConsumerWidget {
|
|||
),
|
||||
Row(
|
||||
children: [
|
||||
const SizedBox(width: 20),
|
||||
Column(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: !isLogged
|
||||
? null
|
||||
: () {
|
||||
ref
|
||||
.read(syncServerProvider(syncId: 1)
|
||||
.notifier)
|
||||
.checkForSync(false);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.sync,
|
||||
color: !isLogged
|
||||
? context.secondaryColor
|
||||
: context.primaryColor,
|
||||
)),
|
||||
Text(l10n.sync_button_sync),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
Column(
|
||||
children: [
|
||||
|
|
|
|||
303
lib/modules/novel/novel_reader_controller_provider.dart
Normal file
303
lib/modules/novel/novel_reader_controller_provider.dart
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
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:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'novel_reader_controller_provider.g.dart';
|
||||
|
||||
@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 setChapterOffset(double newOffset, double maxOffset, bool save) {
|
||||
if (incognitoMode) return;
|
||||
final isRead = (newOffset / (maxOffset != 0 ? maxOffset : 1)) >= 0.9;
|
||||
if (isRead || save) {
|
||||
final ch = chapter;
|
||||
isar.writeTxnSync(() {
|
||||
ch.isRead = isRead;
|
||||
ch.lastPageRead = (maxOffset != 0 ? newOffset / maxOffset : 0).toString();
|
||||
isar.chapters.putSync(ch);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void setChapterBookmarked() {
|
||||
if (incognitoMode) return;
|
||||
final isBookmarked = getChapterBookmarked();
|
||||
final chap = chapter;
|
||||
isar.writeTxnSync(() {
|
||||
chap.isBookmarked = !isBookmarked;
|
||||
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().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().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().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().toList()[prevChapIdx.$1];
|
||||
}
|
||||
|
||||
Chapter getNextChapter() {
|
||||
final nextChapIdx = getNextChapterIndex();
|
||||
return nextChapIdx.$2
|
||||
? getManga().getFilteredChapterList()[nextChapIdx.$1]
|
||||
: getManga().chapters.toList().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 MangaExtensions on Manga {
|
||||
List<Chapter> getFilteredChapterList() {
|
||||
final data = this.chapters.toList().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;
|
||||
}
|
||||
177
lib/modules/novel/novel_reader_controller_provider.g.dart
Normal file
177
lib/modules/novel/novel_reader_controller_provider.g.dart
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'novel_reader_controller_provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$novelReaderControllerHash() =>
|
||||
r'2eec885b858de8195e31a2d0b70feb56c1dc4268';
|
||||
|
||||
/// 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
|
||||
620
lib/modules/novel/novel_reader_view.dart
Normal file
620
lib/modules/novel/novel_reader_view.dart
Normal file
|
|
@ -0,0 +1,620 @@
|
|||
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/models/settings.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:url_launcher/url_launcher.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'package:flutter_widget_from_html/flutter_widget_from_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);
|
||||
final _scrollController = ScrollController(
|
||||
initialScrollOffset: 0,
|
||||
keepScrollOffset: true,
|
||||
);
|
||||
bool scrolled = false;
|
||||
double offset = 0;
|
||||
double maxOffset = 0;
|
||||
bool isDesktop = Platform.isMacOS || Platform.isLinux || Platform.isWindows;
|
||||
|
||||
void onScroll() {
|
||||
if (_scrollController.hasClients) {
|
||||
offset = _scrollController.offset;
|
||||
maxOffset = _scrollController.position.maxScrollExtent;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_readerController.setChapterOffset(offset, maxOffset, true);
|
||||
_readerController.setMangaHistoryUpdate();
|
||||
_scrollController.removeListener(onScroll);
|
||||
_scrollController.dispose();
|
||||
_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();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_scrollController.addListener(onScroll);
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
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: [
|
||||
Row(
|
||||
children: [
|
||||
widget.htmlContent.when(
|
||||
data: (htmlContent) {
|
||||
Future.delayed(const Duration(milliseconds: 1000),
|
||||
() {
|
||||
if (!scrolled && _scrollController.hasClients) {
|
||||
_scrollController.animateTo(
|
||||
_scrollController.position.maxScrollExtent *
|
||||
(double.tryParse(chapter.lastPageRead!) ??
|
||||
0),
|
||||
duration: Duration(seconds: 2),
|
||||
curve: Curves.fastOutSlowIn);
|
||||
scrolled = true;
|
||||
}
|
||||
});
|
||||
return Expanded(
|
||||
child: SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
_isViewFunction();
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
HtmlWidget(
|
||||
htmlContent,
|
||||
customStylesBuilder: (element) {
|
||||
switch (backgroundColor) {
|
||||
case BackgroundColor.black:
|
||||
return {
|
||||
'background-color': 'black',
|
||||
};
|
||||
default:
|
||||
return {
|
||||
'background-color': '#F0F0F0',
|
||||
};
|
||||
}
|
||||
},
|
||||
onTapUrl: (url) {
|
||||
context.push("/mangawebview",
|
||||
extra: {'url': url, 'title': url});
|
||||
return true;
|
||||
},
|
||||
renderMode: RenderMode.column,
|
||||
textStyle: TextStyle(
|
||||
color: backgroundColor ==
|
||||
BackgroundColor.white
|
||||
? Colors.black
|
||||
: Colors.white,
|
||||
fontSize: 14),
|
||||
),
|
||||
Center(
|
||||
heightFactor: 2,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
spacing: 5,
|
||||
children: [
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(5),
|
||||
onPressed: () =>
|
||||
pushReplacementMangaReaderView(
|
||||
context: context,
|
||||
chapter: _readerController
|
||||
.getPrevChapter(),
|
||||
),
|
||||
icon: Icon(
|
||||
size: 32,
|
||||
Icons.arrow_back,
|
||||
color: backgroundColor ==
|
||||
BackgroundColor.white
|
||||
? Colors.black
|
||||
: Colors.white,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(5),
|
||||
onPressed: () =>
|
||||
pushReplacementMangaReaderView(
|
||||
context: context,
|
||||
chapter: _readerController
|
||||
.getNextChapter(),
|
||||
),
|
||||
icon: Icon(
|
||||
size: 32,
|
||||
Icons.arrow_forward,
|
||||
color: backgroundColor ==
|
||||
BackgroundColor.white
|
||||
? Colors.black
|
||||
: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
loading: () => const Expanded(
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)),
|
||||
error: (err, stack) => Center(
|
||||
child: Text(err.toString()),
|
||||
)),
|
||||
],
|
||||
),
|
||||
//_gestureRightLeft(),
|
||||
//_gestureTopBottom(),
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Widget _gestureRightLeft() {
|
||||
return Consumer(
|
||||
builder: (context, ref, child) {
|
||||
return Row(
|
||||
children: [
|
||||
/// left region
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
_isViewFunction();
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
/// center region
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
_isViewFunction();
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
/// right region
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
_isViewFunction();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _gestureTopBottom() {
|
||||
return Consumer(
|
||||
builder: (context, ref, child) {
|
||||
return Column(
|
||||
children: [
|
||||
/// top region
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
_isViewFunction();
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
/// center region
|
||||
const Expanded(flex: 5, child: SizedBox.shrink()),
|
||||
|
||||
/// bottom region
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
_isViewFunction();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import 'package:mangayomi/models/update.dart';
|
|||
import 'package:mangayomi/models/history.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/modules/manga/detail/providers/update_manga_detail_providers.dart';
|
||||
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
|
||||
import 'package:mangayomi/modules/updates/widgets/update_chapter_list_tile_widget.dart';
|
||||
import 'package:mangayomi/modules/history/providers/isar_providers.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
|
|
@ -31,6 +32,7 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
|
|||
with TickerProviderStateMixin {
|
||||
late TabController _tabBarController;
|
||||
bool _isLoading = false;
|
||||
int tabs = 3;
|
||||
Future<void> _updateLibrary() async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
|
|
@ -42,7 +44,11 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
|
|||
.idIsNotNull()
|
||||
.favoriteEqualTo(true)
|
||||
.and()
|
||||
.isMangaEqualTo(_tabBarController.index == 0)
|
||||
.itemTypeEqualTo(_tabBarController.index == 0
|
||||
? ItemType.manga
|
||||
: _tabBarController.index == 1
|
||||
? ItemType.anime
|
||||
: ItemType.novel)
|
||||
.findAllSync();
|
||||
int numbers = 0;
|
||||
|
||||
|
|
@ -66,16 +72,18 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
|
|||
});
|
||||
}
|
||||
|
||||
void tabListener() {
|
||||
setState(() {
|
||||
_textEditingController.clear();
|
||||
_isSearch = false;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_tabBarController = TabController(length: 2, vsync: this);
|
||||
_tabBarController = TabController(length: tabs, vsync: this);
|
||||
_tabBarController.animateTo(0);
|
||||
_tabBarController.addListener(() {
|
||||
setState(() {
|
||||
_textEditingController.clear();
|
||||
_isSearch = false;
|
||||
});
|
||||
});
|
||||
_tabBarController.addListener(tabListener);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
|
@ -84,10 +92,27 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
|
|||
List<History> entriesData = [];
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int newTabs = 0;
|
||||
final hideManga = ref.watch(hideMangaStateProvider);
|
||||
final hideAnime = ref.watch(hideAnimeStateProvider);
|
||||
final hideNovel = ref.watch(hideNovelStateProvider);
|
||||
if (!hideManga) newTabs++;
|
||||
if (!hideAnime) newTabs++;
|
||||
if (!hideNovel) newTabs++;
|
||||
if (tabs != newTabs) {
|
||||
_tabBarController.removeListener(tabListener);
|
||||
_tabBarController.dispose();
|
||||
_tabBarController = TabController(length: newTabs, vsync: this);
|
||||
_tabBarController.animateTo(0);
|
||||
_tabBarController.addListener(tabListener);
|
||||
setState(() {
|
||||
tabs = newTabs;
|
||||
});
|
||||
}
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return DefaultTabController(
|
||||
animationDuration: Duration.zero,
|
||||
length: 2,
|
||||
length: newTabs,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
|
|
@ -160,10 +185,20 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
|
|||
List<Update> updates = isar.updates
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.chapter((q) => q.manga((q) =>
|
||||
q.isMangaEqualTo(
|
||||
_tabBarController.index ==
|
||||
0)))
|
||||
.chapter((q) => q.manga((q) => q
|
||||
.itemTypeEqualTo(_tabBarController
|
||||
.index ==
|
||||
0 &&
|
||||
!hideManga
|
||||
? ItemType.manga
|
||||
: _tabBarController.index ==
|
||||
1 -
|
||||
(hideManga
|
||||
? 1
|
||||
: 0) &&
|
||||
!hideAnime
|
||||
? ItemType.anime
|
||||
: ItemType.novel)))
|
||||
.findAllSync()
|
||||
.toList();
|
||||
isar.writeTxnSync(() {
|
||||
|
|
@ -189,22 +224,30 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
|
|||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
controller: _tabBarController,
|
||||
tabs: [
|
||||
Tab(text: l10n.manga),
|
||||
Tab(text: l10n.anime),
|
||||
if (!hideManga) Tab(text: l10n.manga),
|
||||
if (!hideAnime) Tab(text: l10n.anime),
|
||||
if (!hideNovel) Tab(text: l10n.novel),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: TabBarView(controller: _tabBarController, children: [
|
||||
UpdateTab(
|
||||
isManga: true,
|
||||
query: _textEditingController.text,
|
||||
isLoading: _isLoading),
|
||||
UpdateTab(
|
||||
isManga: false,
|
||||
query: _textEditingController.text,
|
||||
isLoading: _isLoading)
|
||||
if (!hideManga)
|
||||
UpdateTab(
|
||||
itemType: ItemType.manga,
|
||||
query: _textEditingController.text,
|
||||
isLoading: _isLoading),
|
||||
if (!hideAnime)
|
||||
UpdateTab(
|
||||
itemType: ItemType.anime,
|
||||
query: _textEditingController.text,
|
||||
isLoading: _isLoading),
|
||||
if (!hideNovel)
|
||||
UpdateTab(
|
||||
itemType: ItemType.novel,
|
||||
query: _textEditingController.text,
|
||||
isLoading: _isLoading)
|
||||
]),
|
||||
),
|
||||
),
|
||||
|
|
@ -214,10 +257,10 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
|
|||
|
||||
class UpdateTab extends ConsumerStatefulWidget {
|
||||
final String query;
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
final bool isLoading;
|
||||
const UpdateTab(
|
||||
{required this.isManga,
|
||||
{required this.itemType,
|
||||
required this.query,
|
||||
required this.isLoading,
|
||||
super.key});
|
||||
|
|
@ -231,7 +274,7 @@ class _UpdateTabState extends ConsumerState<UpdateTab> {
|
|||
Widget build(BuildContext context) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
final update =
|
||||
ref.watch(getAllUpdateStreamProvider(isManga: widget.isManga));
|
||||
ref.watch(getAllUpdateStreamProvider(itemType: widget.itemType));
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import 'package:mangayomi/modules/widgets/cover_view_widget.dart';
|
|||
|
||||
class MangaImageCardWidget extends ConsumerWidget {
|
||||
final Source source;
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
final bool isComfortableGrid;
|
||||
final MManga? getMangaDetail;
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ class MangaImageCardWidget extends ConsumerWidget {
|
|||
super.key,
|
||||
required this.getMangaDetail,
|
||||
required this.isComfortableGrid,
|
||||
required this.isManga});
|
||||
required this.itemType});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -68,7 +68,7 @@ class MangaImageCardWidget extends ConsumerWidget {
|
|||
getManga: getMangaDetail!,
|
||||
lang: source.lang!,
|
||||
source: source.name!,
|
||||
isManga: isManga);
|
||||
itemType: itemType);
|
||||
},
|
||||
onLongPress: () {
|
||||
pushToMangaReaderDetail(
|
||||
|
|
@ -76,7 +76,7 @@ class MangaImageCardWidget extends ConsumerWidget {
|
|||
getManga: getMangaDetail!,
|
||||
lang: source.lang!,
|
||||
source: source.name!,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
addToFavourite: true);
|
||||
},
|
||||
onSecondaryTap: () {
|
||||
|
|
@ -85,7 +85,7 @@ class MangaImageCardWidget extends ConsumerWidget {
|
|||
getManga: getMangaDetail!,
|
||||
lang: source.lang!,
|
||||
source: source.name!,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
addToFavourite: true);
|
||||
},
|
||||
children: [
|
||||
|
|
@ -121,13 +121,13 @@ class MangaImageCardWidget extends ConsumerWidget {
|
|||
|
||||
class MangaImageCardListTileWidget extends ConsumerWidget {
|
||||
final Source source;
|
||||
final bool isManga;
|
||||
final ItemType itemType;
|
||||
final MManga? getMangaDetail;
|
||||
|
||||
const MangaImageCardListTileWidget(
|
||||
{required this.source,
|
||||
super.key,
|
||||
required this.isManga,
|
||||
required this.itemType,
|
||||
required this.getMangaDetail});
|
||||
|
||||
@override
|
||||
|
|
@ -166,7 +166,7 @@ class MangaImageCardListTileWidget extends ConsumerWidget {
|
|||
getManga: getMangaDetail!,
|
||||
lang: source.lang!,
|
||||
source: source.name!,
|
||||
isManga: isManga);
|
||||
itemType: itemType);
|
||||
},
|
||||
onLongPress: () {
|
||||
pushToMangaReaderDetail(
|
||||
|
|
@ -174,7 +174,7 @@ class MangaImageCardListTileWidget extends ConsumerWidget {
|
|||
getManga: getMangaDetail!,
|
||||
lang: source.lang!,
|
||||
source: source.name!,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
addToFavourite: true);
|
||||
},
|
||||
onSecondaryTap: () {
|
||||
|
|
@ -183,7 +183,7 @@ class MangaImageCardListTileWidget extends ConsumerWidget {
|
|||
getManga: getMangaDetail!,
|
||||
lang: source.lang!,
|
||||
source: source.name!,
|
||||
isManga: isManga,
|
||||
itemType: itemType,
|
||||
addToFavourite: true);
|
||||
},
|
||||
child: Row(
|
||||
|
|
@ -252,7 +252,7 @@ Future<void> pushToMangaReaderDetail(
|
|||
required String source,
|
||||
int? archiveId,
|
||||
Manga? mangaM,
|
||||
bool? isManga,
|
||||
ItemType? itemType,
|
||||
bool useMaterialRoute = false,
|
||||
bool addToFavourite = false}) async {
|
||||
int? mangaId;
|
||||
|
|
@ -269,7 +269,7 @@ Future<void> pushToMangaReaderDetail(
|
|||
source: source,
|
||||
lang: lang,
|
||||
lastUpdate: 0,
|
||||
isManga: isManga ?? true,
|
||||
itemType: itemType ?? ItemType.manga,
|
||||
artist: getManga.artist ?? '');
|
||||
final empty = isar.mangas
|
||||
.filter()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import 'package:isar/isar.dart';
|
|||
import 'package:mangayomi/eval/model/source_preference.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/category.dart';
|
||||
import 'package:mangayomi/models/changed_items.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/download.dart';
|
||||
import 'package:mangayomi/models/update.dart';
|
||||
|
|
@ -88,19 +87,29 @@ class StorageProvider {
|
|||
String scanlator = chapter.scanlator?.isNotEmpty ?? false
|
||||
? "${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();
|
||||
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);
|
||||
}
|
||||
|
||||
Future<Directory?> getMangaMainDirectory(Chapter chapter) async {
|
||||
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();
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +146,6 @@ class StorageProvider {
|
|||
|
||||
final isar = Isar.openSync([
|
||||
MangaSchema,
|
||||
ChangedItemsSchema,
|
||||
ChapterSchema,
|
||||
CategorySchema,
|
||||
UpdateSchema,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'package:bot_toast/bot_toast.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/models/track_preference.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/widgets/create_extension.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/more/backup_and_restore/backup_and_restore.dart';
|
||||
import 'package:mangayomi/modules/more/categories/categories_screen.dart';
|
||||
|
|
@ -86,12 +88,12 @@ class RouterNotifier extends ChangeNotifier {
|
|||
name: "MangaLibrary",
|
||||
path: '/MangaLibrary',
|
||||
builder: (context, state) => const LibraryScreen(
|
||||
isManga: true,
|
||||
itemType: ItemType.manga,
|
||||
),
|
||||
pageBuilder: (context, state) => transitionPage(
|
||||
key: state.pageKey,
|
||||
child: const LibraryScreen(
|
||||
isManga: true,
|
||||
itemType: ItemType.manga,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -99,12 +101,25 @@ class RouterNotifier extends ChangeNotifier {
|
|||
name: "AnimeLibrary",
|
||||
path: '/AnimeLibrary',
|
||||
builder: (context, state) => const LibraryScreen(
|
||||
isManga: false,
|
||||
itemType: ItemType.anime,
|
||||
),
|
||||
pageBuilder: (context, state) => transitionPage(
|
||||
key: state.pageKey,
|
||||
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(
|
||||
path: "/mangareaderview",
|
||||
name: "mangareaderview",
|
||||
path: "/mangaReaderView",
|
||||
name: "mangaReaderView",
|
||||
builder: (context, state) {
|
||||
final chapter = state.extra as Chapter;
|
||||
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(
|
||||
path: "/ExtensionLang",
|
||||
name: "ExtensionLang",
|
||||
|
|
|
|||
|
|
@ -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/services/fetch_sources_list.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
|
@ -13,6 +14,6 @@ Future fetchAnimeSourcesList(Ref ref, {int? id, required bool reFresh}) async {
|
|||
refresh: reFresh,
|
||||
id: id,
|
||||
ref: ref,
|
||||
isManga: false);
|
||||
itemType: ItemType.anime);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'fetch_anime_sources.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$fetchAnimeSourcesListHash() =>
|
||||
r'8fbe1642aee4d475583a1f04b2d236984c6fcfb4';
|
||||
r'75185e008e90491987fabb55851c536de89653a4';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -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/services/fetch_sources_list.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
|
@ -13,6 +14,6 @@ Future fetchMangaSourcesList(Ref ref, {int? id, required reFresh}) async {
|
|||
refresh: reFresh,
|
||||
id: id,
|
||||
ref: ref,
|
||||
isManga: true);
|
||||
itemType: ItemType.manga);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'fetch_manga_sources.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$fetchMangaSourcesListHash() =>
|
||||
r'8bc08c334cfdba887227c154e249355f33e69da4';
|
||||
r'f66f3011e72a3b234d7729ef203fc5f255870db3';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
20
lib/services/fetch_novel_sources.dart
Normal file
20
lib/services/fetch_novel_sources.dart
Normal 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);
|
||||
}
|
||||
}
|
||||
179
lib/services/fetch_novel_sources.g.dart
Normal file
179
lib/services/fetch_novel_sources.g.dart
Normal 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
|
||||
|
|
@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/eval/lib.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
|
||||
import 'package:mangayomi/services/http/m_client.dart';
|
||||
|
|
@ -13,7 +14,7 @@ Future<void> fetchSourcesList(
|
|||
required bool refresh,
|
||||
required String sourcesIndexUrl,
|
||||
required Ref ref,
|
||||
required bool isManga}) async {
|
||||
required ItemType itemType}) async {
|
||||
final http = MClient.init(reqcopyWith: {'useDartHttpClient': true});
|
||||
final req = await http.get(Uri.parse(sourcesIndexUrl));
|
||||
|
||||
|
|
@ -25,7 +26,7 @@ Future<void> fetchSourcesList(
|
|||
for (var source in sourceList) {
|
||||
if (source.appMinVerReq != null) {
|
||||
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 == source.id) {
|
||||
final sourc = isar.sources.getSync(id)!;
|
||||
|
|
@ -52,7 +53,7 @@ Future<void> fetchSourcesList(
|
|||
..name = source.name
|
||||
..version = source.version
|
||||
..versionLast = source.version
|
||||
..isManga = source.isManga
|
||||
..itemType = itemType
|
||||
..isFullData = source.isFullData ?? false
|
||||
..appMinVerReq = source.appMinVerReq
|
||||
..sourceCodeLanguage = source.sourceCodeLanguage
|
||||
|
|
@ -92,7 +93,7 @@ Future<void> fetchSourcesList(
|
|||
..name = source.name
|
||||
..version = source.version
|
||||
..versionLast = source.version
|
||||
..isManga = source.isManga
|
||||
..itemType = itemType
|
||||
..isFullData = source.isFullData ?? false
|
||||
..appMinVerReq = source.appMinVerReq
|
||||
..sourceCodeLanguage = source.sourceCodeLanguage
|
||||
|
|
@ -122,7 +123,7 @@ Future<void> fetchSourcesList(
|
|||
..name = source.name
|
||||
..version = source.version
|
||||
..versionLast = source.version
|
||||
..isManga = source.isManga
|
||||
..itemType = itemType
|
||||
..sourceCodeLanguage = source.sourceCodeLanguage
|
||||
..isFullData = source.isFullData ?? false
|
||||
..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
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.isMangaEqualTo(isManga)
|
||||
.itemTypeEqualTo(itemType)
|
||||
.findAllSync()) {
|
||||
if (sourceList.isNotEmpty && !(source.isLocal ?? false)) {
|
||||
final ids =
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'get_chapter_pages.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getChapterPagesHash() => r'8a2606a6640046cb006b24516bf88512f3204aca';
|
||||
String _$getChapterPagesHash() => r'5b18b20360abecf1125f27c32b10977dd18f1831';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
27
lib/services/get_html_content.dart
Normal file
27
lib/services/get_html_content.dart
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
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 '''<div id="readerViewContent"><div style="padding: 2em;">${html.substring(1, html.length - 1)}</div></div>'''
|
||||
.replaceAll("\\n", "")
|
||||
.replaceAll("\\t", "")
|
||||
.replaceAll("\\\"", "\"");
|
||||
}
|
||||
160
lib/services/get_html_content.g.dart
Normal file
160
lib/services/get_html_content.g.dart
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'get_html_content.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getHtmlContentHash() => r'0c964239912b7f93bfb4c80a47f7266ff1ae3f5e';
|
||||
|
||||
/// 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
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
import 'package:crypto/crypto.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/eval/model/m_bridge.dart';
|
||||
import 'package:mangayomi/eval/model/source_preference.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/changed_items.dart';
|
||||
import 'package:mangayomi/models/update.dart';
|
||||
import 'package:mangayomi/models/sync_preference.dart';
|
||||
import 'package:mangayomi/models/track.dart';
|
||||
|
|
@ -13,6 +11,7 @@ import 'package:mangayomi/models/chapter.dart';
|
|||
import 'package:mangayomi/models/history.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/modules/more/backup_and_restore/providers/restore.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/models/jwt.dart';
|
||||
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/providers/blend_level_state_provider.dart';
|
||||
|
|
@ -30,8 +29,6 @@ part 'sync_server.g.dart';
|
|||
class SyncServer extends _$SyncServer {
|
||||
final http = MClient.init(reqcopyWith: {'useDartHttpClient': true});
|
||||
final String _loginUrl = '/login';
|
||||
final String _checkUrl = '/check';
|
||||
final String _syncUrl = '/sync';
|
||||
final String _uploadUrl = '/upload/full';
|
||||
final String _downloadUrl = '/download';
|
||||
|
||||
|
|
@ -67,78 +64,6 @@ class SyncServer extends _$SyncServer {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> checkForSync(bool silent) async {
|
||||
if (!silent) {
|
||||
botToast("Checking for sync...", second: 2);
|
||||
}
|
||||
try {
|
||||
final datas = _getData();
|
||||
final accessToken = _getAccessToken();
|
||||
final localHash = _getDataHash(datas);
|
||||
|
||||
var response = await http.get(
|
||||
Uri.parse('${_getServer()}$_checkUrl'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $accessToken'
|
||||
},
|
||||
);
|
||||
if (response.statusCode != 200) {
|
||||
botToast("Check failed", second: 5);
|
||||
return;
|
||||
}
|
||||
var jsonData = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
final remoteHash = jsonData["hash"];
|
||||
if (localHash != remoteHash) {
|
||||
syncToServer(silent);
|
||||
} else if (!silent) {
|
||||
botToast("Sync up to date", second: 2);
|
||||
}
|
||||
} catch (error) {
|
||||
botToast(error.toString(), second: 5);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> syncToServer(bool silent) async {
|
||||
if (!silent) {
|
||||
botToast("Sync started...", second: 2);
|
||||
}
|
||||
try {
|
||||
final datas = _getData();
|
||||
final accessToken = _getAccessToken();
|
||||
|
||||
var response = await http.post(
|
||||
Uri.parse('${_getServer()}$_syncUrl'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $accessToken'
|
||||
},
|
||||
body: jsonEncode(
|
||||
{'backupData': datas, 'changedItems': _getChangedData()}),
|
||||
);
|
||||
if (response.statusCode != 200) {
|
||||
botToast("Sync failed", second: 5);
|
||||
return;
|
||||
}
|
||||
var jsonData = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
final decodedBackupData = jsonData["backupData"] is String
|
||||
? jsonDecode(jsonData["backupData"])
|
||||
: jsonData["backupData"];
|
||||
_restoreMerge(decodedBackupData);
|
||||
ref
|
||||
.read(synchingProvider(syncId: syncId).notifier)
|
||||
.setLastSync(DateTime.now().millisecondsSinceEpoch);
|
||||
ref
|
||||
.read(changedItemsManagerProvider(managerId: 1).notifier)
|
||||
.cleanChangedItems(true);
|
||||
if (!silent) {
|
||||
botToast("Sync finished", second: 2);
|
||||
}
|
||||
} catch (error) {
|
||||
botToast(error.toString(), second: 5);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> uploadToServer(AppLocalizations l10n) async {
|
||||
botToast(l10n.sync_uploading, second: 2);
|
||||
try {
|
||||
|
|
@ -160,9 +85,6 @@ class SyncServer extends _$SyncServer {
|
|||
ref
|
||||
.read(synchingProvider(syncId: syncId).notifier)
|
||||
.setLastUpload(DateTime.now().millisecondsSinceEpoch);
|
||||
ref
|
||||
.read(changedItemsManagerProvider(managerId: 1).notifier)
|
||||
.cleanChangedItems(true);
|
||||
botToast(l10n.sync_upload_finished, second: 2);
|
||||
} catch (error) {
|
||||
botToast(error.toString(), second: 5);
|
||||
|
|
@ -192,52 +114,15 @@ class SyncServer extends _$SyncServer {
|
|||
ref
|
||||
.read(synchingProvider(syncId: syncId).notifier)
|
||||
.setLastDownload(DateTime.now().millisecondsSinceEpoch);
|
||||
ref
|
||||
.read(changedItemsManagerProvider(managerId: 1).notifier)
|
||||
.cleanChangedItems(true);
|
||||
botToast(l10n.sync_download_finished, second: 2);
|
||||
} catch (error) {
|
||||
botToast(error.toString(), second: 5);
|
||||
}
|
||||
}
|
||||
|
||||
String _getDataHash(Map<String, dynamic> data) {
|
||||
Map<String, dynamic> datas = {};
|
||||
datas["version"] = data["version"];
|
||||
datas["manga"] = data["manga"];
|
||||
datas["categories"] = data["categories"];
|
||||
datas["chapters"] = data["chapters"];
|
||||
datas["tracks"] = data["tracks"];
|
||||
datas["history"] = data["history"];
|
||||
datas["updates"] = data["updates"];
|
||||
var encodedJson = jsonEncode(datas);
|
||||
return sha256.convert(utf8.encode(encodedJson)).toString();
|
||||
}
|
||||
|
||||
Map<String, dynamic> _getChangedData() {
|
||||
Map<String, dynamic> data = {};
|
||||
final changedItems = isar.changedItems.getSync(1);
|
||||
if (changedItems != null) {
|
||||
data.addAll({
|
||||
"deletedMangas":
|
||||
changedItems.deletedMangas?.map((e) => e.toJson()).toList() ?? []
|
||||
});
|
||||
data.addAll({
|
||||
"updatedChapters":
|
||||
changedItems.updatedChapters?.map((e) => e.toJson()).toList() ?? []
|
||||
});
|
||||
data.addAll({
|
||||
"deletedCategories":
|
||||
changedItems.deletedCategories?.map((e) => e.toJson()).toList() ??
|
||||
[]
|
||||
});
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
Map<String, dynamic> _getData() {
|
||||
Map<String, dynamic> datas = {};
|
||||
datas.addAll({"version": "1"});
|
||||
datas.addAll({"version": "2"});
|
||||
final mangas = isar.mangas
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
|
|
@ -309,208 +194,11 @@ class SyncServer extends _$SyncServer {
|
|||
return datas;
|
||||
}
|
||||
|
||||
void _restoreMerge(Map<String, dynamic> backup) {
|
||||
if (backup['version'] == "1") {
|
||||
try {
|
||||
final manga =
|
||||
(backup["manga"] as List?)?.map((e) => Manga.fromJson(e)).toList();
|
||||
final chapters = (backup["chapters"] as List?)
|
||||
?.map((e) => Chapter.fromJson(e))
|
||||
.toList();
|
||||
final categories = (backup["categories"] as List?)
|
||||
?.map((e) => Category.fromJson(e))
|
||||
.toList();
|
||||
final track =
|
||||
(backup["tracks"] as List?)?.map((e) => Track.fromJson(e)).toList();
|
||||
final history = (backup["history"] as List?)
|
||||
?.map((e) => History.fromJson(e))
|
||||
.toList();
|
||||
final updates = (backup["updates"] as List?)
|
||||
?.map((e) => Update.fromJson(e))
|
||||
.toList();
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
isar.mangas.clearSync();
|
||||
if (manga != null) {
|
||||
isar.mangas.putAllSync(manga);
|
||||
if (chapters != null) {
|
||||
isar.chapters.clearSync();
|
||||
for (var chapter in chapters) {
|
||||
final manga = isar.mangas.getSync(chapter.mangaId!);
|
||||
if (manga != null) {
|
||||
isar.chapters.putSync(chapter..manga.value = manga);
|
||||
chapter.manga.saveSync();
|
||||
}
|
||||
}
|
||||
|
||||
isar.historys.clearSync();
|
||||
if (history != null) {
|
||||
for (var element in history) {
|
||||
final chapter = isar.chapters.getSync(element.chapterId!);
|
||||
if (chapter != null) {
|
||||
isar.historys.putSync(element..chapter.value = chapter);
|
||||
element.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.updates.clearSync();
|
||||
if (updates != null) {
|
||||
final tempChapters =
|
||||
isar.chapters.filter().idIsNotNull().findAllSync().toList();
|
||||
for (var update in updates) {
|
||||
final matchingChapter = tempChapters
|
||||
.where((chapter) =>
|
||||
chapter.mangaId == update.mangaId &&
|
||||
chapter.name == update.chapterName)
|
||||
.firstOrNull;
|
||||
if (matchingChapter != null) {
|
||||
isar.updates
|
||||
.putSync(update..chapter.value = matchingChapter);
|
||||
update.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.categorys.clearSync();
|
||||
if (categories != null) {
|
||||
isar.categorys.putAllSync(categories);
|
||||
}
|
||||
}
|
||||
|
||||
isar.tracks.clearSync();
|
||||
if (track != null) {
|
||||
isar.tracks.putAllSync(track);
|
||||
}
|
||||
|
||||
ref.invalidate(themeModeStateProvider);
|
||||
ref.invalidate(blendLevelStateProvider);
|
||||
ref.invalidate(flexSchemeColorStateProvider);
|
||||
ref.invalidate(pureBlackDarkModeStateProvider);
|
||||
ref.invalidate(l10nLocaleStateProvider);
|
||||
});
|
||||
} catch (e) {
|
||||
botToast(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _restore(Map<String, dynamic> backup) {
|
||||
if (backup['version'] == "1") {
|
||||
try {
|
||||
final manga =
|
||||
(backup["manga"] as List?)?.map((e) => Manga.fromJson(e)).toList();
|
||||
final chapters = (backup["chapters"] as List?)
|
||||
?.map((e) => Chapter.fromJson(e))
|
||||
.toList();
|
||||
final categories = (backup["categories"] as List?)
|
||||
?.map((e) => Category.fromJson(e))
|
||||
.toList();
|
||||
final track =
|
||||
(backup["tracks"] as List?)?.map((e) => Track.fromJson(e)).toList();
|
||||
final history = (backup["history"] as List?)
|
||||
?.map((e) => History.fromJson(e))
|
||||
.toList();
|
||||
final settings = (backup["settings"] as List?)
|
||||
?.map((e) => Settings.fromJson(e))
|
||||
.toList();
|
||||
final extensions = (backup["extensions"] as List?)
|
||||
?.map((e) => Source.fromJson(e))
|
||||
.toList();
|
||||
final extensionsPref = (backup["extensions_preferences"] as List?)
|
||||
?.map((e) => SourcePreference.fromJson(e))
|
||||
.toList();
|
||||
final updates = (backup["updates"] as List?)
|
||||
?.map((e) => Update.fromJson(e))
|
||||
.toList();
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
isar.mangas.clearSync();
|
||||
if (manga != null) {
|
||||
isar.mangas.putAllSync(manga);
|
||||
if (chapters != null) {
|
||||
isar.chapters.clearSync();
|
||||
for (var chapter in chapters) {
|
||||
final manga = isar.mangas.getSync(chapter.mangaId!);
|
||||
if (manga != null) {
|
||||
isar.chapters.putSync(chapter..manga.value = manga);
|
||||
chapter.manga.saveSync();
|
||||
}
|
||||
}
|
||||
|
||||
isar.historys.clearSync();
|
||||
if (history != null) {
|
||||
for (var element in history) {
|
||||
final chapter = isar.chapters.getSync(element.chapterId!);
|
||||
if (chapter != null) {
|
||||
isar.historys.putSync(element..chapter.value = chapter);
|
||||
element.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.updates.clearSync();
|
||||
if (updates != null) {
|
||||
final tempChapters =
|
||||
isar.chapters.filter().idIsNotNull().findAllSync().toList();
|
||||
for (var update in updates) {
|
||||
final matchingChapter = tempChapters
|
||||
.where((chapter) =>
|
||||
chapter.mangaId == update.mangaId &&
|
||||
chapter.name == update.chapterName)
|
||||
.firstOrNull;
|
||||
if (matchingChapter != null) {
|
||||
isar.updates
|
||||
.putSync(update..chapter.value = matchingChapter);
|
||||
update.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.categorys.clearSync();
|
||||
if (categories != null) {
|
||||
isar.categorys.putAllSync(categories);
|
||||
}
|
||||
}
|
||||
|
||||
isar.tracks.clearSync();
|
||||
if (track != null) {
|
||||
isar.tracks.putAllSync(track);
|
||||
}
|
||||
|
||||
isar.sources.clearSync();
|
||||
if (extensions != null) {
|
||||
isar.sources.putAllSync(extensions);
|
||||
}
|
||||
|
||||
isar.sourcePreferences.clearSync();
|
||||
if (extensionsPref != null) {
|
||||
isar.sourcePreferences.putAllSync(extensionsPref);
|
||||
}
|
||||
final syncAfterReading = isar.settings.getSync(227)!.syncAfterReading;
|
||||
final syncOnAppLaunch = isar.settings.getSync(227)!.syncOnAppLaunch;
|
||||
isar.settings.clearSync();
|
||||
if (settings != null) {
|
||||
isar.settings.putAllSync(settings);
|
||||
}
|
||||
if (isar.settings.getSync(227) == null) {
|
||||
isar.settings.putSync(Settings(id: 227));
|
||||
}
|
||||
isar.settings.putSync(
|
||||
isar.settings.getSync(227)!..syncAfterReading = syncAfterReading);
|
||||
isar.settings.putSync(
|
||||
isar.settings.getSync(227)!..syncOnAppLaunch = syncOnAppLaunch);
|
||||
ref.invalidate(themeModeStateProvider);
|
||||
ref.invalidate(blendLevelStateProvider);
|
||||
ref.invalidate(flexSchemeColorStateProvider);
|
||||
ref.invalidate(pureBlackDarkModeStateProvider);
|
||||
ref.invalidate(l10nLocaleStateProvider);
|
||||
});
|
||||
} catch (e) {
|
||||
botToast(e.toString(), second: 5);
|
||||
}
|
||||
ref.watch(restoreV1Provider(backup));
|
||||
} else if (backup['version'] == "2") {
|
||||
ref.watch(restoreV2Provider(backup));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'sync_server.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$syncServerHash() => r'99e16d503937f2973f00c0cf2e834a03cf4aa245';
|
||||
String _$syncServerHash() => r'4ef01cd50d1ec4eaecd971fe2f176d2650147df8';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue