add library category sort & selectable multiple for multiple action
This commit is contained in:
parent
5b96bdea5c
commit
c7b910c807
21 changed files with 2241 additions and 1753 deletions
|
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
},
|
|
||||||
)))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
46
lib/views/library/widgets/list_tile_manga_category.dart
Normal file
46
lib/views/library/widgets/list_tile_manga_category.dart
Normal 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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: [
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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: [
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue