mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-03-11 17:25:32 +00:00
feature sort ,filter & widget update
This commit is contained in:
parent
923660dcea
commit
143756cff6
10 changed files with 473 additions and 236 deletions
|
|
@ -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"))
|
||||
]),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
);
|
||||
|
|
|
|||
74
lib/views/library/widgets/library_gridview_widget.dart
Normal file
74
lib/views/library/widgets/library_gridview_widget.dart
Normal 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!)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
;
|
||||
}
|
||||
}
|
||||
88
lib/views/library/widgets/library_listview_widget.dart
Normal file
88
lib/views/library/widgets/library_listview_widget.dart
Normal 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()),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -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: [
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
9
lib/views/manga/detail/providers/state_providers.dart
Normal file
9
lib/views/manga/detail/providers/state_providers.dart
Normal 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',
|
||||
);
|
||||
|
|
@ -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),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
25
lib/views/widgets/listview_widget.dart
Normal file
25
lib/views/widgets/listview_widget.dart
Normal 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),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue