add library category sort & selectable multiple for multiple action

This commit is contained in:
kodjomoustapha 2023-05-08 22:14:49 +01:00
parent 5b96bdea5c
commit c7b910c807
21 changed files with 2241 additions and 1753 deletions

View file

@ -31,7 +31,7 @@ class Manga {
int? lastUpdate; int? lastUpdate;
String? lastRead; int? lastRead;
List<int>? categories; List<int>? categories;
@ -53,6 +53,6 @@ class Manga {
this.dateAdded, this.dateAdded,
this.lastUpdate, this.lastUpdate,
this.categories, this.categories,
this.lastRead, this.lastRead = 0,
}); });
} }

View file

@ -60,7 +60,7 @@ const MangaSchema = CollectionSchema(
r'lastRead': PropertySchema( r'lastRead': PropertySchema(
id: 8, id: 8,
name: r'lastRead', name: r'lastRead',
type: IsarType.string, type: IsarType.long,
), ),
r'lastUpdate': PropertySchema( r'lastUpdate': PropertySchema(
id: 9, id: 9,
@ -158,12 +158,6 @@ int _mangaEstimateSize(
bytesCount += 3 + value.length * 3; bytesCount += 3 + value.length * 3;
} }
} }
{
final value = object.lastRead;
if (value != null) {
bytesCount += 3 + value.length * 3;
}
}
{ {
final value = object.link; final value = object.link;
if (value != null) { if (value != null) {
@ -205,7 +199,7 @@ void _mangaSerialize(
writer.writeStringList(offsets[5], object.genre); writer.writeStringList(offsets[5], object.genre);
writer.writeString(offsets[6], object.imageUrl); writer.writeString(offsets[6], object.imageUrl);
writer.writeString(offsets[7], object.lang); writer.writeString(offsets[7], object.lang);
writer.writeString(offsets[8], object.lastRead); writer.writeLong(offsets[8], object.lastRead);
writer.writeLong(offsets[9], object.lastUpdate); writer.writeLong(offsets[9], object.lastUpdate);
writer.writeString(offsets[10], object.link); writer.writeString(offsets[10], object.link);
writer.writeString(offsets[11], object.name); writer.writeString(offsets[11], object.name);
@ -229,7 +223,7 @@ Manga _mangaDeserialize(
id: id, id: id,
imageUrl: reader.readStringOrNull(offsets[6]), imageUrl: reader.readStringOrNull(offsets[6]),
lang: reader.readStringOrNull(offsets[7]), lang: reader.readStringOrNull(offsets[7]),
lastRead: reader.readStringOrNull(offsets[8]), lastRead: reader.readLongOrNull(offsets[8]),
lastUpdate: reader.readLongOrNull(offsets[9]), lastUpdate: reader.readLongOrNull(offsets[9]),
link: reader.readStringOrNull(offsets[10]), link: reader.readStringOrNull(offsets[10]),
name: reader.readStringOrNull(offsets[11]), name: reader.readStringOrNull(offsets[11]),
@ -263,7 +257,7 @@ P _mangaDeserializeProp<P>(
case 7: case 7:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 8: case 8:
return (reader.readStringOrNull(offset)) as P; return (reader.readLongOrNull(offset)) as P;
case 9: case 9:
return (reader.readLongOrNull(offset)) as P; return (reader.readLongOrNull(offset)) as P;
case 10: case 10:
@ -1497,54 +1491,46 @@ extension MangaQueryFilter on QueryBuilder<Manga, Manga, QFilterCondition> {
} }
QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadEqualTo( QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadEqualTo(
String? value, { int? value) {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo( return query.addFilterCondition(FilterCondition.equalTo(
property: r'lastRead', property: r'lastRead',
value: value, value: value,
caseSensitive: caseSensitive,
)); ));
}); });
} }
QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadGreaterThan( QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadGreaterThan(
String? value, { int? value, {
bool include = false, bool include = false,
bool caseSensitive = true,
}) { }) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan( return query.addFilterCondition(FilterCondition.greaterThan(
include: include, include: include,
property: r'lastRead', property: r'lastRead',
value: value, value: value,
caseSensitive: caseSensitive,
)); ));
}); });
} }
QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadLessThan( QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadLessThan(
String? value, { int? value, {
bool include = false, bool include = false,
bool caseSensitive = true,
}) { }) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan( return query.addFilterCondition(FilterCondition.lessThan(
include: include, include: include,
property: r'lastRead', property: r'lastRead',
value: value, value: value,
caseSensitive: caseSensitive,
)); ));
}); });
} }
QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadBetween( QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadBetween(
String? lower, int? lower,
String? upper, { int? upper, {
bool includeLower = true, bool includeLower = true,
bool includeUpper = true, bool includeUpper = true,
bool caseSensitive = true,
}) { }) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between( return query.addFilterCondition(FilterCondition.between(
@ -1553,75 +1539,6 @@ extension MangaQueryFilter on QueryBuilder<Manga, Manga, QFilterCondition> {
includeLower: includeLower, includeLower: includeLower,
upper: upper, upper: upper,
includeUpper: includeUpper, includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'lastRead',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'lastRead',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadContains(
String value,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'lastRead',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadMatches(
String pattern,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'lastRead',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'lastRead',
value: '',
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> lastReadIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'lastRead',
value: '',
)); ));
}); });
} }
@ -2691,10 +2608,9 @@ extension MangaQueryWhereDistinct on QueryBuilder<Manga, Manga, QDistinct> {
}); });
} }
QueryBuilder<Manga, Manga, QDistinct> distinctByLastRead( QueryBuilder<Manga, Manga, QDistinct> distinctByLastRead() {
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'lastRead', caseSensitive: caseSensitive); return query.addDistinctBy(r'lastRead');
}); });
} }
@ -2788,7 +2704,7 @@ extension MangaQueryProperty on QueryBuilder<Manga, Manga, QQueryProperty> {
}); });
} }
QueryBuilder<Manga, String?, QQueryOperations> lastReadProperty() { QueryBuilder<Manga, int?, QQueryOperations> lastReadProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'lastRead'); return query.addPropertyName(r'lastRead');
}); });

View file

