add novel support

This commit is contained in:
Schnitzel5 2024-11-24 19:49:57 +01:00
parent b2e25d26de
commit fb127f56b5
21 changed files with 349 additions and 97 deletions

View file

@ -1122,6 +1122,10 @@ Settings _settingsDeserialize(
libraryFilterMangasDownloadType: reader.readLongOrNull(offsets[53]), libraryFilterMangasDownloadType: reader.readLongOrNull(offsets[53]),
libraryFilterMangasStartedType: reader.readLongOrNull(offsets[54]), libraryFilterMangasStartedType: reader.readLongOrNull(offsets[54]),
libraryFilterMangasUnreadType: reader.readLongOrNull(offsets[55]), libraryFilterMangasUnreadType: reader.readLongOrNull(offsets[55]),
libraryFilterNovelBookMarkedType: reader.readLongOrNull(offsets[56]),
libraryFilterNovelDownloadType: reader.readLongOrNull(offsets[57]),
libraryFilterNovelStartedType: reader.readLongOrNull(offsets[58]),
libraryFilterNovelUnreadType: reader.readLongOrNull(offsets[59]),
libraryLocalSource: reader.readBoolOrNull(offsets[60]), libraryLocalSource: reader.readBoolOrNull(offsets[60]),
libraryShowCategoryTabs: reader.readBoolOrNull(offsets[61]), libraryShowCategoryTabs: reader.readBoolOrNull(offsets[61]),
libraryShowContinueReadingButton: reader.readBoolOrNull(offsets[62]), libraryShowContinueReadingButton: reader.readBoolOrNull(offsets[62]),
@ -1132,6 +1136,15 @@ Settings _settingsDeserialize(
reader.readByteOrNull(offsets[67])] ?? reader.readByteOrNull(offsets[67])] ??
DisplayType.comfortableGrid, DisplayType.comfortableGrid,
markEpisodeAsSeenType: reader.readLongOrNull(offsets[68]), markEpisodeAsSeenType: reader.readLongOrNull(offsets[68]),
novelDisplayType: _SettingsnovelDisplayTypeValueEnumMap[
reader.readByteOrNull(offsets[69])] ??
DisplayType.comfortableGrid,
novelLibraryDownloadedChapters: reader.readBoolOrNull(offsets[71]),
novelLibraryLocalSource: reader.readBoolOrNull(offsets[72]),
novelLibraryShowCategoryTabs: reader.readBoolOrNull(offsets[73]),
novelLibraryShowContinueReadingButton: reader.readBoolOrNull(offsets[74]),
novelLibraryShowLanguage: reader.readBoolOrNull(offsets[75]),
novelLibraryShowNumbersOfItems: reader.readBoolOrNull(offsets[76]),
onlyIncludePinnedSources: reader.readBoolOrNull(offsets[77]), onlyIncludePinnedSources: reader.readBoolOrNull(offsets[77]),
pagePreloadAmount: reader.readLongOrNull(offsets[78]), pagePreloadAmount: reader.readLongOrNull(offsets[78]),
personalPageModeList: reader.readObjectList<PersonalPageMode>( personalPageModeList: reader.readObjectList<PersonalPageMode>(
@ -1174,6 +1187,11 @@ Settings _settingsDeserialize(
SortLibraryMangaSchema.deserialize, SortLibraryMangaSchema.deserialize,
allOffsets, allOffsets,
), ),
sortLibraryNovel: reader.readObjectOrNull<SortLibraryManga>(
offsets[90],
SortLibraryMangaSchema.deserialize,
allOffsets,
),
startDatebackup: reader.readLongOrNull(offsets[91]), startDatebackup: reader.readLongOrNull(offsets[91]),
syncAfterReading: reader.readBoolOrNull(offsets[92]), syncAfterReading: reader.readBoolOrNull(offsets[92]),
syncOnAppLaunch: reader.readBoolOrNull(offsets[93]), syncOnAppLaunch: reader.readBoolOrNull(offsets[93]),
@ -1202,31 +1220,12 @@ Settings _settingsDeserialize(
allOffsets, allOffsets,
FilterScanlator(), FilterScanlator(),
); );
object.libraryFilterNovelBookMarkedType = reader.readLongOrNull(offsets[56]);
object.libraryFilterNovelDownloadType = reader.readLongOrNull(offsets[57]);
object.libraryFilterNovelStartedType = reader.readLongOrNull(offsets[58]);
object.libraryFilterNovelUnreadType = reader.readLongOrNull(offsets[59]);
object.locale = reader.readObjectOrNull<L10nLocale>( object.locale = reader.readObjectOrNull<L10nLocale>(
offsets[65], offsets[65],
L10nLocaleSchema.deserialize, L10nLocaleSchema.deserialize,
allOffsets, allOffsets,
); );
object.novelDisplayType = _SettingsnovelDisplayTypeValueEnumMap[
reader.readByteOrNull(offsets[69])] ??
DisplayType.compactGrid;
object.novelGridSize = reader.readLongOrNull(offsets[70]); object.novelGridSize = reader.readLongOrNull(offsets[70]);
object.novelLibraryDownloadedChapters = reader.readBoolOrNull(offsets[71]);
object.novelLibraryLocalSource = reader.readBoolOrNull(offsets[72]);
object.novelLibraryShowCategoryTabs = reader.readBoolOrNull(offsets[73]);
object.novelLibraryShowContinueReadingButton =
reader.readBoolOrNull(offsets[74]);
object.novelLibraryShowLanguage = reader.readBoolOrNull(offsets[75]);
object.novelLibraryShowNumbersOfItems = reader.readBoolOrNull(offsets[76]);
object.sortLibraryNovel = reader.readObjectOrNull<SortLibraryManga>(
offsets[90],
SortLibraryMangaSchema.deserialize,
allOffsets,
);
return object; return object;
} }
@ -1439,7 +1438,7 @@ P _settingsDeserializeProp<P>(
case 69: case 69:
return (_SettingsnovelDisplayTypeValueEnumMap[ return (_SettingsnovelDisplayTypeValueEnumMap[
reader.readByteOrNull(offset)] ?? reader.readByteOrNull(offset)] ??
DisplayType.compactGrid) as P; DisplayType.comfortableGrid) as P;
case 70: case 70:
return (reader.readLongOrNull(offset)) as P; return (reader.readLongOrNull(offset)) as P;
case 71: case 71:

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -34,7 +34,7 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen>
@override @override
void initState() { void initState() {
_tabBarController = TabController(length: 2, vsync: this); _tabBarController = TabController(length: 3, vsync: this);
_tabBarController.animateTo(0); _tabBarController.animateTo(0);
_tabBarController.addListener(() { _tabBarController.addListener(() {
setState(() { setState(() {

View file

@ -7,7 +7,7 @@ part of 'isar_providers.dart';
// ************************************************************************** // **************************************************************************
String _$getAllHistoryStreamHash() => String _$getAllHistoryStreamHash() =>
r'53b3a7837efab9e7d2808930e5070dbd788c59f8'; r'42048cb03035be55b52fc501fb2309cdb2acfcb8';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -161,7 +161,7 @@ class _GetAllHistoryStreamProviderElement
} }
String _$getAllUpdateStreamHash() => String _$getAllUpdateStreamHash() =>
r'01f77807c8be11f471b6acee6e7bc358ce600a65'; r'6a20f8feba3010c2ab7a80560f7a7f6cf10c7366';
/// See also [getAllUpdateStream]. /// See also [getAllUpdateStream].
@ProviderFor(getAllUpdateStream) @ProviderFor(getAllUpdateStream)

View file

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

View file

@ -6,7 +6,7 @@ part of 'isar_providers.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$getAllMangaStreamHash() => r'1c0b5442ae86b2fa899d509a555f5d375f0ff79a'; String _$getAllMangaStreamHash() => r'5e86a22a68ca1a52aefa9c0bc675d284369beac5';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -176,7 +176,7 @@ class _GetAllMangaStreamProviderElement
} }
String _$getAllMangaWithoutCategoriesStreamHash() => String _$getAllMangaWithoutCategoriesStreamHash() =>
r'78076f291274b7defd9567e55314002d9aeecab1'; r'61ea54070c7e87a45aeabce5fd21366faaf4ae6d';
/// See also [getAllMangaWithoutCategoriesStream]. /// See also [getAllMangaWithoutCategoriesStream].
@ProviderFor(getAllMangaWithoutCategoriesStream) @ProviderFor(getAllMangaWithoutCategoriesStream)

View file

@ -7,7 +7,7 @@ part of 'local_archive.dart';
// ************************************************************************** // **************************************************************************
String _$importArchivesFromFileHash() => String _$importArchivesFromFileHash() =>
r'8be95f0947ab5247e3305a355a6f17f0aaecad00'; r'8e6e592c927ad080e93d54dac1144ef8637a7e52';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {

View file

@ -43,10 +43,10 @@ class MainScreen extends ConsumerWidget {
int currentIndex = switch (location) { int currentIndex = switch (location) {
null || '/MangaLibrary' => 0, null || '/MangaLibrary' => 0,
'/AnimeLibrary' => 1, '/AnimeLibrary' => 1,
'/updates' => 2, '/NovelLibrary' => 2,
'/history' => 3, '/updates' => 3,
'/browse' => 4, '/history' => 4,
'/NovelLibrary' => 5, '/browse' => 5,
_ => 6, _ => 6,
}; };
@ -259,6 +259,12 @@ class MainScreen extends ConsumerWidget {
icon: const Icon( icon: const Icon(
Icons.video_collection_outlined), Icons.video_collection_outlined),
label: l10n.anime), label: l10n.anime),
NavigationDestination(
selectedIcon:
const Icon(Icons.local_library),
icon: const Icon(
Icons.local_library_outlined),
label: l10n.novel),
Stack( Stack(
children: [ children: [
NavigationDestination( NavigationDestination(
@ -298,9 +304,10 @@ class MainScreen extends ConsumerWidget {
final fn = switch (newIndex) { final fn = switch (newIndex) {
0 => route.go('/MangaLibrary'), 0 => route.go('/MangaLibrary'),
1 => route.go('/AnimeLibrary'), 1 => route.go('/AnimeLibrary'),
2 => route.go('/updates'), 2 => route.go('/NovelLibrary'),
3 => route.go('/history'), 3 => route.go('/updates'),
4 => route.go('/browse'), 4 => route.go('/history'),
5 => route.go('/browse'),
_ => route.go('/more'), _ => route.go('/more'),
}; };
fn; fn;

View file

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

View file

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

View file

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

View file

@ -22,7 +22,7 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen>
late TabController _tabBarController; late TabController _tabBarController;
@override @override
void initState() { void initState() {
_tabBarController = TabController(length: 2, vsync: this); _tabBarController = TabController(length: 3, vsync: this);
_tabBarController.animateTo(widget.data.$2); _tabBarController.animateTo(widget.data.$2);
super.initState(); super.initState();

View file

@ -7,7 +7,7 @@ part of 'isar_providers.dart';
// ************************************************************************** // **************************************************************************
String _$getMangaCategorieStreamHash() => String _$getMangaCategorieStreamHash() =>
r'97e90977f4696eedcf597c655a40dd6ccd47ed37'; r'1dcf15018a6467eef7a26c1728b9e531ebd984d0';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {

View file

@ -72,7 +72,7 @@ class _UpdatesScreenState extends ConsumerState<UpdatesScreen>
@override @override
void initState() { void initState() {
_tabBarController = TabController(length: 2, vsync: this); _tabBarController = TabController(length: 3, vsync: this);
_tabBarController.animateTo(0); _tabBarController.animateTo(0);
_tabBarController.addListener(() { _tabBarController.addListener(() {
setState(() { setState(() {

View file

@ -0,0 +1,19 @@
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://kodjodevf.github.io/mangayomi-extensions/index.json",
refresh: reFresh,
id: id,
ref: ref,
isManga: true);
}
}

View file

@ -0,0 +1,179 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'fetch_novel_sources.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$fetchNovelSourcesListHash() =>
r'110b23568136e32ebfba7e5414bdf524881a8579';
/// 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