feature sort ,filter & widget update

This commit is contained in:
kodjodevf 2023-04-07 14:15:07 +01:00
parent 923660dcea
commit 143756cff6
10 changed files with 473 additions and 236 deletions

View file

@ -1,16 +1,15 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:mangayomi/models/model_manga.dart';
import 'package:mangayomi/providers/hive_provider.dart';
import 'package:mangayomi/utils/cached_network.dart';
import 'package:mangayomi/utils/media_query.dart';
import 'package:mangayomi/views/library/providers/state_providers.dart';
import 'package:mangayomi/views/library/search_text_form_field.dart';
import 'package:mangayomi/views/widgets/bottom_text_widget.dart';
import 'package:mangayomi/views/widgets/cover_view_widget.dart';
import 'package:mangayomi/views/widgets/gridview_widget.dart';
import 'package:mangayomi/views/library/widgets/library_gridview_widget.dart';
import 'package:mangayomi/views/library/widgets/library_listview_widget.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
class LibraryScreen extends ConsumerStatefulWidget {
@ -30,6 +29,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
@override
Widget build(BuildContext context) {
final reverse = ref.watch(reverseStateProvider);
final display = ref.watch(displayValueStateProvider);
return Scaffold(
appBar: AppBar(
elevation: 0,
@ -74,26 +74,15 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
},
icon: Icon(Icons.filter_list_sharp,
color: Theme.of(context).hintColor)),
PopupMenuButton(
color: Theme.of(context).hintColor,
itemBuilder: (context) {
return [
const PopupMenuItem<int>(value: 0, child: Text("1")),
const PopupMenuItem<int>(
value: 1,
child: Text("2"),
),
const PopupMenuItem<int>(
value: 2,
child: Text("3"),
),
];
},
onSelected: (value) {
if (value == 0) {
} else if (value == 1) {
} else if (value == 2) {}
}),
// PopupMenuButton(
// color: Theme.of(context).hintColor,
// itemBuilder: (context) {
// return [
// const PopupMenuItem<int>(
// value: 0, child: Text("Open random entry")),
// ];
// },
// onSelected: (value) {}),
],
),
body: ValueListenableBuilder<Box<ModelManga>>(
@ -106,63 +95,13 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
? entries.reversed.toList()
: entries;
if (entries.isNotEmpty || entriesFilter.isNotEmpty) {
return GridViewWidget(
itemCount: entriesManga.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
final model = ModelManga(
imageUrl: entriesManga[index].imageUrl,
name: entriesManga[index].name,
genre: entriesManga[index].genre,
author: entriesManga[index].author,
status: entriesManga[index].status,
chapterDate: entriesManga[index].chapterDate,
chapterTitle: entriesManga[index].chapterTitle,
chapterUrl: entriesManga[index].chapterUrl,
description: entriesManga[index].description,
favorite: entriesManga[index].favorite,
link: entriesManga[index].link,
source: entriesManga[index].source,
lang: entriesManga[index].lang);
context.push('/manga-reader/detail', extra: model);
},
child: CoverViewWidget(
children: [
Stack(
children: [
cachedNetworkImage(
imageUrl: entriesManga[index].imageUrl!,
width: 200,
height: 270,
fit: BoxFit.cover),
Positioned(
top: 0,
left: 0,
child: Padding(
padding: const EdgeInsets.all(5),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
color: Theme.of(context).cardColor),
child: Padding(
padding: const EdgeInsets.all(1),
child: Text(entriesManga[index]
.chapterDate!
.length
.toString()),
),
),
))
],
),
BottomTextWidget(text: entriesManga[index].name!)
],
),
);
},
);
return display == 'List'
? LibraryListViewWidget(
entriesManga: entriesManga,
)
: LibraryGridViewWidget(
entriesManga: entriesManga,
);
}
return const Center(child: Text("Empty Library"));
},
@ -171,11 +110,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
}
_showModalSort() {
List<String> sortList = [
"Alphabetically",
"Total chapters",
"Latest chapter",
"Date added"
List<String> displayList = [
"Compact grid",
"List",
];
late TabController tabBarController;
showMaterialModalBottomSheet(
@ -192,7 +129,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
tabBarController.animateTo(0);
}
return SizedBox(
height: mediaHeight(context, 0.4),
height: mediaHeight(context, 0.3),
child: DefaultTabController(
length: 3,
child: Scaffold(
@ -214,37 +151,49 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
Consumer(builder: (context, ref, chil) {
final reverse =
ref.watch(reverseStateProvider);
final sortedValue =
ref.watch(sortedValueStateProvider);
return Column(
children: [
for (var i = 0; i < sortList.length; i++)
ListTile(
onTap: () {
ListTile(
onTap: () {
ref
.read(
reverseStateProvider.notifier)
.state = !reverse;
},
dense: true,
leading: Icon(reverse
? Icons.arrow_downward_sharp
: Icons.arrow_upward_sharp),
title: const Text("Alphabetically"),
),
],
);
}),
Consumer(builder: (context, ref, chil) {
final display =
ref.watch(displayValueStateProvider);
return Column(
children: [
for (var i = 0;
i < displayList.length;
i++)
RadioListTile(
title: Text(displayList[i]),
value: displayList[i],
groupValue: display,
selected: true,
onChanged: (value) {
ref
.read(reverseStateProvider
.read(displayValueStateProvider
.notifier)
.state = !reverse;
ref
.read(sortedValueStateProvider
.notifier)
.state = sortList[i];
.state = value.toString();
},
dense: true,
leading: sortedValue == sortList[i]
? Icon(reverse
? Icons.arrow_downward_sharp
: Icons.arrow_upward_sharp)
: const Icon(
Icons.arrow_upward_sharp,
color: Colors.transparent,
),
title: Text(sortList[i]),
),
],
);
}),
const Center(child: Text("soon"))
]),
),
],

View file

@ -4,6 +4,6 @@ final reverseStateProvider = StateProvider.autoDispose<bool>(
(ref) => false,
);
final sortedValueStateProvider = StateProvider.autoDispose<String>(
(ref) => 'Alphabetically',
final displayValueStateProvider = StateProvider.autoDispose<String>(
(ref) => 'Compact grid',
);

View file

@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:mangayomi/models/model_manga.dart';
import 'package:mangayomi/utils/cached_network.dart';
import 'package:mangayomi/views/widgets/bottom_text_widget.dart';
import 'package:mangayomi/views/widgets/cover_view_widget.dart';
import 'package:mangayomi/views/widgets/gridview_widget.dart';
class LibraryGridViewWidget extends StatelessWidget {
final List<ModelManga> entriesManga;
const LibraryGridViewWidget({super.key, required this.entriesManga});
@override
Widget build(BuildContext context) {
return GridViewWidget(
itemCount: entriesManga.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
final model = ModelManga(
imageUrl: entriesManga[index].imageUrl,
name: entriesManga[index].name,
genre: entriesManga[index].genre,
author: entriesManga[index].author,
status: entriesManga[index].status,
chapterDate: entriesManga[index].chapterDate,
chapterTitle: entriesManga[index].chapterTitle,
chapterUrl: entriesManga[index].chapterUrl,
description: entriesManga[index].description,
favorite: entriesManga[index].favorite,
link: entriesManga[index].link,
source: entriesManga[index].source,
lang: entriesManga[index].lang);
context.push('/manga-reader/detail', extra: model);
},
child: CoverViewWidget(
children: [
Stack(
children: [
cachedNetworkImage(
imageUrl: entriesManga[index].imageUrl!,
width: 200,
height: 270,
fit: BoxFit.cover),
Positioned(
top: 0,
left: 0,
child: Padding(
padding: const EdgeInsets.all(5),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
color: Theme.of(context).cardColor),
child: Padding(
padding: const EdgeInsets.all(1),
child: Text(entriesManga[index]
.chapterDate!
.length
.toString()),
),
),
))
],
),
BottomTextWidget(text: entriesManga[index].name!)
],
),
);
},
);
;
}
}