@ -1,6 +1,9 @@
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:go_router/go_router.dart'; 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/manga.dart';
import 'package:mangayomi/providers/hive_provider.dart'; import 'package:mangayomi/providers/hive_provider.dart';
import 'package:mangayomi/services/get_manga_detail.dart'; import 'package:mangayomi/services/get_manga_detail.dart';
@ -180,24 +183,48 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
data: (data) { data: (data) {
return GestureDetector( return GestureDetector(
onTap: () async { onTap: () async {
final modelManga = Manga( final manga = Manga(
imageUrl: data.imageUrl, imageUrl: data.imageUrl,
name: data.name, name: data.name,
genre: data.genre, genre: data.genre,
author: data.author, author: data.author,
status: data.status, status: data.status,
description: data.description, description: data.description,
favorite: false,
link: data.url, link: data.url,
source: data.source, source: data.source,
lang: widget.lang, lang: widget.lang,
dateAdded: DateTime.now().microsecondsSinceEpoch, lastUpdate: DateTime.now().millisecondsSinceEpoch);
lastUpdate: DateTime.now().microsecondsSinceEpoch,
categories: null, final empty = isar.mangas
lastRead: ''); .filter()
if (mounted) { .langEqualTo(widget.lang)
context.push('/manga-reader/detail', extra: modelManga); .nameEqualTo(data.name)
.sourceEqualTo(data.source)
.isEmptySync();
if (empty) {
isar.writeTxnSync(() {
isar.mangas.putSync(manga);
for (var i = 0; i < data.chapters.length; i++) {
final chapters = Chapter(
name: data.chapters[i].name,
url: data.chapters[i].url,
dateUpload: data.chapters[i].dateUpload,
scanlator: data.chapters[i].scanlator,
mangaId: manga.id)
..manga.value = manga;
isar.chapters.putSync(chapters);
chapters.manga.saveSync();
}
});
} }
final mangaId = isar.mangas
.filter()
.langEqualTo(widget.lang)
.nameEqualTo(data.name)
.sourceEqualTo(data.source)
.findFirstSync()!
.id!;
context.push('/manga-reader/detail', extra: mangaId);
}, },
child: SizedBox( child: SizedBox(
width: 90, width: 90,

View file

@ -6,6 +6,7 @@ import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:mangayomi/utils/colors.dart'; import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/media_query.dart'; import 'package:mangayomi/utils/media_query.dart';
import 'package:mangayomi/views/library/providers/library_state_provider.dart';
import 'package:mangayomi/views/more/settings/providers/incognito_mode_state_provider.dart'; import 'package:mangayomi/views/more/settings/providers/incognito_mode_state_provider.dart';
class GeneralScreen extends StatefulWidget { class GeneralScreen extends StatefulWidget {
@ -68,87 +69,93 @@ class _GeneralScreenState extends State<GeneralScreen> {
Flexible( Flexible(
child: Scaffold( child: Scaffold(
body: widget.child, body: widget.child,
bottomNavigationBar: SizedBox( bottomNavigationBar: Consumer(builder: (context, ref, child) {
width: mediaWidth(context, 1), final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
height: route.location != '/library' && return AnimatedContainer(
route.location != '/updates' && duration: const Duration(milliseconds: 300),
route.location != '/history' && width: mediaWidth(context, 1),
route.location != '/browse' && height: isLongPressed
route.location != '/more' ? 0
? 0 : route.location != '/library' &&
: 80, route.location != '/updates' &&
child: NavigationBarTheme( route.location != '/history' &&
data: NavigationBarThemeData( route.location != '/browse' &&
indicatorShape: RoundedRectangleBorder( route.location != '/more'
borderRadius: BorderRadius.circular(30)), ? 0
height: 20, : 80,
child: NavigationBarTheme(
data: NavigationBarThemeData(
indicatorShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30)),
height: 20,
),
child: NavigationBar(
animationDuration: const Duration(milliseconds: 500),
selectedIndex: currentIndex,
destinations: const [
NavigationDestination(
selectedIcon: Icon(
Icons.collections_bookmark,
),
icon: Icon(
Icons.collections_bookmark_outlined,
),
label: 'Library'),
NavigationDestination(
selectedIcon: Icon(
Icons.new_releases,
),
icon: Icon(
Icons.new_releases_outlined,
),
label: 'Updates'),
NavigationDestination(
selectedIcon: Icon(
Icons.history,
),
icon: Icon(
Icons.history_outlined,
),
label: "History"),
NavigationDestination(
selectedIcon: Icon(
Icons.explore,
),
icon: Icon(
Icons.explore_outlined,
),
label: "Browse"),
NavigationDestination(
selectedIcon: Icon(
Icons.more_horiz,
),
icon: Icon(
Icons.more_horiz_outlined,
),
label: "More"),
],
onDestinationSelected: (int newIndex) {
if (mounted) {
setState(() {
currentIndex = newIndex;
});
}
if (newIndex == 0) {
route.go('/library');
} else if (newIndex == 1) {
route.go('/updates');
} else if (newIndex == 2) {
route.go('/history');
} else if (newIndex == 3) {
route.go('/browse');
} else if (newIndex == 4) {
route.go('/more');
}
},
),
), ),
child: NavigationBar( );
animationDuration: const Duration(milliseconds: 500), }),
selectedIndex: currentIndex,
destinations: const [
NavigationDestination(
selectedIcon: Icon(
Icons.collections_bookmark,
),
icon: Icon(
Icons.collections_bookmark_outlined,
),
label: 'Library'),
NavigationDestination(
selectedIcon: Icon(
Icons.new_releases,
),
icon: Icon(
Icons.new_releases_outlined,
),
label: 'Updates'),
NavigationDestination(
selectedIcon: Icon(
Icons.history,
),
icon: Icon(
Icons.history_outlined,
),
label: "History"),
NavigationDestination(
selectedIcon: Icon(
Icons.explore,
),
icon: Icon(
Icons.explore_outlined,
),
label: "Browse"),
NavigationDestination(
selectedIcon: Icon(
Icons.more_horiz,
),
icon: Icon(
Icons.more_horiz_outlined,
),
label: "More"),
],
onDestinationSelected: (int newIndex) {
if (mounted) {
setState(() {
currentIndex = newIndex;
});
}
if (newIndex == 0) {
route.go('/library');
} else if (newIndex == 1) {
route.go('/updates');
} else if (newIndex == 2) {
route.go('/history');
} else if (newIndex == 3) {
route.go('/browse');
} else if (newIndex == 4) {
route.go('/more');
}
},
),
),
),
), ),
), ),
], ],

File diff suppressed because it is too large Load diff

View file

@ -111,7 +111,7 @@ class GetAllMangaStreamProvider extends AutoDisposeStreamProvider<List<Manga>> {
} }
String _$getAllMangaWithoutCategoriesStreamHash() => String _$getAllMangaWithoutCategoriesStreamHash() =>
r'76230abaa3a6394c56b3ec90b6a4af812f6ebfb5'; r'6fc216e2a14edb3a0323b358ef3749a75007e8b5';
/// See also [getAllMangaWithoutCategoriesStream]. /// See also [getAllMangaWithoutCategoriesStream].
@ProviderFor(getAllMangaWithoutCategoriesStream) @ProviderFor(getAllMangaWithoutCategoriesStream)

View file

@ -1,25 +1,10 @@
import 'dart:developer'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/providers/hive_provider.dart'; import 'package:mangayomi/providers/hive_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'library_state_provider.g.dart'; part 'library_state_provider.g.dart';
@riverpod
class LibraryReverseListState extends _$LibraryReverseListState {
@override
bool build() {
return ref
.watch(hiveBoxSettingsProvider)
.get('libraryReverseList', defaultValue: false)!;
}
void set(bool value) {
state = value;
ref.watch(hiveBoxSettingsProvider).put('libraryReverseList', value);
}
}
@riverpod @riverpod
class LibraryDisplayTypeState extends _$LibraryDisplayTypeState { class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
@override @override
@ -139,7 +124,7 @@ class MangaFilterUnreadState extends _$MangaFilterUnreadState {
} }
} }
update() { update() {
if (state == 0) { if (state == 0) {
final data = mangaList.where((element) { final data = mangaList.where((element) {
List list = []; List list = [];
@ -425,3 +410,132 @@ class LibraryShowContinueReadingButtonState
.put('libraryShowContinueReadingButton', value); .put('libraryShowContinueReadingButton', value);
} }
} }
@riverpod
class SortLibraryMangaState extends _$SortLibraryMangaState {
@override
dynamic build() {
return ref.watch(hiveBoxSettingsProvider).get("sortLibraryMangaMap",
defaultValue: {"reverse": false, "index": 2});
}
void update(bool reverse, int index) {
var value = {
"reverse": state['index'] == index ? !reverse : reverse,
"index": index
};
ref.watch(hiveBoxSettingsProvider).put("sortLibraryMangaMap", value);
state = value;
}
void set(int index) {
final reverse = isReverse();
update(reverse, index);
}
bool isReverse() {
return state["reverse"];
}
}
@riverpod
class MangasListState extends _$MangasListState {
@override
List<int> build() {
return [];
}
void update(Manga value) {
var newList = state.reversed.toList();
if (newList.contains(value.id)) {
newList.remove(value.id);
} else {
newList.add(value.id!);
}
if (newList.isEmpty) {
ref.read(isLongPressedMangaStateProvider.notifier).update(false);
}
state = newList;
}
void selectAll(Manga value) {
var newList = state.reversed.toList();
if (!newList.contains(value.id)) {
newList.add(value.id!);
}
state = newList;
}
void selectSome(Manga value) {
var newList = state.reversed.toList();
if (newList.contains(value.id)) {
newList.remove(value.id);
} else {
newList.add(value.id!);
}
state = newList;
}
void clear() {
state = [];
}
}
@riverpod
class IsLongPressedMangaState extends _$IsLongPressedMangaState {
@override
bool build() {
return false;
}
void update(bool value) {
state = value;
}
}
@riverpod
class MangasSetIsReadState extends _$MangasSetIsReadState {
@override
build({required List<int> mangaIds}) {}
set() {
for (var mangaid in mangaIds) {
final manga = isar.mangas.getSync(mangaid)!;
final chapters = manga.chapters;
isar.writeTxnSync(() {
for (var chapter in chapters) {
chapter.isRead = true;
isar.chapters.putSync(chapter..manga.value = manga);
chapter.manga.saveSync();
}
});
}
ref.read(isLongPressedMangaStateProvider.notifier).update(false);
ref.read(mangasListStateProvider.notifier).clear();
}
}
@riverpod
class MangasSetUnReadState extends _$MangasSetUnReadState {
@override
build({required List<int> mangaIds}) {}
set() {
for (var mangaid in mangaIds) {
final manga = isar.mangas.getSync(mangaid)!;
final chapters = manga.chapters;
isar.writeTxnSync(() {
for (var chapter in chapters) {
chapter.isRead = false;
isar.chapters.putSync(chapter..manga.value = manga);
chapter.manga.saveSync();
}
});
}
ref.read(isLongPressedMangaStateProvider.notifier).update(false);
ref.read(mangasListStateProvider.notifier).clear();
}
}

View file

@ -6,23 +6,6 @@ part of 'library_state_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$libraryReverseListStateHash() =>
r'5d9037f95ffe332019dd1d3d08b0db06d798738c';
/// See also [LibraryReverseListState].
@ProviderFor(LibraryReverseListState)
final libraryReverseListStateProvider =
AutoDisposeNotifierProvider<LibraryReverseListState, bool>.internal(
LibraryReverseListState.new,
name: r'libraryReverseListStateProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$libraryReverseListStateHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$LibraryReverseListState = AutoDisposeNotifier<bool>;
String _$libraryDisplayTypeStateHash() => String _$libraryDisplayTypeStateHash() =>
r'746bd6dac3600802c3ab5751b3c1def881274b3a'; r'746bd6dac3600802c3ab5751b3c1def881274b3a';
@ -642,4 +625,249 @@ final libraryShowContinueReadingButtonStateProvider =
); );
typedef _$LibraryShowContinueReadingButtonState = AutoDisposeNotifier<bool>; typedef _$LibraryShowContinueReadingButtonState = AutoDisposeNotifier<bool>;
String _$sortLibraryMangaStateHash() =>
r'81abfe6c2841cf7b25301928d88f8af80cd480fd';
/// See also [SortLibraryMangaState].
@ProviderFor(SortLibraryMangaState)
final sortLibraryMangaStateProvider =
AutoDisposeNotifierProvider<SortLibraryMangaState, dynamic>.internal(
SortLibraryMangaState.new,
name: r'sortLibraryMangaStateProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$sortLibraryMangaStateHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$SortLibraryMangaState = AutoDisposeNotifier<dynamic>;
String _$mangasListStateHash() => r'ad1cc419dfd3793bfc8c90f3ce8b7726561dd9ad';
/// See also [MangasListState].
@ProviderFor(MangasListState)
final mangasListStateProvider =
AutoDisposeNotifierProvider<MangasListState, List<int>>.internal(
MangasListState.new,
name: r'mangasListStateProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$mangasListStateHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$MangasListState = AutoDisposeNotifier<List<int>>;
String _$isLongPressedMangaStateHash() =>
r'f77076b0335e92df26a75ea0c338d4214a330184';
/// See also [IsLongPressedMangaState].
@ProviderFor(IsLongPressedMangaState)
final isLongPressedMangaStateProvider =
AutoDisposeNotifierProvider<IsLongPressedMangaState, bool>.internal(
IsLongPressedMangaState.new,
name: r'isLongPressedMangaStateProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$isLongPressedMangaStateHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$IsLongPressedMangaState = AutoDisposeNotifier<bool>;
String _$mangasSetIsReadStateHash() =>
r'240a9a3e317e3b2a42fd5babe906699e8869ae0a';
abstract class _$MangasSetIsReadState
extends BuildlessAutoDisposeNotifier<dynamic> {
late final List<int> mangaIds;
dynamic build({
required List<int> mangaIds,
});
}
/// See also [MangasSetIsReadState].
@ProviderFor(MangasSetIsReadState)
const mangasSetIsReadStateProvider = MangasSetIsReadStateFamily();
/// See also [MangasSetIsReadState].
class MangasSetIsReadStateFamily extends Family<dynamic> {
/// See also [MangasSetIsReadState].
const MangasSetIsReadStateFamily();
/// See also [MangasSetIsReadState].
MangasSetIsReadStateProvider call({
required List<int> mangaIds,
}) {
return MangasSetIsReadStateProvider(
mangaIds: mangaIds,
);
}
@override
MangasSetIsReadStateProvider getProviderOverride(
covariant MangasSetIsReadStateProvider provider,
) {
return call(
mangaIds: provider.mangaIds,
);
}
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'mangasSetIsReadStateProvider';
}
/// See also [MangasSetIsReadState].
class MangasSetIsReadStateProvider
extends AutoDisposeNotifierProviderImpl<MangasSetIsReadState, dynamic> {
/// See also [MangasSetIsReadState].
MangasSetIsReadStateProvider({
required this.mangaIds,
}) : super.internal(
() => MangasSetIsReadState()..mangaIds = mangaIds,
from: mangasSetIsReadStateProvider,
name: r'mangasSetIsReadStateProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$mangasSetIsReadStateHash,
dependencies: MangasSetIsReadStateFamily._dependencies,
allTransitiveDependencies:
MangasSetIsReadStateFamily._allTransitiveDependencies,
);
final List<int> mangaIds;
@override
bool operator ==(Object other) {
return other is MangasSetIsReadStateProvider && other.mangaIds == mangaIds;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, mangaIds.hashCode);
return _SystemHash.finish(hash);
}
@override
dynamic runNotifierBuild(
covariant MangasSetIsReadState notifier,
) {
return notifier.build(
mangaIds: mangaIds,
);
}
}
String _$mangasSetUnReadStateHash() =>
r'0494afb9a17a0e4346e182cc2944341174348514';
abstract class _$MangasSetUnReadState
extends BuildlessAutoDisposeNotifier<dynamic> {
late final List<int> mangaIds;
dynamic build({
required List<int> mangaIds,
});
}
/// See also [MangasSetUnReadState].
@ProviderFor(MangasSetUnReadState)
const mangasSetUnReadStateProvider = MangasSetUnReadStateFamily();
/// See also [MangasSetUnReadState].
class MangasSetUnReadStateFamily extends Family<dynamic> {
/// See also [MangasSetUnReadState].
const MangasSetUnReadStateFamily();
/// See also [MangasSetUnReadState].
MangasSetUnReadStateProvider call({
required List<int> mangaIds,
}) {
return MangasSetUnReadStateProvider(
mangaIds: mangaIds,
);
}
@override
MangasSetUnReadStateProvider getProviderOverride(
covariant MangasSetUnReadStateProvider provider,
) {
return call(
mangaIds: provider.mangaIds,
);
}
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'mangasSetUnReadStateProvider';
}
/// See also [MangasSetUnReadState].
class MangasSetUnReadStateProvider
extends AutoDisposeNotifierProviderImpl<MangasSetUnReadState, dynamic> {
/// See also [MangasSetUnReadState].
MangasSetUnReadStateProvider({
required this.mangaIds,
}) : super.internal(
() => MangasSetUnReadState()..mangaIds = mangaIds,
from: mangasSetUnReadStateProvider,
name: r'mangasSetUnReadStateProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$mangasSetUnReadStateHash,
dependencies: MangasSetUnReadStateFamily._dependencies,
allTransitiveDependencies:
MangasSetUnReadStateFamily._allTransitiveDependencies,
);
final List<int> mangaIds;
@override
bool operator ==(Object other) {
return other is MangasSetUnReadStateProvider && other.mangaIds == mangaIds;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, mangaIds.hashCode);
return _SystemHash.finish(hash);
}
@override
dynamic runNotifierBuild(
covariant MangasSetUnReadState notifier,
) {
return notifier.build(
mangaIds: mangaIds,
);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions

View file

@ -3,6 +3,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import 'package:mangayomi/views/history/providers/isar_providers.dart'; import 'package:mangayomi/views/history/providers/isar_providers.dart';
import 'package:mangayomi/views/library/providers/library_state_provider.dart';
import 'package:mangayomi/views/manga/detail/providers/state_providers.dart';
import 'package:mangayomi/views/manga/reader/providers/push_router.dart'; import 'package:mangayomi/views/manga/reader/providers/push_router.dart';
import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/providers/hive_provider.dart'; import 'package:mangayomi/providers/hive_provider.dart';
@ -19,6 +21,7 @@ import 'package:mangayomi/views/widgets/progress_center.dart';
class LibraryGridViewWidget extends StatelessWidget { class LibraryGridViewWidget extends StatelessWidget {
final bool isCoverOnlyGrid; final bool isCoverOnlyGrid;
final bool isComfortableGrid; final bool isComfortableGrid;
final List<int> mangaIdsList;
final List<Manga> entriesManga; final List<Manga> entriesManga;
final bool language; final bool language;
final bool downloadedChapter; final bool downloadedChapter;
@ -30,7 +33,8 @@ class LibraryGridViewWidget extends StatelessWidget {
this.isComfortableGrid = false, this.isComfortableGrid = false,
required this.language, required this.language,
required this.downloadedChapter, required this.downloadedChapter,
required this.continueReaderBtn}); required this.continueReaderBtn,
required this.mangaIdsList});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -38,214 +42,259 @@ class LibraryGridViewWidget extends StatelessWidget {
mainAxisExtent: isComfortableGrid ? 310 : 280, mainAxisExtent: isComfortableGrid ? 310 : 280,
itemCount: entriesManga.length, itemCount: entriesManga.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return GestureDetector( return Consumer(builder: (context, ref, child) {
onTap: () { final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
context.push('/manga-reader/detail', extra: entriesManga[index].id); return Padding(
}, padding: const EdgeInsets.all(2),
child: CoverViewWidget( child: ElevatedButton(
bottomTextWidget: BottomTextWidget( style: ElevatedButton.styleFrom(
text: entriesManga[index].name!, padding: const EdgeInsets.all(0),
isComfortableGrid: isComfortableGrid, backgroundColor: mangaIdsList.contains(entriesManga[index].id)
), ? primaryColor(context).withOpacity(0.4)
isComfortableGrid: isComfortableGrid, : Colors.transparent,
children: [ shape: RoundedRectangleBorder(
Stack( borderRadius: BorderRadius.circular(5)),
elevation: 0,
shadowColor: Colors.transparent),
onPressed: () {
if (isLongPressed) {
ref
.read(mangasListStateProvider.notifier)
.update(entriesManga[index]);
} else {
context.push('/manga-reader/detail',
extra: entriesManga[index].id);
}
},
onLongPress: () {
if (!isLongPressed) {
ref
.read(mangasListStateProvider.notifier)
.update(entriesManga[index]);
ref
.read(isLongPressedMangaStateProvider.notifier)
.update(!isLongPressed);
} else {
ref
.read(mangasListStateProvider.notifier)
.update(entriesManga[index]);
}
},
child: CoverViewWidget(
bottomTextWidget: BottomTextWidget(
text: entriesManga[index].name!,
isComfortableGrid: isComfortableGrid,
),
isComfortableGrid: isComfortableGrid,
children: [ children: [
cachedNetworkImage( Stack(
headers: headers(entriesManga[index].source!), children: [
imageUrl: entriesManga[index].imageUrl!, cachedNetworkImage(
width: 200, headers: headers(entriesManga[index].source!),
height: 270, imageUrl: entriesManga[index].imageUrl!,
fit: BoxFit.cover), width: 200,
Positioned( height: 270,
top: 0, fit: BoxFit.cover),
left: 0, Positioned(
child: Padding( top: 0,
padding: const EdgeInsets.all(5), left: 0,
child: Container( child: Padding(
decoration: BoxDecoration( padding: const EdgeInsets.all(5),
borderRadius: BorderRadius.circular(3),
color: primaryColor(context),
),
child: Row(
children: [
if (downloadedChapter)
Padding(
padding: const EdgeInsets.only(right: 5),
child: Consumer(
builder: (context, ref, child) {
List nbrDown = [];
for (var i = 0;
i <
entriesManga[index]
.chapters
.length;
i++) {
final entries = ref
.watch(
hiveBoxMangaDownloadsProvider)
.values
.where((element) =>
element.chapterName ==
entriesManga[index]
.chapters
.toList()[i]
.name)
.toList();
if (entries.isNotEmpty &&
entries.first.isDownload) {
nbrDown.add(entries.first);
}
}
if (nbrDown.isNotEmpty) {
return Container(
decoration: BoxDecoration(
borderRadius:
const BorderRadius.only(
topLeft: Radius.circular(3),
bottomLeft:
Radius.circular(3)),
color: Theme.of(context).hintColor,
),
child: Padding(
padding: const EdgeInsets.only(
left: 3, right: 3),
child: Text(
nbrDown.length.toString(),
style: const TextStyle(
color: Colors.white),
),
),
);
} else {
return Container();
}
},
),
),
Padding(
padding: const EdgeInsets.only(right: 3),
child: Text(
entriesManga[index]
.chapters
.length
.toString(),
style: const TextStyle(color: Colors.white),
),
),
],
),
),
)),
if (language)
Positioned(
top: 0,
right: 0,
child: Padding(
padding: const EdgeInsets.all(5),
child: Container(
color: primaryColor(context),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.only( borderRadius: BorderRadius.circular(3),
topLeft: Radius.circular(3), color: primaryColor(context),
bottomLeft: Radius.circular(3)),
color: Theme.of(context).hintColor,
), ),
child: Padding( child: Row(
padding: children: [
const EdgeInsets.only(left: 3, right: 3), if (downloadedChapter)
child: Text( Padding(
entriesManga[index].lang!.toUpperCase(), padding: const EdgeInsets.only(right: 5),
style: const TextStyle(color: Colors.white), child: Consumer(
), builder: (context, ref, child) {
List nbrDown = [];
for (var i = 0;
i <
entriesManga[index]
.chapters
.length;
i++) {
final entries = ref
.watch(
hiveBoxMangaDownloadsProvider)
.values
.where((element) =>
element.chapterName ==
entriesManga[index]
.chapters
.toList()[i]
.name)
.toList();
if (entries.isNotEmpty &&
entries.first.isDownload) {
nbrDown.add(entries.first);
}
}
if (nbrDown.isNotEmpty) {
return Container(
decoration: BoxDecoration(
borderRadius:
const BorderRadius.only(
topLeft:
Radius.circular(3),
bottomLeft:
Radius.circular(3)),
color:
Theme.of(context).hintColor,
),
child: Padding(
padding: const EdgeInsets.only(
left: 3, right: 3),
child: Text(
nbrDown.length.toString(),
style: const TextStyle(
color: Colors.white),
),
),
);
} else {
return Container();
}
},
),
),
Padding(
padding: const EdgeInsets.only(right: 3),
child: Text(
entriesManga[index]
.chapters
.length
.toString(),
style:
const TextStyle(color: Colors.white),
),
),
],
), ),
), ),
), )),
)), if (language)
], Positioned(
), top: 0,
if (!isComfortableGrid) right: 0,
if (!isCoverOnlyGrid) child: Padding(
BottomTextWidget(text: entriesManga[index].name!), padding: const EdgeInsets.all(5),
if (continueReaderBtn) child: Container(
Positioned( color: primaryColor(context),
bottom: 0, child: Container(
right: 0, decoration: BoxDecoration(
child: Padding( borderRadius: const BorderRadius.only(
padding: const EdgeInsets.all(9), topLeft: Radius.circular(3),
child: Consumer( bottomLeft: Radius.circular(3)),
builder: (context, ref, child) { color: Theme.of(context).hintColor,
final history =
ref.watch(getAllHistoryStreamProvider);
return history.when(
data: (data) {
final incognitoMode =
ref.watch(incognitoModeStateProvider);
final entries = data
.where((element) =>
element.mangaId ==
entriesManga[index].id)
.toList();
if (entries.isNotEmpty && !incognitoMode) {
return GestureDetector(
onTap: () {
pushMangaReaderView(
context: context,
chapter: entries.first.chapter.value!,
);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: primaryColor(context)
.withOpacity(0.9),
),
child: const Padding(
padding: EdgeInsets.all(7),
child: Icon(
Icons.play_arrow,
size: 19,
color: Colors.white,
)),
),
);
}
return GestureDetector(
onTap: () {
pushMangaReaderView(
context: context,
chapter:
entriesManga[index].chapters.last);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: primaryColor(context)
.withOpacity(0.9),
),
child: const Padding(
padding: EdgeInsets.all(7),
child: Icon(
Icons.play_arrow,
size: 19,
color: Colors.white,
)),
), ),
child: Padding(
padding: const EdgeInsets.only(
left: 3, right: 3),
child: Text(
entriesManga[index].lang!.toUpperCase(),
style:
const TextStyle(color: Colors.white),
),
),
),
),
)),
],
),
if (!isComfortableGrid)
if (!isCoverOnlyGrid)
BottomTextWidget(text: entriesManga[index].name!),
if (continueReaderBtn)
Positioned(
bottom: 0,
right: 0,
child: Padding(
padding: const EdgeInsets.all(9),
child: Consumer(
builder: (context, ref, child) {
final history =
ref.watch(getAllHistoryStreamProvider);
return history.when(
data: (data) {
final incognitoMode =
ref.watch(incognitoModeStateProvider);
final entries = data
.where((element) =>
element.mangaId ==
entriesManga[index].id)
.toList();
if (entries.isNotEmpty && !incognitoMode) {
return GestureDetector(
onTap: () {
pushMangaReaderView(
context: context,
chapter:
entries.first.chapter.value!,
);
},
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(5),
color: primaryColor(context)
.withOpacity(0.9),
),
child: const Padding(
padding: EdgeInsets.all(7),
child: Icon(
Icons.play_arrow,
size: 19,
color: Colors.white,
)),
),
);
}
return GestureDetector(
onTap: () {
pushMangaReaderView(
context: context,
chapter: entriesManga[index]
.chapters
.last);
},
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(5),
color: primaryColor(context)
.withOpacity(0.9),
),
child: const Padding(
padding: EdgeInsets.all(7),
child: Icon(
Icons.play_arrow,
size: 19,
color: Colors.white,
)),
),
);
},
error: (Object error, StackTrace stackTrace) {
return ErrorText(error);
},
loading: () {
return const ProgressCenter();
},
); );
}, },
error: (Object error, StackTrace stackTrace) { )))
return ErrorText(error); ],
}, ),
loading: () { ),
return const ProgressCenter(); );
}, });
);
},
)))
],
),
);
}, },
); );
} }

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:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import 'package:mangayomi/views/history/providers/isar_providers.dart'; import 'package:mangayomi/views/history/providers/isar_providers.dart';
import 'package:mangayomi/views/library/providers/library_state_provider.dart';
import 'package:mangayomi/views/manga/reader/providers/push_router.dart'; import 'package:mangayomi/views/manga/reader/providers/push_router.dart';
import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/providers/hive_provider.dart'; import 'package:mangayomi/providers/hive_provider.dart';
@ -18,170 +19,233 @@ class LibraryListViewWidget extends StatelessWidget {
final List<Manga> entriesManga; final List<Manga> entriesManga;
final bool language; final bool language;
final bool downloadedChapter; final bool downloadedChapter;
final List<int> mangaIdsList;
final bool continueReaderBtn; final bool continueReaderBtn;
const LibraryListViewWidget( const LibraryListViewWidget(
{super.key, {super.key,
required this.entriesManga, required this.entriesManga,
required this.language, required this.language,
required this.downloadedChapter, required this.downloadedChapter,
required this.continueReaderBtn}); required this.continueReaderBtn,
required this.mangaIdsList});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListViewWidget( return ListViewWidget(
itemCount: entriesManga.length, itemCount: entriesManga.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return ElevatedButton( return Consumer(builder: (context, ref, child) {
style: ElevatedButton.styleFrom( final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
backgroundColor: Colors.transparent, return ElevatedButton(
shape: RoundedRectangleBorder( style: ElevatedButton.styleFrom(
borderRadius: BorderRadius.circular(0)), backgroundColor: mangaIdsList.contains(entriesManga[index].id)
elevation: 0, ? primaryColor(context).withOpacity(0.4)
shadowColor: Colors.transparent), : Colors.transparent,
onPressed: () { shape: RoundedRectangleBorder(
context.push('/manga-reader/detail', extra: entriesManga[index].id); borderRadius: BorderRadius.circular(0)),
}, elevation: 0,
child: Padding( shadowColor: Colors.transparent),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), onPressed: () {
child: Container( if (isLongPressed) {
height: 45, ref
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5)), .read(mangasListStateProvider.notifier)
child: Row( .update(entriesManga[index]);
mainAxisAlignment: MainAxisAlignment.spaceBetween, } else {
children: [ context.push('/manga-reader/detail',
Expanded( extra: entriesManga[index].id);
child: Row( }
children: [ },
ClipRRect( onLongPress: () {
borderRadius: const BorderRadius.only( if (!isLongPressed) {
topLeft: Radius.circular(5), ref
bottomLeft: Radius.circular(5)), .read(mangasListStateProvider.notifier)
child: cachedNetworkImage( .update(entriesManga[index]);
headers: headers(entriesManga[index].source!),
imageUrl: entriesManga[index].imageUrl!, ref
width: 40, .read(isLongPressedMangaStateProvider.notifier)
height: 40, .update(!isLongPressed);
fit: BoxFit.cover), } else {
), ref
Expanded( .read(mangasListStateProvider.notifier)
child: Padding( .update(entriesManga[index]);
padding: const EdgeInsets.symmetric(horizontal: 10), }
child: Text(entriesManga[index].name!), },
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
child: Container(
height: 45,
decoration:
BoxDecoration(borderRadius: BorderRadius.circular(5)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
children: [
ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(5),
bottomLeft: Radius.circular(5)),
child: cachedNetworkImage(
headers: headers(entriesManga[index].source!),
imageUrl: entriesManga[index].imageUrl!,
width: 40,
height: 40,
fit: BoxFit.cover),
), ),
) Expanded(
], child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 10),
child: Text(entriesManga[index].name!),
),
)
],
),
), ),
), Padding(
Padding( padding: const EdgeInsets.all(5),
padding: const EdgeInsets.all(5), child: Container(
child: Container( decoration: BoxDecoration(
decoration: BoxDecoration( borderRadius: BorderRadius.circular(3),
borderRadius: BorderRadius.circular(3), color: primaryColor(context)),
color: primaryColor(context)), child: SizedBox(
child: SizedBox( height: 22,
height: 22, child: Row(
child: Row( children: [
children: [ if (downloadedChapter)
if (downloadedChapter) Padding(
Padding( padding: const EdgeInsets.only(right: 5),
padding: const EdgeInsets.only(right: 5), child: Consumer(
child: Consumer( builder: (context, ref, child) {
builder: (context, ref, child) { List nbrDown = [];
List nbrDown = []; for (var i = 0;
for (var i = 0; i <
i < entriesManga[index].chapters.length;
i++) {
final entries = ref
.watch(hiveBoxMangaDownloadsProvider)
.values
.where((element) =>
element.chapterName ==
entriesManga[index] entriesManga[index]
.chapters .chapters
.toList()[i] .length;
.name) i++) {
.toList(); final entries = ref
if (entries.isNotEmpty && .watch(
entries.first.isDownload) { hiveBoxMangaDownloadsProvider)
nbrDown.add(entries.first); .values
.where((element) =>
element.chapterName ==
entriesManga[index]
.chapters
.toList()[i]
.name)
.toList();
if (entries.isNotEmpty &&
entries.first.isDownload) {
nbrDown.add(entries.first);
}
} }
} if (nbrDown.isNotEmpty) {
if (nbrDown.isNotEmpty) { return Container(
return Container( decoration: BoxDecoration(
decoration: BoxDecoration( borderRadius:
borderRadius: const BorderRadius.only( const BorderRadius.only(
topLeft: Radius.circular(3), topLeft: Radius.circular(3),
bottomLeft: Radius.circular(3)), bottomLeft:
color: Theme.of(context).hintColor, Radius.circular(3)),
), color: Theme.of(context).hintColor,
child: Padding(
padding: const EdgeInsets.only(
left: 3, right: 3),
child: Text(
nbrDown.length.toString(),
style: const TextStyle(
color: Colors.white),
), ),
), child: Padding(
); padding: const EdgeInsets.only(
} else { left: 3, right: 3),
return Container(); child: Text(
} nbrDown.length.toString(),
}, style: const TextStyle(
color: Colors.white),
),
),
);
} else {
return Container();
}
},
),
),
Padding(
padding: const EdgeInsets.only(right: 3),
child: Text(
entriesManga[index]
.chapters
.length
.toString(),
style: const TextStyle(color: Colors.white),
), ),
), ),
Padding( if (language)
padding: const EdgeInsets.only(right: 3), Container(
child: Text( color: primaryColor(context),
entriesManga[index].chapters.length.toString(), child: Container(
style: const TextStyle(color: Colors.white), decoration: BoxDecoration(
), borderRadius: const BorderRadius.only(
), topRight: Radius.circular(3),
if (language) bottomRight: Radius.circular(3)),
Container( color: Theme.of(context).hintColor,
color: primaryColor(context), ),
child: Container( child: Padding(
decoration: BoxDecoration( padding: const EdgeInsets.only(
borderRadius: const BorderRadius.only( left: 3, right: 3),
topRight: Radius.circular(3), child: Text(
bottomRight: Radius.circular(3)), entriesManga[index].lang!.toUpperCase(),
color: Theme.of(context).hintColor, style: const TextStyle(
), color: Colors.white),
child: Padding( ),
padding: const EdgeInsets.only(
left: 3, right: 3),
child: Text(
entriesManga[index].lang!.toUpperCase(),
style:
const TextStyle(color: Colors.white),
), ),
), ),
), ),
), ],
], ),
), ),
), ),
), ),
), if (continueReaderBtn)
if (continueReaderBtn) Consumer(
Consumer( builder: (context, ref, child) {
builder: (context, ref, child) { final history =
final history = ref.watch(getAllHistoryStreamProvider); ref.watch(getAllHistoryStreamProvider);
return history.when( return history.when(
data: (data) { data: (data) {
final incognitoMode = final incognitoMode =
ref.watch(incognitoModeStateProvider); ref.watch(incognitoModeStateProvider);
final entries = data final entries = data
.where((element) => .where((element) =>
element.mangaId == entriesManga[index].id) element.mangaId == entriesManga[index].id)
.toList(); .toList();
if (entries.isNotEmpty && !incognitoMode) { if (entries.isNotEmpty && !incognitoMode) {
return GestureDetector(
onTap: () {
pushMangaReaderView(
context: context,
chapter: entries.first.chapter.value!,
);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: primaryColor(context)
.withOpacity(0.9),
),
child: const Padding(
padding: EdgeInsets.all(7),
child: Icon(
Icons.play_arrow,
size: 19,
color: Colors.white,
)),
),
);
}
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
pushMangaReaderView( pushMangaReaderView(
context: context, context: context,
chapter: entries.first.chapter.value!, chapter:
); entriesManga[index].chapters.last);
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@ -198,42 +262,22 @@ class LibraryListViewWidget extends StatelessWidget {
)), )),
), ),
); );
} },
return GestureDetector( error: (Object error, StackTrace stackTrace) {
onTap: () { return ErrorText(error);
pushMangaReaderView( },
context: context, loading: () {
chapter: entriesManga[index].chapters.last); return const ProgressCenter();
}, },
child: Container( );
decoration: BoxDecoration( },
borderRadius: BorderRadius.circular(5), )
color: primaryColor(context).withOpacity(0.9), ],
), ),
child: const Padding(
padding: EdgeInsets.all(7),
child: Icon(
Icons.play_arrow,
size: 19,
color: Colors.white,
)),
),
);
},
error: (Object error, StackTrace stackTrace) {
return ErrorText(error);
},
loading: () {
return const ProgressCenter();
},
);
},
)
],
), ),
), ),
), );
); });
}, },
); );
} }

