Skip to content

Commit bf0459d

Browse files
committed
fix: wrong current page
1 parent ea01276 commit bf0459d

File tree

4 files changed

+151
-75
lines changed

4 files changed

+151
-75
lines changed

lib/Screens/Manga/MangaReader/Reader.dart

Lines changed: 129 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
import 'dart:io';
2+
13
import 'package:cached_network_image/cached_network_image.dart';
24
import 'package:dartotsu/Widgets/ScrollConfig.dart';
5+
import 'package:flutter/gestures.dart';
36
import 'package:flutter/material.dart';
7+
import 'package:flutter/services.dart';
48
import 'package:get/get.dart';
9+
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
510
import '../../../DataClass/Chapter.dart';
611
import '../../../DataClass/Media.dart';
712
import '../../../Api/Sources/Eval/dart/model/page.dart';
@@ -29,14 +34,37 @@ class MediaReader extends StatefulWidget {
2934
}
3035

3136
class MediaReaderState extends State<MediaReader> {
32-
var showControls = true.obs;
33-
final focusNode = FocusNode();
37+
late final FocusNode focusNode = FocusNode();
38+
late final ItemScrollController itemScrollController = ItemScrollController();
39+
late final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create();
40+
late final PageController pageController = PageController();
41+
42+
final showControls = true.obs;
43+
final currentPage = 1.obs;
44+
final transformationController = TransformationController();
45+
double currentScale = 1.0;
3446

3547
@override
3648
void initState() {
3749
super.initState();
3850
focusNode.requestFocus();
51+
itemPositionsListener.itemPositions.addListener(_updateCurrentPage);
3952
pageController.addListener(_onPageChanged);
53+
if (Platform.isAndroid || Platform.isIOS) {
54+
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
55+
}
56+
}
57+
58+
@override
59+
void dispose() {
60+
focusNode.dispose();
61+
itemPositionsListener.itemPositions.removeListener(_updateCurrentPage);
62+
pageController.removeListener(_onPageChanged);
63+
if (Platform.isAndroid || Platform.isIOS) {
64+
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
65+
}
66+
67+
super.dispose();
4068
}
4169

4270
@override
@@ -51,67 +79,46 @@ class MediaReaderState extends State<MediaReader> {
5179
focusNode: focusNode,
5280
child: GestureDetector(
5381
onTap: () => showControls.value = !showControls.value,
54-
child: Stack(
55-
alignment: Alignment.center,
56-
children: [
57-
InteractiveViewer(
58-
minScale: 0.5,
59-
maxScale: 4,
60-
child: _buildLTRMode(),
61-
),
62-
_buildOverlay(),
63-
],
82+
onDoubleTap: _toggleZoom,
83+
child: Listener(
84+
onPointerSignal: (event) {
85+
if (event is PointerScrollEvent && HardwareKeyboard.instance.isControlPressed) {
86+
_zoomOnScroll(event.scrollDelta.dy);
87+
}
88+
},
89+
child: Stack(
90+
alignment: Alignment.center,
91+
children: [
92+
InteractiveViewer(
93+
transformationController: transformationController,
94+
minScale: 0.5,
95+
maxScale: 4,
96+
panEnabled: true,
97+
scaleEnabled: Platform.isAndroid || Platform.isIOS,
98+
child: _buildUPDMode(),
99+
),
100+
_buildOverlay(),
101+
],
102+
),
64103
),
65104
),
66105
);
67106
}
68107

69-
var currentPage = 1;
70-
71-
void _onPageChanged() {
72-
final page = (pageController.page?.round() ?? 0) + 1;
73-
if (page != currentPage) {
74-
setState(() => currentPage = page);
75-
}
76-
}
77-
78-
ScrollController scrollController = ScrollController();
79-
80108
Widget _buildUPDMode() {
81109
return ScrollConfig(
82110
context,
83-
child: ListView.builder(
84-
reverse: true,
85-
controller: scrollController,
111+
child: ScrollablePositionedList.builder(
86112
itemCount: widget.pages.length,
113+
itemScrollController: itemScrollController,
114+
itemPositionsListener: itemPositionsListener,
87115
itemBuilder: (context, index) {
88-
final page = widget.pages[index];
89-
return Center(
90-
child: ConstrainedBox(
91-
constraints:
92-
BoxConstraints(maxWidth: MediaQuery.of(context).size.width),
93-
child: CachedNetworkImage(
94-
imageUrl: page.url,
95-
fit: BoxFit.fitWidth,
96-
placeholder: (context, url) => SizedBox(
97-
height: MediaQuery.of(context).size.height / 2,
98-
child: Center(child: CircularProgressIndicator()),
99-
),
100-
errorWidget: (context, url, error) => Center(
101-
child: Text(
102-
'Failed to load image: $error',
103-
style: TextStyle(color: Colors.red),
104-
)),
105-
),
106-
),
107-
);
116+
return _buildPageImage(widget.pages[index]);
108117
},
109118
),
110119
);
111120
}
112121

113-
final PageController pageController = PageController();
114-
115122
Widget _buildLTRMode() {
116123
return ScrollConfig(
117124
context,
@@ -121,30 +128,86 @@ class MediaReaderState extends State<MediaReader> {
121128
reverse: true,
122129
itemCount: widget.pages.length,
123130
itemBuilder: (context, index) {
124-
final page = widget.pages[index];
125-
return Center(
126-
child: ConstrainedBox(
127-
constraints:
128-
BoxConstraints(maxWidth: MediaQuery.of(context).size.width),
129-
child: CachedNetworkImage(
130-
imageUrl: page.url,
131-
fit: BoxFit.fitWidth,
132-
placeholder: (context, url) => SizedBox(
133-
height: MediaQuery.of(context).size.height / 2,
134-
child: Center(child: CircularProgressIndicator()),
135-
),
136-
errorWidget: (context, url, error) => Center(
137-
child: Text('Failed to load image: $error',
138-
style: TextStyle(color: Colors.red)),
131+
return _buildPageImage(widget.pages[index]);
132+
},
133+
),
134+
);
135+
}
136+
137+
Widget _buildPageImage(PageUrl page) {
138+
return Center(
139+
child: ConstrainedBox(
140+
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width),
141+
child: CachedNetworkImage(
142+
imageUrl: page.url,
143+
fit: BoxFit.fitWidth,
144+
errorWidget: (context, url, error) => Center(
145+
child: Text('Failed to load image', style: TextStyle(color: Colors.red)),
146+
),
147+
progressIndicatorBuilder: (context, url, downloadProgress) {
148+
return SizedBox(
149+
height: MediaQuery.of(context).size.height / 2,
150+
width: double.infinity,
151+
child: Center(
152+
child: CircularProgressIndicator(
153+
value: downloadProgress.progress,
139154
),
140155
),
141-
),
142-
);
143-
},
156+
);
157+
},
158+
),
144159
),
145160
);
146161
}
147162

163+
void _onPageChanged() {
164+
final page = (pageController.page?.round() ?? 0) + 1;
165+
if (page != currentPage.value) {
166+
currentPage.value = page;
167+
}
168+
}
169+
170+
void _updateCurrentPage() {
171+
final positions = itemPositionsListener.itemPositions.value;
172+
173+
int mostVisiblePage = currentPage.value;
174+
double maxVisibleFraction = 0;
175+
176+
for (final position in positions) {
177+
final visibleFraction = _calculateVisibleFraction(position);
178+
179+
if (visibleFraction > maxVisibleFraction) {
180+
maxVisibleFraction = visibleFraction;
181+
mostVisiblePage = position.index + 1;
182+
}
183+
}
184+
185+
if (mostVisiblePage != currentPage.value && maxVisibleFraction >= 0.6) {
186+
currentPage.value = mostVisiblePage;
187+
}
188+
}
189+
190+
double _calculateVisibleFraction(ItemPosition position) {
191+
final viewportHeight = MediaQuery.of(context).size.height;
192+
final itemTop = position.itemLeadingEdge * viewportHeight;
193+
final itemBottom = position.itemTrailingEdge * viewportHeight;
194+
final visibleTop = itemTop.clamp(0, viewportHeight);
195+
final visibleBottom = itemBottom.clamp(0, viewportHeight);
196+
197+
return (visibleBottom - visibleTop) / (itemBottom - itemTop);
198+
}
199+
200+
void _toggleZoom() {
201+
currentScale = (currentScale < 2.0) ? 2.0 : 1.0;
202+
transformationController.value = Matrix4.identity()..scale(currentScale);
203+
}
204+
205+
void _zoomOnScroll(double scrollDelta) {
206+
final zoomFactor = (scrollDelta < 0) ? 1.1 : 0.9;
207+
currentScale = (currentScale * zoomFactor).clamp(1, 4.0);
208+
transformationController.value = Matrix4.identity()..scale(currentScale);
209+
}
210+
148211
Widget _buildOverlay() {
149212
return Obx(() {
150213
return Positioned.fill(

lib/Screens/Manga/MangaReader/ReaderController.dart

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -222,15 +222,19 @@ class _ReaderControllerState extends State<ReaderController> {
222222
],
223223
),
224224
),
225-
Center(
226-
child: Text(
227-
"${widget.reader.currentPage}/${pages.length}",
228-
style: const TextStyle(
229-
color: Colors.white,
230-
fontSize: 14,
231-
fontWeight: FontWeight.bold,
232-
),
233-
),
225+
Obx(
226+
() {
227+
return Center(
228+
child: Text(
229+
"${widget.reader.currentPage}/${pages.length}",
230+
style: const TextStyle(
231+
color: Colors.white,
232+
fontSize: 14,
233+
fontWeight: FontWeight.bold,
234+
),
235+
),
236+
);
237+
},
234238
),
235239
],
236240
);

pubspec.lock

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,6 +1430,14 @@ packages:
14301430
url: "https://pub.dev"
14311431
source: hosted
14321432
version: "0.2.0"
1433+
scrollable_positioned_list:
1434+
dependency: "direct main"
1435+
description:
1436+
name: scrollable_positioned_list
1437+
sha256: "1b54d5f1329a1e263269abc9e2543d90806131aa14fe7c6062a8054d57249287"
1438+
url: "https://pub.dev"
1439+
source: hosted
1440+
version: "0.3.8"
14331441
share_plus:
14341442
dependency: "direct main"
14351443
description:

pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ dependencies:
5959
expandable_page_view: ^1.0.17
6060
carousel_slider: ^5.0.0
6161
flutter_staggered_grid_view: ^0.7.0
62+
scrollable_positioned_list: ^0.3.8
6263

6364
# Platform Specific
6465
media_kit: ^1.1.11

0 commit comments

Comments
 (0)