View file

@ -0,0 +1,88 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:mangayomi/models/model_manga.dart';
import 'package:mangayomi/utils/cached_network.dart';
import 'package:mangayomi/utils/media_query.dart';
import 'package:mangayomi/views/widgets/listview_widget.dart';
class LibraryListViewWidget extends StatelessWidget {
final List<ModelManga> entriesManga;
const LibraryListViewWidget({super.key, required this.entriesManga});
@override
Widget build(BuildContext context) {
return ListViewWidget(
itemCount: entriesManga.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
final model = ModelManga(
imageUrl: entriesManga[index].imageUrl,
name: entriesManga[index].name,
genre: entriesManga[index].genre,
author: entriesManga[index].author,
status: entriesManga[index].status,
chapterDate: entriesManga[index].chapterDate,
chapterTitle: entriesManga[index].chapterTitle,
chapterUrl: entriesManga[index].chapterUrl,
description: entriesManga[index].description,
favorite: entriesManga[index].favorite,
link: entriesManga[index].link,
source: entriesManga[index].source,
lang: entriesManga[index].lang);
context.push('/manga-reader/detail', extra: model);
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 45,
decoration: BoxDecoration(
color: Theme.of(context).canvasColor,
borderRadius: BorderRadius.circular(5)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(5),
bottomLeft: Radius.circular(5)),
child: cachedNetworkImage(
imageUrl: entriesManga[index].imageUrl!,
width: 30,
height: 40,
fit: BoxFit.cover),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: SizedBox(
width: mediaWidth(context, 0.7),
child: Text(entriesManga[index].name!)),
),
],
),
Padding(
padding: const EdgeInsets.all(5),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
color: Theme.of(context).cardColor),
child: Padding(
padding: const EdgeInsets.all(1),
child: Text(
entriesManga[index].chapterDate!.length.toString()),
),
),
)
],
),
),
),
);
},
);
;
}
}