View file

@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
import 'package:mangayomi/models/category.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/views/manga/detail/widgets/chapter_filter_list_tile_widget.dart';
class ListTileMangaCategory extends StatefulWidget {
final Category category;
final List<int> categoryIds;
final List<Manga> mangasList;
final Function(List<Manga>) res;
final VoidCallback onTap;
const ListTileMangaCategory(
{super.key,
required this.category,
required this.mangasList,
required this.res,
required this.onTap,
required this.categoryIds});
@override
State<ListTileMangaCategory> createState() => _ListTileMangaCategoryState();
}
class _ListTileMangaCategoryState extends State<ListTileMangaCategory> {
@override
void initState() {
final res = widget.mangasList.where(
(element) {
return element.categories == null
? false
: element.categories!.contains(widget.category.id);
},
).toList();
widget.res(res);
super.initState();
}
@override
Widget build(BuildContext context) {
return ListTileChapterFilter(
label: widget.category.name!,
onTap: widget.onTap,
type: widget.categoryIds.contains(widget.category.id) ? 1 : 0,
);
}
}

View file

@ -1,5 +1,3 @@
import 'dart:developer';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:draggable_menu/draggable_menu.dart'; import 'package:draggable_menu/draggable_menu.dart';
import 'package:draggable_scrollbar/draggable_scrollbar.dart'; import 'package:draggable_scrollbar/draggable_scrollbar.dart';
@ -7,8 +5,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/providers/hive_provider.dart'; import 'package:mangayomi/providers/hive_provider.dart';
@ -23,9 +19,7 @@ import 'package:mangayomi/views/manga/detail/readmore.dart';
import 'package:mangayomi/views/manga/detail/widgets/chapter_filter_list_tile_widget.dart'; import 'package:mangayomi/views/manga/detail/widgets/chapter_filter_list_tile_widget.dart';
import 'package:mangayomi/views/manga/detail/widgets/chapter_list_tile_widget.dart'; import 'package:mangayomi/views/manga/detail/widgets/chapter_list_tile_widget.dart';
import 'package:mangayomi/views/manga/detail/widgets/chapter_sort_list_tile_widget.dart'; import 'package:mangayomi/views/manga/detail/widgets/chapter_sort_list_tile_widget.dart';
import 'package:mangayomi/views/manga/download/providers/download_provider.dart';
import 'package:mangayomi/views/widgets/error_text.dart'; import 'package:mangayomi/views/widgets/error_text.dart';
import 'package:mangayomi/views/widgets/progress_center.dart';
class MangaDetailView extends ConsumerStatefulWidget { class MangaDetailView extends ConsumerStatefulWidget {
final Function(bool) isExtended; final Function(bool) isExtended;
@ -66,17 +60,17 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isLongPressed = ref.watch(isLongPressedStateProvider); final isLongPressed = ref.watch(isLongPressedStateProvider);
final chapterNameList = ref.watch(chaptersListStateProvider); final chapterNameList = ref.watch(chaptersListStateProvider);
bool reverse = ref.watch( bool reverse = ref
reverseChapterStateProvider(mangaId: widget.manga!.id!))["reverse"]; .watch(sortChapterStateProvider(mangaId: widget.manga!.id!))["reverse"];
final filterUnread = final filterUnread =
ref.watch(chapterFilterUnreadStateProvider(mangaId: widget.manga!.id!)); ref.watch(chapterFilterUnreadStateProvider(mangaId: widget.manga!.id!));
final filterBookmarked = ref.watch( final filterBookmarked = ref.watch(
chapterFilterBookmarkedStateProvider(mangaId: widget.manga!.id!)); chapterFilterBookmarkedStateProvider(mangaId: widget.manga!.id!));
final filterDownloaded = ref.watch( final filterDownloaded = ref.watch(
chapterFilterDownloadedStateProvider(mangaId: widget.manga!.id!)); chapterFilterDownloadedStateProvider(mangaId: widget.manga!.id!));
final sortChapter = ref.watch( final sortChapter =
reverseChapterStateProvider(mangaId: widget.manga!.id!))['index'] ref.watch(sortChapterStateProvider(mangaId: widget.manga!.id!))['index']
as int; as int;
final chapters = final chapters =
ref.watch(getChaptersStreamProvider(mangaId: widget.manga!.id!)); ref.watch(getChaptersStreamProvider(mangaId: widget.manga!.id!));
return NotificationListener<UserScrollNotification>( return NotificationListener<UserScrollNotification>(
@ -91,45 +85,12 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
}, },
child: chapters.when( child: chapters.when(
data: (data) { data: (data) {
List<Chapter> chapterList = data List<Chapter> chapters = _filterAndSortChapter(
.where((element) => filterUnread == 1 data: data,
? element.isRead == false filterUnread: filterUnread,
: filterUnread == 2 filterBookmarked: filterBookmarked,
? element.isRead == true filterDownloaded: filterDownloaded,
: true) sortChapter: sortChapter);
.where((element) => filterBookmarked == 1
? element.isBookmarked == true
: filterBookmarked == 2
? element.isBookmarked == false
: true)
.where((element) {
final modelChapDownload = ref
.watch(hiveBoxMangaDownloadsProvider)
.get("${element.mangaId}/${element.id}", defaultValue: null);
return filterDownloaded == 1
? modelChapDownload != null &&
modelChapDownload.isDownload == true
: filterDownloaded == 2
? !(modelChapDownload != null &&
modelChapDownload.isDownload == true)
: true;
}).toList();
List<Chapter> chapters =
sortChapter == 1 ? chapterList.reversed.toList() : chapterList;
if (sortChapter == 0) {
chapters.sort(
(a, b) {
return a.scanlator!.compareTo(b.scanlator!) |
a.dateUpload!.compareTo(b.dateUpload!);
},
);
} else if (sortChapter == 2) {
chapters.sort(
(a, b) {
return a.dateUpload!.compareTo(b.dateUpload!);
},
);
}
return _buildWidget( return _buildWidget(
chapters: chapters, chapters: chapters,
reverse: reverse, reverse: reverse,
@ -149,100 +110,158 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
)); ));
} }
List<Chapter> _filterAndSortChapter(
{required List<Chapter> data,
required int filterUnread,
required int filterBookmarked,
required int filterDownloaded,
required int sortChapter}) {
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 = ref
.watch(hiveBoxMangaDownloadsProvider)
.get("${element.mangaId}/${element.id}", defaultValue: null);
return filterDownloaded == 1
? modelChapDownload != null && modelChapDownload.isDownload == true
: filterDownloaded == 2
? !(modelChapDownload != null &&
modelChapDownload.isDownload == true)
: true;
}).toList();
List<Chapter> chapters =
sortChapter == 1 ? chapterList.reversed.toList() : chapterList;
if (sortChapter == 0) {
chapters.sort(
(a, b) {
return a.scanlator!.compareTo(b.scanlator!) |
a.dateUpload!.compareTo(b.dateUpload!);
},
);
} else if (sortChapter == 2) {
chapters.sort(
(a, b) {
return a.dateUpload!.compareTo(b.dateUpload!);
},
);
}
return chapterList;
}
Widget _buildWidget( Widget _buildWidget(
{required List<Chapter> chapters, {required List<Chapter> chapters,
required bool reverse, required bool reverse,
required List<Chapter> chapterList, required List<Chapter> chapterList,
required bool isLongPressed}) { required bool isLongPressed}) {
return Scaffold( return Stack(
extendBodyBehindAppBar: true, children: [
appBar: PreferredSize( Consumer(
preferredSize: Size.fromHeight(AppBar().preferredSize.height), builder: (context, ref, child) {
child: Consumer( return Positioned(
builder: (context, ref, child) { top: 0,
final isNotFiltering = ref.watch( child: ref.watch(offetProvider) == 0.0
chapterFilterResultStateProvider( ? Stack(
mangaId: widget.manga!.id!)); children: [
final isLongPressed = ref.watch(isLongPressedStateProvider); cachedNetworkImage(
// final chapterList = ref.watch(chaptersListStateProvider); headers: headers(widget.manga!.source!),
return isLongPressed imageUrl: widget.manga!.imageUrl!,
? Container( width: mediaWidth(context, 1),
color: Theme.of(context).scaffoldBackgroundColor, height: 410,
child: AppBar( fit: BoxFit.cover),
title: Text(chapterList.length.toString()), Container(
backgroundColor: width: mediaWidth(context, 1),
primaryColor(context).withOpacity(0.2), height: 465,
leading: IconButton( color: Theme.of(context)
onPressed: () { .scaffoldBackgroundColor
ref .withOpacity(0.9),
.read(chaptersListStateProvider.notifier) ),
.clear(); ],
)
ref : Container(),
.read(isLongPressedStateProvider.notifier) );
.update(!isLongPressed); },
}, ),
icon: const Icon(Icons.clear)), Scaffold(
actions: [ backgroundColor: Colors.transparent,
IconButton( extendBodyBehindAppBar: true,
onPressed: () { appBar: PreferredSize(
for (var chapter in chapters) { preferredSize: Size.fromHeight(AppBar().preferredSize.height),
child: Consumer(
builder: (context, ref, child) {
final isNotFiltering = ref.watch(
chapterFilterResultStateProvider(
mangaId: widget.manga!.id!));
final isLongPressed = ref.watch(isLongPressedStateProvider);
return isLongPressed
? Container(
color: Theme.of(context).scaffoldBackgroundColor,
child: AppBar(
title: Text(chapterList.length.toString()),
backgroundColor:
primaryColor(context).withOpacity(0.2),
leading: IconButton(
onPressed: () {
ref ref
.read(chaptersListStateProvider .read(
.notifier) chaptersListStateProvider.notifier)
.selectAll(chapter); .clear();
}
},
icon: const Icon(Icons.select_all)),
IconButton(
onPressed: () {
if (chapters.length ==
chapterList.length) {
for (var chapter in chapters) {
ref
.read(chaptersListStateProvider
.notifier)
.selectSome(chapter);
}
ref ref
.read( .read(
isLongPressedStateProvider.notifier) isLongPressedStateProvider.notifier)
.update(false); .update(!isLongPressed);
} else { },
for (var chapter in chapters) { icon: const Icon(Icons.clear)),
ref actions: [
.read(chaptersListStateProvider IconButton(
.notifier) onPressed: () {
.selectSome(chapter); for (var chapter in chapters) {
} ref
} .read(chaptersListStateProvider
}, .notifier)
icon: const Icon(Icons.flip_to_back_rounded)), .selectAll(chapter);
], }
), },
) icon: const Icon(Icons.select_all)),
: Stack( IconButton(
children: [ onPressed: () {
Positioned( if (chapters.length ==
top: 0, chapterList.length) {
child: Stack( for (var chapter in chapters) {
children: [ ref
cachedNetworkImage( .read(chaptersListStateProvider
headers: headers(widget.manga!.source!), .notifier)
imageUrl: widget.manga!.imageUrl!, .selectSome(chapter);
width: mediaWidth(context, 1), }
height: 410, ref
fit: BoxFit.cover), .read(isLongPressedStateProvider
Container( .notifier)
width: mediaWidth(context, 1), .update(false);
height: 465, } else {
color: Theme.of(context) for (var chapter in chapters) {
.scaffoldBackgroundColor ref
.withOpacity(0.9), .read(chaptersListStateProvider
), .notifier)
], .selectSome(chapter);
)), }
AppBar( }
},
icon:
const Icon(Icons.flip_to_back_rounded)),
],
),
)
: AppBar(
title: ref.watch(offetProvider) > 200 title: ref.watch(offetProvider) > 200
? Text( ? Text(
widget.manga!.name!, widget.manga!.name!,
@ -269,130 +288,155 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
color: color:
isNotFiltering ? null : Colors.yellow, isNotFiltering ? null : Colors.yellow,
)), )),
PopupMenuButton( PopupMenuButton(itemBuilder: (context) {
itemBuilder: (context) { return [
return [ if (widget.manga!.favorite)
if (widget.manga!.favorite) const PopupMenuItem<int>(
const PopupMenuItem<int>( value: 0,
value: 0, child: Text("Edit categories")),
child: Text("Edit categories")), if (widget.manga!.favorite)
if (widget.manga!.favorite) const PopupMenuItem<int>(
const PopupMenuItem<int>( value: 0, child: Text("Migrate")),
value: 0, child: Text("Migrate")), const PopupMenuItem<int>(
const PopupMenuItem<int>( value: 0, child: Text("Share")),
value: 0, child: Text("Share")), ];
]; }, onSelected: (value) {
}, if (value == 0) {
onSelected: (value) {}), context.push("/categories");
}
}),
], ],
) );
], },
); )),
}, body: SafeArea(
)), child: DraggableScrollbar(
body: SafeArea( padding: const EdgeInsets.only(right: 7),
child: DraggableScrollbar( heightScrollThumb: 48.0,
heightScrollThumb: 48.0, backgroundColor: primaryColor(context),
backgroundColor: primaryColor(context), scrollThumbBuilder:
scrollThumbBuilder: (backgroundColor, thumbAnimation, labelAnimation, height,
(backgroundColor, thumbAnimation, labelAnimation, height, {labelConstraints, labelText}) {
{labelConstraints, labelText}) { return FadeTransition(
return FadeTransition( opacity: thumbAnimation,
opacity: thumbAnimation, child: Container(
child: Container( decoration: BoxDecoration(
decoration: BoxDecoration( color: backgroundColor,
color: backgroundColor, borderRadius: BorderRadius.circular(20)),
borderRadius: BorderRadius.circular(20)), height: height,
height: height, width: 8.0,
width: 8.0, ),
);
},
scrollbarTimeToFade: const Duration(seconds: 2),
controller: _scrollController,
child: ListView.builder(
controller: _scrollController,
padding: const EdgeInsets.only(top: 0, bottom: 60),
itemCount: chapters.length + 1,
itemBuilder: (context, index) {
int finalIndex = index - 1;
if (index == 0) {
return _bodyContainer(chapterLength: chapters.length);
}
int reverseIndex = chapters.length -
chapters.reversed.toList().indexOf(
chapters.reversed.toList()[finalIndex]) -
1;
final indexx = reverse ? reverseIndex : finalIndex;
return ChapterListTileWidget(
chapter: chapters[indexx],
chapterList: chapterList,
);
})),
),
bottomNavigationBar: AnimatedContainer(
curve: Curves.easeIn,
decoration: BoxDecoration(
color: primaryColor(context).withOpacity(0.2),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20))),
duration: const Duration(milliseconds: 100),
height: isLongPressed ? 70 : 0,
width: mediaWidth(context, 1),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Expanded(
child: SizedBox(
height: 70,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0,
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
),
onPressed: () {
ref
.read(chapterSetIsBookmarkStateProvider(
manga: widget.manga!)
.notifier)
.set();
},
child: Icon(Icons.bookmark_add_outlined,
color: Theme.of(context)
.textTheme
.bodyLarge!
.color)),
), ),
); ),
}, Expanded(
scrollbarTimeToFade: const Duration(seconds: 2), child: SizedBox(
controller: _scrollController, height: 70,
child: ListView.builder( child: ElevatedButton(
controller: _scrollController, style: ElevatedButton.styleFrom(
padding: const EdgeInsets.only(top: 0, bottom: 60), elevation: 0,
itemCount: chapters.length + 1, backgroundColor: Colors.transparent,
itemBuilder: (context, index) { shadowColor: Colors.transparent,
int finalIndex = index - 1; ),
if (index == 0) { onPressed: () {
return _bodyContainer(chapterLength: chapters.length); ref
} .read(chapterSetIsReadStateProvider(
int reverseIndex = chapters.length - manga: widget.manga!)
chapters.reversed .notifier)
.toList() .set();
.indexOf(chapters.reversed.toList()[finalIndex]) - },
1; child: Icon(Icons.done_all_sharp,
final indexx = reverse ? reverseIndex : finalIndex; color: Theme.of(context)
return ChapterListTileWidget( .textTheme
chapter: chapters[indexx], .bodyLarge!
chapterList: chapterList, .color!)),
); ),
}))), ),
bottomNavigationBar: AnimatedContainer( Expanded(
curve: Curves.easeIn, child: SizedBox(
decoration: BoxDecoration( height: 70,
color: primaryColor(context).withOpacity(0.2), child: ElevatedButton(
borderRadius: const BorderRadius.only( style: ElevatedButton.styleFrom(
topLeft: Radius.circular(20), topRight: Radius.circular(20))), elevation: 0,
duration: const Duration(milliseconds: 100), backgroundColor: Colors.transparent,
height: isLongPressed ? 70 : 0, shadowColor: Colors.transparent,
width: mediaWidth(context, 1), ),
child: Row( onPressed: () {
mainAxisAlignment: MainAxisAlignment.spaceAround, ref
children: [ .read(chapterSetDownloadStateProvider(
Expanded( manga: widget.manga!)
child: SizedBox( .notifier)
height: 70, .set();
child: ElevatedButton( },
style: ElevatedButton.styleFrom( child: Icon(
elevation: 0, backgroundColor: Colors.transparent), Icons.download_outlined,
onPressed: () { color:
ref Theme.of(context).textTheme.bodyLarge!.color!,
.read(chapterSetIsBookmarkStateProvider( )),
manga: widget.manga!) ),
.notifier) )
.set(); ],
},
child: const Icon(Icons.bookmark_add_outlined)),
),
), ),
Expanded( )),
child: SizedBox( ],
height: 70, );
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0, backgroundColor: Colors.transparent),
onPressed: () {
ref
.read(chapterSetIsReadStateProvider(
manga: widget.manga!)
.notifier)
.set();
},
child: const Icon(Icons.done_all_sharp)),
),
),
Expanded(
child: SizedBox(
height: 70,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0, backgroundColor: Colors.transparent),
onPressed: () {
ref
.read(chapterSetDownloadStateProvider(
manga: widget.manga!)
.notifier)
.set();
},
child: const Icon(Icons.download_outlined)),
),
)
],
),
));
} }
_showDraggableMenu() { _showDraggableMenu() {
@ -469,26 +513,22 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
}), }),
Consumer(builder: (context, ref, chil) { Consumer(builder: (context, ref, chil) {
final reverse = ref final reverse = ref
.read(reverseChapterStateProvider( .read(sortChapterStateProvider(
mangaId: widget.manga!.id!) mangaId: widget.manga!.id!)
.notifier) .notifier)
.isReverse(); .isReverse();
final reverseChapter = ref.watch( final reverseChapter = ref.watch(
reverseChapterStateProvider( sortChapterStateProvider(
mangaId: widget.manga!.id!)); mangaId: widget.manga!.id!));
return Column( return Column(
children: [ children: [
for (var i = 0; i < 3; i++) for (var i = 0; i < 3; i++)
ListTileChapterSort( ListTileChapterSort(
label: i == 0 label: _getSortNameByIndex(i),
? "By source"
: i == 1
? "By chapter number"
: "By upload date",
reverse: reverse, reverse: reverse,
onTap: () { onTap: () {
ref ref
.read(reverseChapterStateProvider( .read(sortChapterStateProvider(
mangaId: widget.manga!.id!) mangaId: widget.manga!.id!)
.notifier) .notifier)
.set(i); .set(i);
@ -502,6 +542,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
return Column( return Column(
children: [ children: [
RadioListTile( RadioListTile(
dense: true,
title: const Text("Source title"), title: const Text("Source title"),
value: "e", value: "e",
groupValue: "e", groupValue: "e",
@ -509,6 +550,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
onChanged: (value) {}, onChanged: (value) {},
), ),
RadioListTile( RadioListTile(
dense: true,
title: const Text("Chapter number"), title: const Text("Chapter number"),
value: "ej", value: "ej",
groupValue: "e", groupValue: "e",
@ -528,6 +570,15 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
); );
} }
String _getSortNameByIndex(int index) {
if (index == 0) {
return "By source";
} else if (index == 1) {
return "By chapter number";
}
return "By upload date";
}
Widget _bodyContainer({required int chapterLength}) { Widget _bodyContainer({required int chapterLength}) {
return Stack( return Stack(
children: [ children: [
@ -537,7 +588,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
headers: headers(widget.manga!.source!), headers: headers(widget.manga!.source!),
imageUrl: widget.manga!.imageUrl!, imageUrl: widget.manga!.imageUrl!,
width: mediaWidth(context, 1), width: mediaWidth(context, 1),
height: 300, height: 250,
fit: BoxFit.cover)), fit: BoxFit.cover)),
Container( Container(
height: 300, height: 300,
@ -565,7 +616,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
], ],
), ),
), ),
_actionConstructor(), _actionFavouriteAndWebview(),
Container( Container(
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).scaffoldBackgroundColor,
child: Column( child: Column(
@ -655,7 +706,6 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
], ],
), ),
)), )),
// log
Column( Column(
children: [ children: [
//Description //Description
@ -690,7 +740,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
Widget _coverCard() { Widget _coverCard() {
return Positioned( return Positioned(
top: 20, top: 20,
left: 20, left: 13,
child: GestureDetector( child: GestureDetector(
onTap: () {}, onTap: () {},
child: SizedBox( child: SizedBox(
@ -713,11 +763,11 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
Widget _titles() { Widget _titles() {
return Positioned( return Positioned(
top: 60, top: 60,
left: 30, left: 23,
child: Container( child: Container(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
padding: const EdgeInsets.only(left: 100), padding: const EdgeInsets.only(left: 100),
width: MediaQuery.of(context).size.width * 0.9, width: MediaQuery.of(context).size.width * 1,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -732,7 +782,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
); );
} }
Widget _actionConstructor() { Widget _actionFavouriteAndWebview() {
return Container( return Container(
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).scaffoldBackgroundColor,
child: Row( child: Row(

View file

@ -6,7 +6,6 @@ import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/category.dart'; import 'package:mangayomi/models/category.dart';
import 'package:mangayomi/views/history/providers/isar_providers.dart'; import 'package:mangayomi/views/history/providers/isar_providers.dart';
import 'package:mangayomi/views/manga/detail/providers/isar_providers.dart';
import 'package:mangayomi/views/manga/reader/providers/push_router.dart'; import 'package:mangayomi/views/manga/reader/providers/push_router.dart';
import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/utils/colors.dart'; import 'package:mangayomi/utils/colors.dart';
@ -20,10 +19,8 @@ import 'package:mangayomi/views/widgets/progress_center.dart';
class MangaDetailsView extends ConsumerStatefulWidget { class MangaDetailsView extends ConsumerStatefulWidget {
final Manga manga; final Manga manga;
final Function(bool) isFavorite;
const MangaDetailsView({ const MangaDetailsView({
super.key, super.key,
required this.isFavorite,
required this.manga, required this.manga,
}); });
@ -32,35 +29,9 @@ class MangaDetailsView extends ConsumerStatefulWidget {
} }
class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> { class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
bool isFavorite = false;
bool _isOk = false;
bool isGplay = false;
_checkFavorite(bool i) async {
if (!_isOk) {
await Future.delayed(const Duration(milliseconds: 30));
if (mounted) {
setState(() {
widget.isFavorite(i);
isFavorite = i;
_isOk = true;
});
}
}
}
_setFavorite(bool i) async {
if (mounted) {
setState(() {
widget.isFavorite(i);
isFavorite = i;
});
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final history = ref.watch(getAllHistoryStreamProvider); final history = ref.watch(getAllHistoryStreamProvider);
_checkFavorite(widget.manga.favorite);
return Scaffold( return Scaffold(
floatingActionButton: ref.watch(isLongPressedStateProvider) == true floatingActionButton: ref.watch(isLongPressedStateProvider) == true
? null ? null
@ -113,7 +84,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
duration: duration:
const Duration(milliseconds: 200), const Duration(milliseconds: 200),
child: const Text( child: const Text(
"Continue", "Resume",
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
fontSize: 14, color: Colors.white), fontSize: 14, color: Colors.white),
@ -224,12 +195,12 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
backgroundColor: backgroundColor:
Theme.of(context).scaffoldBackgroundColor, Theme.of(context).scaffoldBackgroundColor,
elevation: 0), elevation: 0),
onPressed: () async { onPressed: () {
_setFavorite(false);
final model = widget.manga; final model = widget.manga;
await isar.writeTxn(() async { isar.writeTxnSync(() {
model.favorite = false; model.favorite = false;
await isar.mangas.put(model); model.dateAdded = 0;
isar.mangas.putSync(model);
}); });
}, },
child: Column( child: Column(
@ -264,11 +235,11 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
if (checkCategoryList) { if (checkCategoryList) {
_openCategory(widget.manga); _openCategory(widget.manga);
} else { } else {
_setFavorite(true);
final model = widget.manga; final model = widget.manga;
await isar.writeTxn(() async { isar.writeTxnSync(() {
model.favorite = true; model.favorite = true;
await isar.mangas.put(model); model.dateAdded = DateTime.now().millisecondsSinceEpoch;
isar.mangas.putSync(model);
}); });
} }
}, },
@ -367,13 +338,12 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
width: 15, width: 15,
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () {
_setFavorite(true);
final model = widget.manga; final model = widget.manga;
await isar.writeTxn(() async { isar.writeTxnSync(() {
model.favorite = true; model.favorite = true;
model.categories = categoryIds; model.categories = categoryIds;
await isar.mangas.put(model); isar.mangas.putSync(model);
}); });
if (mounted) { if (mounted) {
Navigator.pop(context); Navigator.pop(context);

View file

@ -25,7 +25,6 @@ class MangaReaderDetail extends ConsumerStatefulWidget {
} }
class _MangaReaderDetailState extends ConsumerState<MangaReaderDetail> { class _MangaReaderDetailState extends ConsumerState<MangaReaderDetail> {
bool _isFavorite = false;
@override @override
void initState() { void initState() {
SystemChrome.setPreferredOrientations([ SystemChrome.setPreferredOrientations([
@ -51,60 +50,54 @@ class _MangaReaderDetailState extends ConsumerState<MangaReaderDetail> {
data: (modelManga) { data: (modelManga) {
return RefreshIndicator( return RefreshIndicator(
onRefresh: () async { onRefresh: () async {
if (_isFavorite) { bool isOk = false;
bool isOk = false; ref
ref .watch(getMangaDetailProvider(
.watch(getMangaDetailProvider( imageUrl: modelManga.imageUrl!,
imageUrl: modelManga.imageUrl!, lang: modelManga.lang!,
lang: modelManga.lang!, title: modelManga.name!,
title: modelManga.name!, source: modelManga.source!,
source: modelManga.source!, url: modelManga.link!)
url: modelManga.link!) .future)
.future) .then((value) async {
.then((value) async { if (value.chapters.isNotEmpty &&
if (value.chapters.isNotEmpty && value.chapters.length > modelManga.chapters.length) {
value.chapters.length > modelManga.chapters.length) { await isar.writeTxn(() async {
await isar.writeTxn(() async { int newChapsIndex =
int newChapsIndex = value.chapters.length - modelManga.chapters.length;
value.chapters.length - modelManga.chapters.length; modelManga.lastUpdate = DateTime.now().millisecondsSinceEpoch;
for (var i = 0; i < newChapsIndex; i++) { for (var i = 0; i < newChapsIndex; i++) {
final chapters = Chapter( final chapters = Chapter(
name: value.chapters[i].name, name: value.chapters[i].name,
url: value.chapters[i].url, url: value.chapters[i].url,
dateUpload: value.chapters[i].dateUpload, dateUpload: value.chapters[i].dateUpload,
isBookmarked: false, isBookmarked: false,
scanlator: value.chapters[i].scanlator, scanlator: value.chapters[i].scanlator,
isRead: false, isRead: false,
lastPageRead: '', lastPageRead: '',
mangaId: modelManga.id) mangaId: modelManga.id)
..manga.value = modelManga; ..manga.value = modelManga;
await isar.chapters.put(chapters); await isar.chapters.put(chapters);
await chapters.manga.save(); await chapters.manga.save();
} }
}); });
} }
if (mounted) { if (mounted) {
setState(() { setState(() {
isOk = true; isOk = true;
}); });
} }
}); });
await Future.doWhile(() async { await Future.doWhile(() async {
await Future.delayed(const Duration(seconds: 1)); await Future.delayed(const Duration(seconds: 1));
if (isOk == true) { if (isOk == true) {
return false; return false;
} }
return true; return true;
}); });
}
}, },
child: MangaDetailsView( child: MangaDetailsView(
manga: modelManga!, manga: modelManga!,
isFavorite: (value) {
setState(() {
_isFavorite = value;
});
},
), ),
); );
}, },

View file

@ -1,6 +1,3 @@
import 'dart:convert';
import 'dart:developer';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/models/manga.dart';
@ -9,26 +6,6 @@ import 'package:mangayomi/views/manga/download/providers/download_provider.dart'
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'state_providers.g.dart'; part 'state_providers.g.dart';
@riverpod
class ChapterModelState extends _$ChapterModelState {
@override
Chapter build() {
return Chapter(
name: "",
url: "",
dateUpload: "",
isBookmarked: false,
scanlator: "",
isRead: false,
lastPageRead: "",
mangaId: null);
}
void update(Chapter chapters) {
state = chapters;
}
}
@riverpod @riverpod
class ChaptersListState extends _$ChaptersListState { class ChaptersListState extends _$ChaptersListState {
@override @override
@ -98,10 +75,10 @@ class IsExtendedState extends _$IsExtendedState {
} }
@riverpod @riverpod
class ReverseChapterState extends _$ReverseChapterState { class SortChapterState extends _$SortChapterState {
@override @override
dynamic build({required int mangaId}) { dynamic build({required int mangaId}) {
return ref.watch(hiveBoxSettingsProvider).get("$mangaId-reverseChapterMap", return ref.watch(hiveBoxSettingsProvider).get("$mangaId-sortChapterMap",
defaultValue: {"reverse": false, "index": 2}); defaultValue: {"reverse": false, "index": 2});
} }
@ -110,33 +87,13 @@ class ReverseChapterState extends _$ReverseChapterState {
"reverse": state['index'] == index ? !reverse : reverse, "reverse": state['index'] == index ? !reverse : reverse,
"index": index "index": index
}; };
ref.watch(hiveBoxSettingsProvider).put("$mangaId-reverseChapterMap", value); ref.watch(hiveBoxSettingsProvider).put("$mangaId-sortChapterMap", value);
state = value; state = value;
} }
void set(int index) { void set(int index) {
final reverse = ref final reverse = isReverse();
.read(reverseChapterStateProvider(mangaId: mangaId).notifier)
.isReverse();
final sortBySource = ref.watch(sortBySourceStateProvider(mangaId: mangaId));
final sortByChapterNumber =
ref.watch(sortByChapterNumberStateProvider(mangaId: mangaId));
final sortByUploadDate =
ref.watch(sortByUploadDateStateProvider(mangaId: mangaId));
update(reverse, index); update(reverse, index);
if (index == 0) {
ref
.read(sortBySourceStateProvider(mangaId: mangaId).notifier)
.update(!sortBySource);
} else if (index == 1) {
ref
.read(sortByChapterNumberStateProvider(mangaId: mangaId).notifier)
.update(!sortByChapterNumber);
} else {
ref
.read(sortByUploadDateStateProvider(mangaId: mangaId).notifier)
.update(!sortByUploadDate);
}
} }
bool isReverse() { bool isReverse() {
@ -260,20 +217,20 @@ class ChapterFilterResultState extends _$ChapterFilterResultState {
Manga mangaWithNewChapValue( Manga mangaWithNewChapValue(
{required Manga manga, required List<Chapter>? chapters}) { {required Manga manga, required List<Chapter>? chapters}) {
return Manga( return Manga(
imageUrl: manga.imageUrl, imageUrl: manga.imageUrl,
name: manga.name, name: manga.name,
genre: manga.genre, genre: manga.genre,
author: manga.author, author: manga.author,
description: manga.description, description: manga.description,
status: manga.status, status: manga.status,
favorite: manga.favorite, favorite: manga.favorite,
link: manga.link, link: manga.link,
source: manga.source, source: manga.source,
lang: manga.lang, lang: manga.lang,
dateAdded: manga.dateAdded, dateAdded: manga.dateAdded,
lastUpdate: manga.lastUpdate, lastUpdate: manga.lastUpdate,
categories: manga.categories, categories: manga.categories,
lastRead: manga.lastRead); );
} }
@riverpod @riverpod
@ -302,7 +259,7 @@ class ChapterSetIsReadState extends _$ChapterSetIsReadState {
set() { set() {
final chapters = ref.watch(chaptersListStateProvider); final chapters = ref.watch(chaptersListStateProvider);
isar.writeTxnSync(() async { isar.writeTxnSync(() {
for (var chapter in chapters) { for (var chapter in chapters) {
chapter.isRead = !chapter.isRead!; chapter.isRead = !chapter.isRead!;
isar.chapters.putSync(chapter..manga.value = manga); isar.chapters.putSync(chapter..manga.value = manga);
@ -336,54 +293,3 @@ class ChapterSetDownloadState extends _$ChapterSetDownloadState {
ref.read(chaptersListStateProvider.notifier).clear(); ref.read(chaptersListStateProvider.notifier).clear();
} }
} }
@riverpod
class SortByUploadDateState extends _$SortByUploadDateState {
@override
bool build({required int mangaId}) {
return ref
.watch(hiveBoxSettingsProvider)
.get("$mangaId-sortByUploadDateChapter", defaultValue: false);
}
void update(bool value) {
ref
.watch(hiveBoxSettingsProvider)
.put("$mangaId-sortByUploadDateChapter", value);
state = value;
}
}
@riverpod
class SortBySourceState extends _$SortBySourceState {
@override
bool build({required int mangaId}) {
return ref
.watch(hiveBoxSettingsProvider)
.get("$mangaId-sortBySourceChapter", defaultValue: false);
}
void update(bool value) {
ref
.watch(hiveBoxSettingsProvider)
.put("$mangaId-sortBySourceChapter", value);
state = value;
}
}
@riverpod
class SortByChapterNumberState extends _$SortByChapterNumberState {
@override
bool build({required int mangaId}) {
return ref
.watch(hiveBoxSettingsProvider)
.get("$mangaId-sortByChapterNumberChapter", defaultValue: false);
}
void update(bool value) {
ref
.watch(hiveBoxSettingsProvider)
.put("$mangaId-sortByChapterNumberChapter", value);
state = value;
}
}

View file

@ -6,22 +6,6 @@ part of 'state_providers.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$chapterModelStateHash() => r'e1b191e6176992d1fc5f04dcb1e25e211f8a69a7';
/// See also [ChapterModelState].
@ProviderFor(ChapterModelState)
final chapterModelStateProvider =
AutoDisposeNotifierProvider<ChapterModelState, Chapter>.internal(
ChapterModelState.new,
name: r'chapterModelStateProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$chapterModelStateHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$ChapterModelState = AutoDisposeNotifier<Chapter>;
String _$chaptersListStateHash() => r'251609214d127964e84d4616d2c3a7afa4fd80b4'; String _$chaptersListStateHash() => r'251609214d127964e84d4616d2c3a7afa4fd80b4';
/// See also [ChaptersListState]. /// See also [ChaptersListState].
@ -71,8 +55,7 @@ final isExtendedStateProvider =
); );
typedef _$IsExtendedState = AutoDisposeNotifier<bool>; typedef _$IsExtendedState = AutoDisposeNotifier<bool>;
String _$reverseChapterStateHash() => String _$sortChapterStateHash() => r'38b241e06866613a0c34d306da0d855f57af3862';
r'8e3db99ef54d27d37e9af35ef9d822a4f5dc6eaf';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@ -95,7 +78,7 @@ class _SystemHash {
} }
} }
abstract class _$ReverseChapterState abstract class _$SortChapterState
extends BuildlessAutoDisposeNotifier<dynamic> { extends BuildlessAutoDisposeNotifier<dynamic> {
late final int mangaId; late final int mangaId;
@ -104,27 +87,27 @@ abstract class _$ReverseChapterState
}); });
} }
/// See also [ReverseChapterState]. /// See also [SortChapterState].
@ProviderFor(ReverseChapterState) @ProviderFor(SortChapterState)
const reverseChapterStateProvider = ReverseChapterStateFamily(); const sortChapterStateProvider = SortChapterStateFamily();
/// See also [ReverseChapterState]. /// See also [SortChapterState].
class ReverseChapterStateFamily extends Family<dynamic> { class SortChapterStateFamily extends Family<dynamic> {
/// See also [ReverseChapterState]. /// See also [SortChapterState].
const ReverseChapterStateFamily(); const SortChapterStateFamily();
/// See also [ReverseChapterState]. /// See also [SortChapterState].
ReverseChapterStateProvider call({ SortChapterStateProvider call({
required int mangaId, required int mangaId,
}) { }) {
return ReverseChapterStateProvider( return SortChapterStateProvider(
mangaId: mangaId, mangaId: mangaId,
); );
} }
@override @override
ReverseChapterStateProvider getProviderOverride( SortChapterStateProvider getProviderOverride(
covariant ReverseChapterStateProvider provider, covariant SortChapterStateProvider provider,
) { ) {
return call( return call(
mangaId: provider.mangaId, mangaId: provider.mangaId,
@ -143,33 +126,33 @@ class ReverseChapterStateFamily extends Family<dynamic> {
_allTransitiveDependencies; _allTransitiveDependencies;
@override @override
String? get name => r'reverseChapterStateProvider'; String? get name => r'sortChapterStateProvider';
} }
/// See also [ReverseChapterState]. /// See also [SortChapterState].
class ReverseChapterStateProvider class SortChapterStateProvider
extends AutoDisposeNotifierProviderImpl<ReverseChapterState, dynamic> { extends AutoDisposeNotifierProviderImpl<SortChapterState, dynamic> {
/// See also [ReverseChapterState]. /// See also [SortChapterState].
ReverseChapterStateProvider({ SortChapterStateProvider({
required this.mangaId, required this.mangaId,
}) : super.internal( }) : super.internal(
() => ReverseChapterState()..mangaId = mangaId, () => SortChapterState()..mangaId = mangaId,
from: reverseChapterStateProvider, from: sortChapterStateProvider,
name: r'reverseChapterStateProvider', name: r'sortChapterStateProvider',
debugGetCreateSourceHash: debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') const bool.fromEnvironment('dart.vm.product')
? null ? null
: _$reverseChapterStateHash, : _$sortChapterStateHash,
dependencies: ReverseChapterStateFamily._dependencies, dependencies: SortChapterStateFamily._dependencies,
allTransitiveDependencies: allTransitiveDependencies:
ReverseChapterStateFamily._allTransitiveDependencies, SortChapterStateFamily._allTransitiveDependencies,
); );
final int mangaId; final int mangaId;
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is ReverseChapterStateProvider && other.mangaId == mangaId; return other is SortChapterStateProvider && other.mangaId == mangaId;
} }
@override @override
@ -182,7 +165,7 @@ class ReverseChapterStateProvider
@override @override
dynamic runNotifierBuild( dynamic runNotifierBuild(
covariant ReverseChapterState notifier, covariant SortChapterState notifier,
) { ) {
return notifier.build( return notifier.build(
mangaId: mangaId, mangaId: mangaId,
@ -687,7 +670,7 @@ class ChapterSetIsBookmarkStateProvider extends AutoDisposeNotifierProviderImpl<
} }
String _$chapterSetIsReadStateHash() => String _$chapterSetIsReadStateHash() =>
r'a8436a6cdac49c241483b4260f41c7b4045c060d'; r'b60dfd136e52743fdde9067d3e366d90d49dd9b4';
abstract class _$ChapterSetIsReadState abstract class _$ChapterSetIsReadState
extends BuildlessAutoDisposeNotifier<dynamic> { extends BuildlessAutoDisposeNotifier<dynamic> {
@ -881,297 +864,4 @@ class ChapterSetDownloadStateProvider
); );
} }
} }
String _$sortByUploadDateStateHash() =>
r'5dd31fd2ee8fbaa5f3f5c8e2397842fa60af8b46';
abstract class _$SortByUploadDateState
extends BuildlessAutoDisposeNotifier<bool> {
late final int mangaId;
bool build({
required int mangaId,
});
}
/// See also [SortByUploadDateState].
@ProviderFor(SortByUploadDateState)
const sortByUploadDateStateProvider = SortByUploadDateStateFamily();
/// See also [SortByUploadDateState].
class SortByUploadDateStateFamily extends Family<bool> {
/// See also [SortByUploadDateState].
const SortByUploadDateStateFamily();
/// See also [SortByUploadDateState].
SortByUploadDateStateProvider call({
required int mangaId,
}) {
return SortByUploadDateStateProvider(
mangaId: mangaId,
);
}
@override
SortByUploadDateStateProvider getProviderOverride(
covariant SortByUploadDateStateProvider provider,
) {
return call(
mangaId: provider.mangaId,
);
}
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'sortByUploadDateStateProvider';
}
/// See also [SortByUploadDateState].
class SortByUploadDateStateProvider
extends AutoDisposeNotifierProviderImpl<SortByUploadDateState, bool> {
/// See also [SortByUploadDateState].
SortByUploadDateStateProvider({
required this.mangaId,
}) : super.internal(
() => SortByUploadDateState()..mangaId = mangaId,
from: sortByUploadDateStateProvider,
name: r'sortByUploadDateStateProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$sortByUploadDateStateHash,
dependencies: SortByUploadDateStateFamily._dependencies,
allTransitiveDependencies:
SortByUploadDateStateFamily._allTransitiveDependencies,
);
final int mangaId;
@override
bool operator ==(Object other) {
return other is SortByUploadDateStateProvider && other.mangaId == mangaId;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, mangaId.hashCode);
return _SystemHash.finish(hash);
}
@override
bool runNotifierBuild(
covariant SortByUploadDateState notifier,
) {
return notifier.build(
mangaId: mangaId,
);
}
}
String _$sortBySourceStateHash() => r'b254edd8c935aafd1cb41e4841134d177b58ba62';
abstract class _$SortBySourceState extends BuildlessAutoDisposeNotifier<bool> {
late final int mangaId;
bool build({
required int mangaId,
});
}
/// See also [SortBySourceState].
@ProviderFor(SortBySourceState)
const sortBySourceStateProvider = SortBySourceStateFamily();
/// See also [SortBySourceState].
class SortBySourceStateFamily extends Family<bool> {
/// See also [SortBySourceState].
const SortBySourceStateFamily();
/// See also [SortBySourceState].
SortBySourceStateProvider call({
required int mangaId,
}) {
return SortBySourceStateProvider(
mangaId: mangaId,
);
}
@override
SortBySourceStateProvider getProviderOverride(
covariant SortBySourceStateProvider provider,
) {
return call(
mangaId: provider.mangaId,
);
}
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'sortBySourceStateProvider';
}
/// See also [SortBySourceState].
class SortBySourceStateProvider
extends AutoDisposeNotifierProviderImpl<SortBySourceState, bool> {
/// See also [SortBySourceState].
SortBySourceStateProvider({
required this.mangaId,
}) : super.internal(
() => SortBySourceState()..mangaId = mangaId,
from: sortBySourceStateProvider,
name: r'sortBySourceStateProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$sortBySourceStateHash,
dependencies: SortBySourceStateFamily._dependencies,
allTransitiveDependencies:
SortBySourceStateFamily._allTransitiveDependencies,
);
final int mangaId;
@override
bool operator ==(Object other) {
return other is SortBySourceStateProvider && other.mangaId == mangaId;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, mangaId.hashCode);
return _SystemHash.finish(hash);
}
@override
bool runNotifierBuild(
covariant SortBySourceState notifier,
) {
return notifier.build(
mangaId: mangaId,
);
}
}
String _$sortByChapterNumberStateHash() =>
r'c3f088a3235a0c0305b8c33376fa430950902fc6';
abstract class _$SortByChapterNumberState
extends BuildlessAutoDisposeNotifier<bool> {
late final int mangaId;
bool build({
required int mangaId,
});
}
/// See also [SortByChapterNumberState].
@ProviderFor(SortByChapterNumberState)
const sortByChapterNumberStateProvider = SortByChapterNumberStateFamily();
/// See also [SortByChapterNumberState].
class SortByChapterNumberStateFamily extends Family<bool> {
/// See also [SortByChapterNumberState].
const SortByChapterNumberStateFamily();
/// See also [SortByChapterNumberState].
SortByChapterNumberStateProvider call({
required int mangaId,
}) {
return SortByChapterNumberStateProvider(
mangaId: mangaId,
);
}
@override
SortByChapterNumberStateProvider getProviderOverride(
covariant SortByChapterNumberStateProvider provider,
) {
return call(
mangaId: provider.mangaId,
);
}
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'sortByChapterNumberStateProvider';
}
/// See also [SortByChapterNumberState].
class SortByChapterNumberStateProvider
extends AutoDisposeNotifierProviderImpl<SortByChapterNumberState, bool> {
/// See also [SortByChapterNumberState].
SortByChapterNumberStateProvider({
required this.mangaId,
}) : super.internal(
() => SortByChapterNumberState()..mangaId = mangaId,
from: sortByChapterNumberStateProvider,
name: r'sortByChapterNumberStateProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$sortByChapterNumberStateHash,
dependencies: SortByChapterNumberStateFamily._dependencies,
allTransitiveDependencies:
SortByChapterNumberStateFamily._allTransitiveDependencies,
);
final int mangaId;
@override
bool operator ==(Object other) {
return other is SortByChapterNumberStateProvider &&
other.mangaId == mangaId;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, mangaId.hashCode);
return _SystemHash.finish(hash);
}
@override
bool runNotifierBuild(
covariant SortByChapterNumberState notifier,
) {
return notifier.build(
mangaId: mangaId,
);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions // ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions

View file

@ -40,19 +40,17 @@ class ChapterListTileWidget extends ConsumerWidget {
onLongPress: () { onLongPress: () {
if (!isLongPressed) { if (!isLongPressed) {
ref.read(chaptersListStateProvider.notifier).update(chapter); ref.read(chaptersListStateProvider.notifier).update(chapter);
ref.read(chapterModelStateProvider.notifier).update(chapter);
ref ref
.read(isLongPressedStateProvider.notifier) .read(isLongPressedStateProvider.notifier)
.update(!isLongPressed); .update(!isLongPressed);
} else { } else {
ref.read(chaptersListStateProvider.notifier).update(chapter); ref.read(chaptersListStateProvider.notifier).update(chapter);
ref.read(chapterModelStateProvider.notifier).update(chapter);
} }
}, },
onTap: () async { onTap: () async {
if (isLongPressed) { if (isLongPressed) {
ref.read(chaptersListStateProvider.notifier).update(chapter); ref.read(chaptersListStateProvider.notifier).update(chapter);
ref.read(chapterModelStateProvider.notifier).update(chapter);
} else { } else {
pushMangaReaderView(context: context, chapter: chapter); pushMangaReaderView(context: context, chapter: chapter);
} }
@ -62,7 +60,7 @@ class ChapterListTileWidget extends ConsumerWidget {
chapter.isBookmarked! chapter.isBookmarked!
? Icon( ? Icon(
Icons.bookmark, Icons.bookmark,
size: 15, size: 16,
color: primaryColor(context), color: primaryColor(context),
) )
: Container(), : Container(),
@ -81,6 +79,7 @@ class ChapterListTileWidget extends ConsumerWidget {
dateFormat(chapter.dateUpload!, ref: ref), dateFormat(chapter.dateUpload!, ref: ref),
style: const TextStyle(fontSize: 11), style: const TextStyle(fontSize: 11),
), ),
if(!chapter.isRead!)
if (chapter.lastPageRead!.isNotEmpty && chapter.lastPageRead != "1") if (chapter.lastPageRead!.isNotEmpty && chapter.lastPageRead != "1")
Row( Row(
children: [ children: [

View file

@ -106,6 +106,11 @@ class ReaderController extends _$ReaderController {
void setMangaHistoryUpdate() { void setMangaHistoryUpdate() {
final incognitoMode = ref.watch(incognitoModeStateProvider); final incognitoMode = ref.watch(incognitoModeStateProvider);
if (!incognitoMode) { if (!incognitoMode) {
isar.writeTxnSync(() {
Manga? manga = chapter.manga.value;
manga!.lastRead = DateTime.now().millisecondsSinceEpoch;
isar.mangas.putSync(manga);
});
History? history; History? history;
final empty = final empty =
@ -205,9 +210,11 @@ class ReaderController extends _$ReaderController {
int getPageIndex() { int getPageIndex() {
final incognitoMode = ref.watch(incognitoModeStateProvider); final incognitoMode = ref.watch(incognitoModeStateProvider);
if (!incognitoMode) { if (!incognitoMode) {
return ref.watch(hiveBoxMangaProvider).get( return chapter.isRead!
"${getSourceName()}/${getMangaName()}/${getChapterTitle()}-page_index", ? 0
defaultValue: 0); : ref.watch(hiveBoxMangaProvider).get(
"${getSourceName()}/${getMangaName()}/${getChapterTitle()}-page_index",
defaultValue: 0);
} }
return 0; return 0;
} }

View file

@ -181,7 +181,7 @@ class CurrentIndexProvider
} }
} }
String _$readerControllerHash() => r'232cc4cde708015a3b4cdac481c61cff82076182'; String _$readerControllerHash() => r'cd0b65db9c027393d7b0f6cf1b7000847623364d';
abstract class _$ReaderController extends BuildlessAutoDisposeNotifier<void> { abstract class _$ReaderController extends BuildlessAutoDisposeNotifier<void> {
late final Chapter chapter; late final Chapter chapter;

View file

@ -13,7 +13,7 @@ class CoverViewWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(5),
child: isComfortableGrid child: isComfortableGrid
? Column( ? Column(
children: [ children: [

View file

@ -28,16 +28,16 @@ class MangaImageCardWidget extends StatelessWidget {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
final manga = Manga( final manga = Manga(
imageUrl: getMangaDetailModel!.imageUrl, imageUrl: getMangaDetailModel!.imageUrl,
name: getMangaDetailModel!.name, name: getMangaDetailModel!.name,
genre: getMangaDetailModel!.genre, genre: getMangaDetailModel!.genre,
author: getMangaDetailModel!.author, author: getMangaDetailModel!.author,
status: getMangaDetailModel!.status, status: getMangaDetailModel!.status,
description: getMangaDetailModel!.description, description: getMangaDetailModel!.description,
link: getMangaDetailModel!.url, link: getMangaDetailModel!.url,
source: getMangaDetailModel!.source, source: getMangaDetailModel!.source,
lang: lang, lang: lang,
); lastUpdate: DateTime.now().millisecondsSinceEpoch);
final empty = isar.mangas final empty = isar.mangas
.filter() .filter()