Skip to content

Commit 0aace90

Browse files
committed
feat(manga): adaptors
1 parent d5b452d commit 0aace90

21 files changed

+1025
-110
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
2+
import 'package:flutter/material.dart';
3+
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
4+
5+
import '../../Animation/ScaleAnimation.dart';
6+
import '../../DataClass/Chapter.dart';
7+
import '../../DataClass/Media.dart';
8+
import '../../api/Mangayomi/Model/Source.dart';
9+
import 'ChapterCompactViewHolder.dart';
10+
import 'ChapterListViewHolder.dart';
11+
12+
class ChapterAdaptor extends StatefulWidget {
13+
final int type;
14+
final Source source;
15+
final List<Chapter> chapterList;
16+
final Media mediaData;
17+
final VoidCallback? onEpisodeClick;
18+
19+
const ChapterAdaptor({
20+
super.key,
21+
required this.type,
22+
required this.source,
23+
required this.chapterList,
24+
required this.mediaData,
25+
this.onEpisodeClick,
26+
});
27+
28+
@override
29+
ChapterAdaptorState createState() => ChapterAdaptorState();
30+
}
31+
32+
class ChapterAdaptorState extends State<ChapterAdaptor> {
33+
late List<Chapter> chapterList;
34+
35+
@override
36+
void initState() {
37+
super.initState();
38+
chapterList = widget.chapterList;
39+
}
40+
41+
@override
42+
void didUpdateWidget(ChapterAdaptor oldWidget) {
43+
super.didUpdateWidget(oldWidget);
44+
if (oldWidget.chapterList != widget.chapterList) {
45+
chapterList = widget.chapterList;
46+
}
47+
}
48+
49+
@override
50+
Widget build(BuildContext context) {
51+
switch (widget.type) {
52+
case 0:
53+
return _buildListLayout();
54+
case 1:
55+
return _buildCompactView();
56+
default:
57+
return _buildListLayout();
58+
}
59+
}
60+
61+
Widget _buildListLayout() {
62+
return AnimatedSwitcher(
63+
duration: const Duration(milliseconds: 500),
64+
child: Container(
65+
constraints: const BoxConstraints(maxHeight: double.infinity),
66+
child: ListView.builder(
67+
physics: const NeverScrollableScrollPhysics(),
68+
shrinkWrap: true,
69+
itemCount: chapterList.length,
70+
itemBuilder: (context, index) {
71+
return SlideAndScaleAnimation(
72+
initialScale: 0.0,
73+
finalScale: 1.0,
74+
initialOffset: const Offset(1.0, 0.0),
75+
finalOffset: Offset.zero,
76+
duration: const Duration(milliseconds: 200),
77+
child: GestureDetector(
78+
onTap: () {},
79+
child: SizedBox(
80+
width: double.infinity,
81+
child: ChapterListView(
82+
chapter: chapterList[index],
83+
mediaData: widget.mediaData,
84+
),
85+
),
86+
),
87+
);
88+
},
89+
),
90+
),
91+
);
92+
}
93+
Widget _buildCompactView(){
94+
return LayoutBuilder(
95+
builder: (context, constraints) {
96+
final parentWidth = constraints.maxWidth;
97+
var crossAxisCount = (parentWidth / 82).floor();
98+
if (crossAxisCount < 1) crossAxisCount = 1;
99+
return AnimatedSwitcher(
100+
duration: const Duration(milliseconds: 500),
101+
child: Padding(
102+
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
103+
child: StaggeredGrid.count(
104+
crossAxisCount: crossAxisCount,
105+
children: List.generate(
106+
chapterList.length,
107+
(index) {
108+
return SlideAndScaleAnimation(
109+
initialScale: 0.0,
110+
finalScale: 1.0,
111+
initialOffset: const Offset(1.0, 0.0),
112+
finalOffset: Offset.zero,
113+
duration: const Duration(milliseconds: 200),
114+
child: GestureDetector(
115+
onTap: () {},
116+
onLongPress: () {},
117+
child: SizedBox(
118+
width: 82,
119+
height: 82,
120+
child: ChapterCompactView(
121+
chapter: chapterList[index],
122+
mediaData: widget.mediaData,
123+
),
124+
),
125+
),
126+
);
127+
},
128+
),
129+
),
130+
),
131+
);
132+
},
133+
);
134+
}
135+
}
136+
137+
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import 'package:dantotsu/Functions/string_extensions.dart';
2+
import 'package:flutter/material.dart';
3+
4+
import '../../DataClass/Chapter.dart';
5+
import '../../DataClass/Media.dart';
6+
import '../Episode/Widget/HandleProgress.dart';
7+
8+
class ChapterCompactView extends StatelessWidget {
9+
final Chapter chapter;
10+
final Media mediaData;
11+
final bool isWatched;
12+
13+
ChapterCompactView({
14+
super.key,
15+
required this.chapter,
16+
required this.mediaData,
17+
}) : isWatched = (mediaData.userProgress != null &&
18+
mediaData.userProgress! > 0)
19+
? mediaData.userProgress!.toDouble() >= chapter.number.toDouble()
20+
: false;
21+
22+
@override
23+
Widget build(BuildContext context) {
24+
return Card(
25+
shape: RoundedRectangleBorder(
26+
borderRadius: BorderRadius.circular(16),
27+
),
28+
margin: const EdgeInsets.all(8),
29+
clipBehavior: Clip.hardEdge,
30+
elevation: 4,
31+
child: Stack(
32+
children: [
33+
Container(
34+
decoration: BoxDecoration(
35+
borderRadius: BorderRadius.circular(16),
36+
color: Theme.of(context).colorScheme.surfaceVariant,
37+
),
38+
),
39+
40+
Align(
41+
alignment: Alignment.bottomCenter,
42+
child: handleProgress(
43+
context: context,
44+
mediaId: mediaData.id,
45+
ep: chapter.number,
46+
width: 162,
47+
),
48+
),
49+
Center(
50+
child: Text(
51+
chapter.number,
52+
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
53+
fontWeight: FontWeight.bold,
54+
fontSize: 16,
55+
),
56+
),
57+
),
58+
59+
// Viewed cover
60+
if (isWatched)
61+
Container(
62+
decoration: BoxDecoration(
63+
color:
64+
Theme.of(context).colorScheme.background.withOpacity(0.33),
65+
borderRadius: BorderRadius.circular(16),
66+
),
67+
),
68+
],
69+
),
70+
);
71+
}
72+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import 'package:dantotsu/Functions/string_extensions.dart';
2+
import 'package:flutter/material.dart';
3+
import '../../DataClass/Chapter.dart';
4+
import '../../DataClass/Media.dart';
5+
import '../../Screens/Info/Tabs/Watch/Manga/DateFormat.dart';
6+
import '../Episode/Widget/HandleProgress.dart';
7+
8+
class ChapterListView extends StatelessWidget {
9+
final Chapter chapter;
10+
final Media mediaData;
11+
final bool isWatched;
12+
13+
ChapterListView({
14+
super.key,
15+
required this.chapter,
16+
required this.mediaData,
17+
}) : isWatched =
18+
(mediaData.userProgress != null && mediaData.userProgress! > 0)
19+
? mediaData.userProgress!.toString().toDouble() >=
20+
chapter.number.toDouble()
21+
: false;
22+
23+
@override
24+
Widget build(BuildContext context) {
25+
final theme = Theme.of(context).colorScheme;
26+
27+
return Opacity(
28+
opacity: isWatched ? 0.5 : 1.0,
29+
child: Card(
30+
margin: const EdgeInsets.all(8),
31+
shape: RoundedRectangleBorder(
32+
borderRadius: BorderRadius.circular(18),
33+
),
34+
elevation: 4,
35+
child: SizedBox(
36+
height: 84,
37+
child: _buildChapterHeader(
38+
context,
39+
theme,
40+
),
41+
),
42+
),
43+
);
44+
}
45+
46+
Widget _buildChapterHeader(BuildContext context, ColorScheme theme) {
47+
return Row(
48+
crossAxisAlignment: CrossAxisAlignment.center,
49+
children: [
50+
Expanded(
51+
child: Padding(
52+
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
53+
child: Column(
54+
crossAxisAlignment: CrossAxisAlignment.start,
55+
mainAxisAlignment: MainAxisAlignment.center,
56+
children: [
57+
Text(
58+
chapter.title ?? '',
59+
maxLines: 1,
60+
style: const TextStyle(
61+
fontFamily: 'Poppins',
62+
fontWeight: FontWeight.bold,
63+
overflow: TextOverflow.ellipsis,
64+
),
65+
),
66+
if (chapter.mChapter?.scanlator != null &&
67+
chapter.mChapter?.scanlator != '')
68+
SizedBox(height: 4),
69+
_buildDescription(theme, context),
70+
],
71+
),
72+
),
73+
),
74+
if (isWatched)
75+
Icon(
76+
Icons.remove_red_eye,
77+
color: theme.onSurface,
78+
size: 26,
79+
),
80+
SizedBox(width: 8),
81+
],
82+
);
83+
}
84+
85+
Widget _buildDescription(ColorScheme theme, BuildContext context) {
86+
final List<TextSpan> spans = [];
87+
if (chapter.date != null) {
88+
spans.add(
89+
TextSpan(
90+
text: dateFormat(chapter.date, context: context),
91+
),
92+
);
93+
}
94+
if (chapter.date != null && chapter.mChapter?.scanlator != null) {
95+
spans.add(
96+
TextSpan(
97+
text: ' • ',
98+
),
99+
);
100+
}
101+
if (chapter.mChapter?.scanlator != null) {
102+
spans.add(
103+
TextSpan(
104+
text: chapter.mChapter?.scanlator?.replaceAll('_', ' ') ?? '',
105+
),
106+
);
107+
}
108+
return Flexible(
109+
child: RichText(
110+
maxLines: 1,
111+
text: TextSpan(
112+
children: spans,
113+
style: TextStyle(
114+
color: theme.onSurface,
115+
fontFamily: 'Poppins',
116+
fontWeight: FontWeight.w400,
117+
overflow: TextOverflow.ellipsis,
118+
),
119+
),
120+
),
121+
);
122+
}
123+
124+
Widget _buildThumbnail(BuildContext context, ColorScheme theme) {
125+
return Card(
126+
shape: RoundedRectangleBorder(
127+
borderRadius: BorderRadius.circular(16),
128+
),
129+
clipBehavior: Clip.hardEdge,
130+
elevation: 4,
131+
color: theme.surfaceContainerLowest,
132+
child: Stack(
133+
alignment: Alignment.bottomCenter,
134+
children: [
135+
handleProgress(
136+
context: context,
137+
mediaId: mediaData.id,
138+
ep: chapter.number,
139+
width: 162,
140+
)
141+
],
142+
),
143+
);
144+
}
145+
}

0 commit comments

Comments
 (0)