View file

@ -1,5 +1,3 @@
import 'dart:developer';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:draggable_scrollbar/draggable_scrollbar.dart';
import 'package:flutter/material.dart';
@ -10,6 +8,7 @@ import 'package:mangayomi/models/manga_reader.dart';
import 'package:mangayomi/models/model_manga.dart';
import 'package:mangayomi/utils/cached_network.dart';
import 'package:mangayomi/utils/media_query.dart';
import 'package:mangayomi/views/manga/detail/providers/state_providers.dart';
import 'package:mangayomi/views/manga/detail/readmore.dart';
class MangaDetailView extends ConsumerStatefulWidget {
@ -34,7 +33,8 @@ class MangaDetailView extends ConsumerStatefulWidget {
ConsumerState<MangaDetailView> createState() => _MangaDetailViewState();
}
class _MangaDetailViewState extends ConsumerState<MangaDetailView> {
class _MangaDetailViewState extends ConsumerState<MangaDetailView>
with TickerProviderStateMixin {
@override
void initState() {
_scrollController = ScrollController()
@ -45,7 +45,8 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView> {
}
final offetProvider = StateProvider((ref) => 0.0);
bool _reverse = false;
bool isOk = false;
bool _expanded = false;
ScrollController _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
@ -65,91 +66,124 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView> {
preferredSize: Size.fromHeight(AppBar().preferredSize.height),
child: Consumer(
builder: (context, ref, child) {
final reverse = ref.watch(reverseMangaStateProvider);
return AppBar(
title: ref.watch(offetProvider) > 200
? Text(widget.modelManga!.name!)
? Text(
widget.modelManga!.name!,
style: const TextStyle(fontSize: 17),
)
: null,
backgroundColor: ref.watch(offetProvider) == 0.0
? Colors.transparent
: Theme.of(context).scaffoldBackgroundColor,
actions: [
// IconButton(
// splashRadius: 20,
// onPressed: () {},
// icon: Icon(Icons.download_outlined,
// color: Theme.of(context).hintColor)),
IconButton(
splashRadius: 20,
onPressed: () {},
icon: Icon(Icons.download_outlined,
color: Theme.of(context).hintColor)),
IconButton(
splashRadius: 20,
onPressed: () {},
icon: Icon(Icons.filter_list_sharp,
color: Theme.of(context).hintColor)),
PopupMenuButton(
color: Theme.of(context).hintColor,
itemBuilder: (context) {
return [
const PopupMenuItem<int>(
value: 0,
child: Text("1"),
),
const PopupMenuItem<int>(
value: 1,
child: Text("2"),
),
const PopupMenuItem<int>(
value: 2,
child: Text("3"),
),
];
onPressed: () {
ref.read(reverseMangaStateProvider.notifier).state =
!reverse;
},
onSelected: (value) {
if (value == 0) {
} else if (value == 1) {
} else if (value == 2) {}
}),
icon: Icon(
reverse
? Icons.arrow_downward_sharp
: Icons.arrow_upward_sharp,
color: Theme.of(context).hintColor)),
],
);
},
)),
body: _listView(),
body: Stack(
children: [
Positioned(
top: 0,
child: Stack(
children: [
cachedNetworkImage(
imageUrl: widget.modelManga!.imageUrl!,
width: mediaWidth(context, 1),
height: 461,
fit: BoxFit.cover),
Container(
width: mediaWidth(context, 1),
height: 465,
color: Theme.of(context)
.scaffoldBackgroundColor
.withOpacity(0.9),
),
SafeArea(
child: Container(
width: mediaWidth(context, 1),
height: mediaHeight(context, 1),
color: Theme.of(context).scaffoldBackgroundColor),
)
],
)),
SafeArea(child: _listView()),
],
),
));
}
_listView() {
return DraggableScrollbar.rrect(
alwaysVisibleScrollThumb: true,
controller: _scrollController,
child: ListView.builder(
controller: _scrollController,
padding: const EdgeInsets.only(top: 0),
reverse: _reverse,
itemCount: widget.listLength,
itemBuilder: (context, index) {
int finalIndex = index - 1;
if (index == 0) {
return _bodyContainer();
}
return ListTile(
key: ObjectKey(widget.modelManga!.chapterUrl),
onTap: () {
pushMangaReaderView(
context: context,
modelManga: widget.modelManga!,
index: finalIndex);
},
trailing: const Icon(
FontAwesomeIcons.circleDown,
size: 20,
),
subtitle: Text(
widget.modelManga!.chapterDate![finalIndex],
style: const TextStyle(fontSize: 12),
),
title: Text(
widget.modelManga!.chapterTitle![finalIndex],
style: const TextStyle(fontSize: 13),
),
);
}));
Widget _listView() {
return Consumer(builder: (context, ref, child) {
final reverse = ref.watch(reverseMangaStateProvider);
return DraggableScrollbar.rrect(
scrollbarTimeToFade: const Duration(seconds: 2),
controller: _scrollController,
child: ListView.builder(
controller: _scrollController,
padding: const EdgeInsets.only(top: 0),
itemCount: widget.listLength,
itemBuilder: (context, index) {
int finalIndex = index - 1;
if (index == 0) {
return _bodyContainer();
}
int reverseIndex = widget.modelManga!.chapterDate!.length -
widget.modelManga!.chapterDate!.reversed.toList().indexOf(
widget.modelManga!.chapterDate!.reversed
.toList()[finalIndex]) -
1;
List<String>? chapterUrl = reverse
? widget.modelManga!.chapterUrl!.reversed.toList()
: widget.modelManga!.chapterUrl!;
List<String>? chapterDate = reverse
? widget.modelManga!.chapterDate!.reversed.toList()
: widget.modelManga!.chapterDate!;
List<String>? chapterTitle = reverse
? widget.modelManga!.chapterTitle!.reversed.toList()
: widget.modelManga!.chapterTitle!;
return ListTile(
key: ObjectKey(chapterUrl),
onTap: () {
pushMangaReaderView(
context: context,
modelManga: widget.modelManga!,
index: reverse ? reverseIndex : finalIndex);
},
trailing: const Icon(
FontAwesomeIcons.circleDown,
size: 20,
),
subtitle: Text(
chapterDate[finalIndex],
style: const TextStyle(fontSize: 12),
),
title: Text(
chapterTitle[finalIndex],
style: const TextStyle(fontSize: 13),
),
);
}));
});
}
Widget _bodyContainer() {
@ -164,18 +198,15 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView> {
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Theme.of(context).scaffoldBackgroundColor.withOpacity(0.6),
Theme.of(context).scaffoldBackgroundColor.withOpacity(0.9),
Color(Theme.of(context).scaffoldBackgroundColor.value)
],
stops: const [0, .8],
stops: const [0, .35],
),
),
),
Column(
children: [
SizedBox(
height: AppBar().preferredSize.height * 1.5,
),
SizedBox(
height: 180,
child: Stack(
@ -197,36 +228,71 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView> {
padding: const EdgeInsets.all(8.0),
child: ReadMoreWidget(
text: widget.modelManga!.description!,
onChanged: (value) {
setState(() {
_expanded = value;
});
},
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Wrap(
children: [
for (var i = 0;
i < widget.modelManga!.genre!.length;
i++)
Padding(
padding: const EdgeInsets.only(
left: 2, right: 2, bottom: 5),
child: SizedBox(
height: 30,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
shape: BeveledRectangleBorder(
borderRadius:
BorderRadius.circular(3))),
onPressed: () {},
child: Text(
widget.modelManga!.genre![i],
style: const TextStyle(fontSize: 12),
),
padding: const EdgeInsets.symmetric(horizontal: 12),
child: _expanded
? Wrap(
children: [
for (var i = 0;
i < widget.modelManga!.genre!.length;
i++)
Padding(
padding: const EdgeInsets.only(
left: 2, right: 2, bottom: 5),
child: SizedBox(
height: 30,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5))),
onPressed: () {},
child: Text(
widget.modelManga!.genre![i],
style: const TextStyle(fontSize: 12),
),
),
),
),
],
)
: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
for (var i = 0;
i < widget.modelManga!.genre!.length;
i++)
Padding(
padding: const EdgeInsets.only(
left: 2, right: 2, bottom: 5),
child: SizedBox(
height: 30,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
5))),
onPressed: () {},
child: Text(
widget.modelManga!.genre![i],
style:
const TextStyle(fontSize: 12),
),
),
),
),
],
),
),
),
],
),
),
)),
// log
Column(
children: [

View file

@ -113,7 +113,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
width: !ref.watch(isExtended)
? 60
: mediaWidth(context, 0.25),
duration: const Duration(milliseconds: 500),
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
@ -126,7 +126,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
AnimatedContainer(
curve: Curves.easeIn,
width: !ref.watch(isExtended) ? 0 : 30,
duration: const Duration(milliseconds: 500),
duration: const Duration(milliseconds: 300),
child: const Text(
"Read",
overflow: TextOverflow.ellipsis,
@ -136,7 +136,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
AnimatedContainer(
curve: Curves.easeIn,
width: !ref.watch(isExtended) ? 0 : 10,
duration: const Duration(milliseconds: 500),
duration: const Duration(milliseconds: 300),
),
const Icon(
Icons.play_arrow,

View file

@ -0,0 +1,9 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
final reverseMangaStateProvider = StateProvider.autoDispose<bool>(
(ref) => false,
);
final sortedMangaValueStateProvider = StateProvider.autoDispose<String>(
(ref) => 'By source',
);

View file

@ -3,8 +3,9 @@ import 'package:flutter/material.dart';
import 'package:mangayomi/utils/media_query.dart';
class ReadMoreWidget extends StatefulWidget {
const ReadMoreWidget({Key? key, required this.text}) : super(key: key);
const ReadMoreWidget({Key? key, required this.text, required this.onChanged})
: super(key: key);
final Function(bool) onChanged;
final String text;
@override
@ -24,6 +25,7 @@ class ReadMoreWidgetState extends State<ReadMoreWidget>
animationDuration: const Duration(milliseconds: 500),
onExpandedChanged: (ok) {
setState(() => expanded = ok);
widget.onChanged(ok);
},
expandOnTextTap: true,
widget.text,
@ -32,25 +34,46 @@ class ReadMoreWidgetState extends State<ReadMoreWidget>
expanded: false,
onPrefixTap: () {
setState(() => expanded = !expanded);
widget.onChanged(expanded);
},
linkColor: Theme.of(context).scaffoldBackgroundColor,
animation: true,
collapseOnTextTap: true,
prefixText: '',
),
Positioned(
if (!expanded)
Positioned(
bottom: 0,
left: 0,
right: 0,
child: expanded
? const Icon(Icons.keyboard_arrow_up_sharp)
: const Icon(Icons.keyboard_arrow_down_sharp))
left: 0,
child: Container(
width: mediaWidth(context, 1),
height: 20,
decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor,
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Theme.of(context)
.scaffoldBackgroundColor
.withOpacity(0.2),
Theme.of(context).scaffoldBackgroundColor
],
stops: const [0, .9],
),
),
child: const Icon(Icons.keyboard_arrow_down_sharp),
),
),
],
),
Container(
color: Theme.of(context).cardColor.withOpacity(0.15),
width: mediaWidth(context, 1),
)
if (expanded)
SizedBox(
width: mediaWidth(context, 1),
height: 20,
child: const Icon(Icons.keyboard_arrow_up_sharp),
)
],
);
}

View file

@ -216,13 +216,16 @@ class _MangaChapterPageGalleryState
widget.modelManga.link,
MangaHistoryModel(
date: DateTime.now().toString(), modelManga: widget.modelManga));
setState(() {
_currentIndex = index;
if (_imageDetailY != 0) {
_imageDetailY = 0;
_rebuildDetail.sink.add(_imageDetailY);
}
});
if (mounted) {
setState(() {
_currentIndex = index;
if (_imageDetailY != 0) {
_imageDetailY = 0;
_rebuildDetail.sink.add(_imageDetailY);
}
});
}
ref.watch(hiveBoxMangaInfo).put(
"${widget.source}/${widget.titleManga}/${widget.chapter}-page_index",
index);

View file

@ -0,0 +1,25 @@
import 'package:flutter/material.dart';
class ListViewWidget extends StatelessWidget {
final ScrollController? controller;
final int? itemCount;
final bool reverse;
final Widget? Function(BuildContext, int) itemBuilder;
const ListViewWidget(
{super.key,
this.controller,
required this.itemCount,
required this.itemBuilder,
this.reverse = false});
@override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).scaffoldBackgroundColor,
child: ListView.builder(
controller: controller,
itemCount: itemCount,
itemBuilder: itemBuilder),
);
}
}