new reader slider
This commit is contained in:
parent
c95771e637
commit
b5868f3fe9
|
@ -44,7 +44,7 @@ var switchAddresses = map[int]string{
|
||||||
}
|
}
|
||||||
|
|
||||||
var switchAddress = 1
|
var switchAddress = 1
|
||||||
var switchAddressPattern, _ = regexp.Compile("^.+pica" + "comic\\.com:\\d+$")
|
var switchAddressPattern, _ = regexp.Compile("^.+picacomic\\.com:\\d+$")
|
||||||
|
|
||||||
func switchAddressContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
func switchAddressContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
if sAddr, ok := switchAddresses[switchAddress]; ok {
|
if sAddr, ok := switchAddresses[switchAddress]; ok {
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
var readerAppbarColor = Color(0xff1e202c);
|
||||||
|
var readerAppbarColor2 = readerAppbarColor.withAlpha(225);
|
|
@ -332,7 +332,7 @@ class _ComicInfoScreenState extends State<ComicInfoScreen> with RouteAware {
|
||||||
comicInfo: comicInfo,
|
comicInfo: comicInfo,
|
||||||
epList: epList,
|
epList: epList,
|
||||||
currentEpOrder: order,
|
currentEpOrder: order,
|
||||||
initPictureRank: rank,
|
initPicturePosition: rank,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:pikapika/basic/Common.dart';
|
||||||
import 'package:pikapika/basic/Entities.dart';
|
import 'package:pikapika/basic/Entities.dart';
|
||||||
import 'package:pikapika/basic/Method.dart';
|
import 'package:pikapika/basic/Method.dart';
|
||||||
import 'package:pikapika/basic/config/AutoFullScreen.dart';
|
import 'package:pikapika/basic/config/AutoFullScreen.dart';
|
||||||
|
@ -9,6 +10,7 @@ import 'package:pikapika/basic/config/FullScreenUI.dart';
|
||||||
import 'package:pikapika/basic/config/Quality.dart';
|
import 'package:pikapika/basic/config/Quality.dart';
|
||||||
import 'package:pikapika/basic/config/ReaderDirection.dart';
|
import 'package:pikapika/basic/config/ReaderDirection.dart';
|
||||||
import 'package:pikapika/basic/config/ReaderType.dart';
|
import 'package:pikapika/basic/config/ReaderType.dart';
|
||||||
|
import 'package:pikapika/basic/const.dart';
|
||||||
import 'package:pikapika/screens/components/ContentBuilder.dart';
|
import 'package:pikapika/screens/components/ContentBuilder.dart';
|
||||||
import 'components/ImageReader.dart';
|
import 'components/ImageReader.dart';
|
||||||
|
|
||||||
|
@ -17,7 +19,7 @@ class ComicReaderScreen extends StatefulWidget {
|
||||||
final ComicInfo comicInfo;
|
final ComicInfo comicInfo;
|
||||||
final List<Ep> epList;
|
final List<Ep> epList;
|
||||||
final currentEpOrder;
|
final currentEpOrder;
|
||||||
final int? initPictureRank;
|
final int? initPicturePosition;
|
||||||
final ReaderType pagerType = currentReaderType();
|
final ReaderType pagerType = currentReaderType();
|
||||||
final ReaderDirection pagerDirection = gReaderDirection;
|
final ReaderDirection pagerDirection = gReaderDirection;
|
||||||
late final bool autoFullScreen;
|
late final bool autoFullScreen;
|
||||||
|
@ -27,7 +29,7 @@ class ComicReaderScreen extends StatefulWidget {
|
||||||
required this.comicInfo,
|
required this.comicInfo,
|
||||||
required this.epList,
|
required this.epList,
|
||||||
required this.currentEpOrder,
|
required this.currentEpOrder,
|
||||||
this.initPictureRank,
|
this.initPicturePosition,
|
||||||
bool? autoFullScreen,
|
bool? autoFullScreen,
|
||||||
}) : super(key: key) {
|
}) : super(key: key) {
|
||||||
this.autoFullScreen = autoFullScreen ?? currentAutoFullScreen();
|
this.autoFullScreen = autoFullScreen ?? currentAutoFullScreen();
|
||||||
|
@ -45,8 +47,8 @@ class _ComicReaderScreenState extends State<ComicReaderScreen> {
|
||||||
bool _replacement = false;
|
bool _replacement = false;
|
||||||
|
|
||||||
Future<List<RemoteImageInfo>> _load() async {
|
Future<List<RemoteImageInfo>> _load() async {
|
||||||
if (widget.initPictureRank == null) {
|
if (widget.initPicturePosition == null) {
|
||||||
await method.storeViewEp(widget.comicInfo.id, _ep.order, _ep.title, 1);
|
await method.storeViewEp(widget.comicInfo.id, _ep.order, _ep.title, 0);
|
||||||
}
|
}
|
||||||
List<RemoteImageInfo> list = [];
|
List<RemoteImageInfo> list = [];
|
||||||
var _needLoadPage = 0;
|
var _needLoadPage = 0;
|
||||||
|
@ -70,11 +72,13 @@ class _ComicReaderScreenState extends State<ComicReaderScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _onPositionChange(int position) async {
|
Future _onPositionChange(int position) async {
|
||||||
_lastChangeRank = position + 1;
|
_lastChangeRank = position;
|
||||||
return method.storeViewEp(
|
return method.storeViewEp(
|
||||||
widget.comicInfo.id, _ep.order, _ep.title, position + 1);
|
widget.comicInfo.id, _ep.order, _ep.title, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FutureOr<dynamic> Function() _previousAction = () => null;
|
||||||
|
|
||||||
String _nextText = "";
|
String _nextText = "";
|
||||||
FutureOr<dynamic> Function() _nextAction = () => null;
|
FutureOr<dynamic> Function() _nextAction = () => null;
|
||||||
|
|
||||||
|
@ -85,6 +89,23 @@ class _ComicReaderScreenState extends State<ComicReaderScreen> {
|
||||||
widget.epList.forEach((element) {
|
widget.epList.forEach((element) {
|
||||||
orderMap[element.order] = element;
|
orderMap[element.order] = element;
|
||||||
});
|
});
|
||||||
|
if (orderMap.containsKey(widget.currentEpOrder - 1)) {
|
||||||
|
_previousAction = () {
|
||||||
|
_replacement = true;
|
||||||
|
Navigator.of(context).pushReplacement(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => ComicReaderScreen(
|
||||||
|
comicInfo: widget.comicInfo,
|
||||||
|
epList: widget.epList,
|
||||||
|
currentEpOrder: widget.currentEpOrder - 1,
|
||||||
|
autoFullScreen: _fullScreen,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
_previousAction = () => defaultToast(context, "已经到头了");
|
||||||
|
}
|
||||||
if (orderMap.containsKey(widget.currentEpOrder + 1)) {
|
if (orderMap.containsKey(widget.currentEpOrder + 1)) {
|
||||||
_nextText = "下一章";
|
_nextText = "下一章";
|
||||||
_nextAction = () {
|
_nextAction = () {
|
||||||
|
@ -135,6 +156,7 @@ class _ComicReaderScreenState extends State<ComicReaderScreen> {
|
||||||
appBar: _fullScreen
|
appBar: _fullScreen
|
||||||
? null
|
? null
|
||||||
: AppBar(
|
: AppBar(
|
||||||
|
backgroundColor: readerAppbarColor,
|
||||||
title: Text("${_ep.title} - ${widget.comicInfo.title}"),
|
title: Text("${_ep.title} - ${widget.comicInfo.title}"),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
|
@ -164,8 +186,8 @@ class _ComicReaderScreenState extends State<ComicReaderScreen> {
|
||||||
_future = _load();
|
_future = _load();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
successBuilder:
|
successBuilder: (BuildContext context,
|
||||||
(BuildContext context, AsyncSnapshot<List<RemoteImageInfo>> snapshot) {
|
AsyncSnapshot<List<RemoteImageInfo>> snapshot) {
|
||||||
return ImageReader(
|
return ImageReader(
|
||||||
ImageReaderStruct(
|
ImageReaderStruct(
|
||||||
images: snapshot.data!
|
images: snapshot.data!
|
||||||
|
@ -182,11 +204,10 @@ class _ComicReaderScreenState extends State<ComicReaderScreen> {
|
||||||
fullScreen: _fullScreen,
|
fullScreen: _fullScreen,
|
||||||
onFullScreenChange: _onFullScreenChange,
|
onFullScreenChange: _onFullScreenChange,
|
||||||
onNextText: _nextText,
|
onNextText: _nextText,
|
||||||
|
onPreviousAction: _previousAction,
|
||||||
onNextAction: _nextAction,
|
onNextAction: _nextAction,
|
||||||
onPositionChange: _onPositionChange,
|
onPositionChange: _onPositionChange,
|
||||||
initPosition: widget.initPictureRank == null
|
initPosition: widget.initPicturePosition,
|
||||||
? null
|
|
||||||
: widget.initPictureRank! - 1,
|
|
||||||
pagerType: widget.pagerType,
|
pagerType: widget.pagerType,
|
||||||
pagerDirection: widget.pagerDirection,
|
pagerDirection: widget.pagerDirection,
|
||||||
),
|
),
|
||||||
|
@ -212,7 +233,7 @@ class _ComicReaderScreenState extends State<ComicReaderScreen> {
|
||||||
comicInfo: widget.comicInfo,
|
comicInfo: widget.comicInfo,
|
||||||
epList: widget.epList,
|
epList: widget.epList,
|
||||||
currentEpOrder: widget.currentEpOrder,
|
currentEpOrder: widget.currentEpOrder,
|
||||||
initPictureRank: _lastChangeRank ?? widget.initPictureRank,
|
initPicturePosition: _lastChangeRank ?? widget.initPicturePosition,
|
||||||
// maybe null
|
// maybe null
|
||||||
autoFullScreen: _fullScreen,
|
autoFullScreen: _fullScreen,
|
||||||
),
|
),
|
||||||
|
|
|
@ -176,7 +176,7 @@ class _DownloadInfoScreenState extends State<DownloadInfoScreen>
|
||||||
comicInfo: _task,
|
comicInfo: _task,
|
||||||
epList: _epList,
|
epList: _epList,
|
||||||
currentEpOrder: epOrder,
|
currentEpOrder: epOrder,
|
||||||
initPictureRank: rank,
|
initPicturePosition: rank,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:pikapika/basic/Common.dart';
|
||||||
import 'package:pikapika/basic/Entities.dart';
|
import 'package:pikapika/basic/Entities.dart';
|
||||||
import 'package:pikapika/basic/config/AutoFullScreen.dart';
|
import 'package:pikapika/basic/config/AutoFullScreen.dart';
|
||||||
import 'package:pikapika/basic/config/FullScreenUI.dart';
|
import 'package:pikapika/basic/config/FullScreenUI.dart';
|
||||||
|
@ -16,7 +17,7 @@ class DownloadReaderScreen extends StatefulWidget {
|
||||||
final DownloadComic comicInfo;
|
final DownloadComic comicInfo;
|
||||||
final List<DownloadEp> epList;
|
final List<DownloadEp> epList;
|
||||||
final int currentEpOrder;
|
final int currentEpOrder;
|
||||||
final int? initPictureRank;
|
final int? initPicturePosition;
|
||||||
final ReaderType pagerType = currentReaderType();
|
final ReaderType pagerType = currentReaderType();
|
||||||
final ReaderDirection pagerDirection = gReaderDirection;
|
final ReaderDirection pagerDirection = gReaderDirection;
|
||||||
late final bool autoFullScreen;
|
late final bool autoFullScreen;
|
||||||
|
@ -26,7 +27,7 @@ class DownloadReaderScreen extends StatefulWidget {
|
||||||
required this.comicInfo,
|
required this.comicInfo,
|
||||||
required this.epList,
|
required this.epList,
|
||||||
required this.currentEpOrder,
|
required this.currentEpOrder,
|
||||||
this.initPictureRank,
|
this.initPicturePosition,
|
||||||
bool? autoFullScreen,
|
bool? autoFullScreen,
|
||||||
}) : super(key: key) {
|
}) : super(key: key) {
|
||||||
this.autoFullScreen = autoFullScreen ?? currentAutoFullScreen();
|
this.autoFullScreen = autoFullScreen ?? currentAutoFullScreen();
|
||||||
|
@ -45,8 +46,8 @@ class _DownloadReaderScreenState extends State<DownloadReaderScreen> {
|
||||||
bool _replacement = false;
|
bool _replacement = false;
|
||||||
|
|
||||||
Future _load() async {
|
Future _load() async {
|
||||||
if (widget.initPictureRank == null) {
|
if (widget.initPicturePosition == null) {
|
||||||
await method.storeViewEp(widget.comicInfo.id, _ep.epOrder, _ep.title, 1);
|
await method.storeViewEp(widget.comicInfo.id, _ep.epOrder, _ep.title, 0);
|
||||||
}
|
}
|
||||||
pictures.clear();
|
pictures.clear();
|
||||||
for (var ep in widget.epList) {
|
for (var ep in widget.epList) {
|
||||||
|
@ -63,11 +64,13 @@ class _DownloadReaderScreenState extends State<DownloadReaderScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _onPositionChange(int position) async {
|
Future _onPositionChange(int position) async {
|
||||||
_lastChangeRank = position + 1;
|
_lastChangeRank = position;
|
||||||
return method.storeViewEp(
|
return method.storeViewEp(
|
||||||
widget.comicInfo.id, _ep.epOrder, _ep.title, position + 1);
|
widget.comicInfo.id, _ep.epOrder, _ep.title, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FutureOr<dynamic> Function() _previousAction = () => null;
|
||||||
|
|
||||||
String _nextText = "";
|
String _nextText = "";
|
||||||
FutureOr<dynamic> Function() _nextAction = () => null;
|
FutureOr<dynamic> Function() _nextAction = () => null;
|
||||||
|
|
||||||
|
@ -78,6 +81,23 @@ class _DownloadReaderScreenState extends State<DownloadReaderScreen> {
|
||||||
widget.epList.forEach((element) {
|
widget.epList.forEach((element) {
|
||||||
orderMap[element.epOrder] = element;
|
orderMap[element.epOrder] = element;
|
||||||
});
|
});
|
||||||
|
if (orderMap.containsKey(widget.currentEpOrder - 1)) {
|
||||||
|
_previousAction = () {
|
||||||
|
_replacement = true;
|
||||||
|
Navigator.of(context).pushReplacement(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => DownloadReaderScreen(
|
||||||
|
comicInfo: widget.comicInfo,
|
||||||
|
epList: widget.epList,
|
||||||
|
currentEpOrder: widget.currentEpOrder - 1,
|
||||||
|
autoFullScreen: _fullScreen,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
_previousAction = () => defaultToast(context, "已经到头了");
|
||||||
|
}
|
||||||
if (orderMap.containsKey(widget.currentEpOrder + 1)) {
|
if (orderMap.containsKey(widget.currentEpOrder + 1)) {
|
||||||
_nextText = "下一章";
|
_nextText = "下一章";
|
||||||
_nextAction = () {
|
_nextAction = () {
|
||||||
|
@ -168,11 +188,10 @@ class _DownloadReaderScreenState extends State<DownloadReaderScreen> {
|
||||||
fullScreen: _fullScreen,
|
fullScreen: _fullScreen,
|
||||||
onFullScreenChange: _onFullScreenChange,
|
onFullScreenChange: _onFullScreenChange,
|
||||||
onNextText: _nextText,
|
onNextText: _nextText,
|
||||||
|
onPreviousAction: _previousAction,
|
||||||
onNextAction: _nextAction,
|
onNextAction: _nextAction,
|
||||||
onPositionChange: _onPositionChange,
|
onPositionChange: _onPositionChange,
|
||||||
initPosition: widget.initPictureRank == null
|
initPosition: widget.initPicturePosition,
|
||||||
? null
|
|
||||||
: widget.initPictureRank! - 1,
|
|
||||||
pagerType: widget.pagerType,
|
pagerType: widget.pagerType,
|
||||||
pagerDirection: widget.pagerDirection,
|
pagerDirection: widget.pagerDirection,
|
||||||
),
|
),
|
||||||
|
@ -199,7 +218,7 @@ class _DownloadReaderScreenState extends State<DownloadReaderScreen> {
|
||||||
comicInfo: widget.comicInfo,
|
comicInfo: widget.comicInfo,
|
||||||
epList: widget.epList,
|
epList: widget.epList,
|
||||||
currentEpOrder: widget.currentEpOrder,
|
currentEpOrder: widget.currentEpOrder,
|
||||||
initPictureRank: _lastChangeRank ?? widget.initPictureRank,
|
initPicturePosition: _lastChangeRank ?? widget.initPicturePosition,
|
||||||
// maybe null
|
// maybe null
|
||||||
autoFullScreen: _fullScreen,
|
autoFullScreen: _fullScreen,
|
||||||
),
|
),
|
||||||
|
|
|
@ -37,7 +37,7 @@ class _ContinueReadButtonState extends State<ContinueReadButton> {
|
||||||
snapshot.data?.lastViewPictureRank,
|
snapshot.data?.lastViewPictureRank,
|
||||||
);
|
);
|
||||||
text =
|
text =
|
||||||
'继续阅读 ${snapshot.data?.lastViewEpTitle} P. ${snapshot.data?.lastViewPictureRank}';
|
'继续阅读 ${snapshot.data?.lastViewEpTitle} P. ${(snapshot.data?.lastViewPictureRank ?? 0) + 1}';
|
||||||
} else {
|
} else {
|
||||||
onPressed = () => widget.onChoose(null, null);
|
onPressed = () => widget.onChoose(null, null);
|
||||||
text = '开始阅读';
|
text = '开始阅读';
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:another_xlider/another_xlider.dart';
|
import 'package:another_xlider/another_xlider.dart';
|
||||||
import 'package:event/event.dart';
|
import 'package:event/event.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:photo_view/photo_view_gallery.dart';
|
import 'package:photo_view/photo_view_gallery.dart';
|
||||||
|
@ -11,11 +12,11 @@ import 'package:pikapika/basic/Cross.dart';
|
||||||
import 'package:pikapika/basic/Entities.dart';
|
import 'package:pikapika/basic/Entities.dart';
|
||||||
import 'package:pikapika/basic/Method.dart';
|
import 'package:pikapika/basic/Method.dart';
|
||||||
import 'package:pikapika/basic/config/FullScreenAction.dart';
|
import 'package:pikapika/basic/config/FullScreenAction.dart';
|
||||||
import 'package:pikapika/basic/config/GalleryPreloadCount.dart';
|
|
||||||
import 'package:pikapika/basic/config/KeyboardController.dart';
|
import 'package:pikapika/basic/config/KeyboardController.dart';
|
||||||
import 'package:pikapika/basic/config/NoAnimation.dart';
|
import 'package:pikapika/basic/config/NoAnimation.dart';
|
||||||
import 'package:pikapika/basic/config/ReaderDirection.dart';
|
import 'package:pikapika/basic/config/ReaderDirection.dart';
|
||||||
import 'package:pikapika/basic/config/ReaderType.dart';
|
import 'package:pikapika/basic/config/ReaderType.dart';
|
||||||
|
import 'package:pikapika/basic/const.dart';
|
||||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
import '../FilePhotoViewScreen.dart';
|
import '../FilePhotoViewScreen.dart';
|
||||||
import 'gesture_zoom_box.dart';
|
import 'gesture_zoom_box.dart';
|
||||||
|
@ -69,7 +70,7 @@ var _volumeListenCount = 0;
|
||||||
EventChannel volumeButtonChannel = EventChannel("volume_button");
|
EventChannel volumeButtonChannel = EventChannel("volume_button");
|
||||||
StreamSubscription? volumeS;
|
StreamSubscription? volumeS;
|
||||||
|
|
||||||
addVolumeListen() {
|
void addVolumeListen() {
|
||||||
_volumeListenCount++;
|
_volumeListenCount++;
|
||||||
if (_volumeListenCount == 1) {
|
if (_volumeListenCount == 1) {
|
||||||
volumeS =
|
volumeS =
|
||||||
|
@ -77,7 +78,7 @@ addVolumeListen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delVolumeListen() {
|
void delVolumeListen() {
|
||||||
_volumeListenCount--;
|
_volumeListenCount--;
|
||||||
if (_volumeListenCount == 0) {
|
if (_volumeListenCount == 0) {
|
||||||
volumeS?.cancel();
|
volumeS?.cancel();
|
||||||
|
@ -106,6 +107,7 @@ class ImageReaderStruct {
|
||||||
final bool fullScreen;
|
final bool fullScreen;
|
||||||
final FutureOr<dynamic> Function(bool fullScreen) onFullScreenChange;
|
final FutureOr<dynamic> Function(bool fullScreen) onFullScreenChange;
|
||||||
final String onNextText;
|
final String onNextText;
|
||||||
|
final FutureOr<dynamic> Function() onPreviousAction;
|
||||||
final FutureOr<dynamic> Function() onNextAction;
|
final FutureOr<dynamic> Function() onNextAction;
|
||||||
final FutureOr<dynamic> Function(int) onPositionChange;
|
final FutureOr<dynamic> Function(int) onPositionChange;
|
||||||
final int? initPosition;
|
final int? initPosition;
|
||||||
|
@ -117,6 +119,7 @@ class ImageReaderStruct {
|
||||||
required this.fullScreen,
|
required this.fullScreen,
|
||||||
required this.onFullScreenChange,
|
required this.onFullScreenChange,
|
||||||
required this.onNextText,
|
required this.onNextText,
|
||||||
|
required this.onPreviousAction,
|
||||||
required this.onNextAction,
|
required this.onNextAction,
|
||||||
required this.onPositionChange,
|
required this.onPositionChange,
|
||||||
this.initPosition,
|
this.initPosition,
|
||||||
|
@ -127,51 +130,259 @@ class ImageReaderStruct {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
class ImageReader extends StatelessWidget {
|
class ImageReader extends StatefulWidget {
|
||||||
final ImageReaderStruct struct;
|
final ImageReaderStruct struct;
|
||||||
|
|
||||||
const ImageReader(this.struct);
|
const ImageReader(this.struct);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
State<StatefulWidget> createState() {
|
||||||
late Widget reader;
|
|
||||||
switch (struct.pagerType) {
|
switch (struct.pagerType) {
|
||||||
case ReaderType.WEB_TOON:
|
case ReaderType.WEB_TOON:
|
||||||
reader = _WebToonReader(struct);
|
return _WebToonReaderState();
|
||||||
break;
|
|
||||||
case ReaderType.WEB_TOON_ZOOM:
|
case ReaderType.WEB_TOON_ZOOM:
|
||||||
reader = _WebToonZoomReader(struct);
|
return _WebToonZoomReaderState();
|
||||||
break;
|
|
||||||
case ReaderType.GALLERY:
|
case ReaderType.GALLERY:
|
||||||
reader = _GalleryReader(struct);
|
return _GalleryReaderState();
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
reader = Container();
|
throw Exception("ERROR READER TYPE");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
switch (currentFullScreenAction()) {
|
}
|
||||||
case FullScreenAction.CONTROLLER:
|
}
|
||||||
reader = Stack(
|
|
||||||
|
abstract class _ImageReaderState extends State<ImageReader> {
|
||||||
|
// 阅读器
|
||||||
|
Widget _buildViewer();
|
||||||
|
|
||||||
|
// 键盘, 音量键 等事件
|
||||||
|
void _needJumpTo(int index, bool animation);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_initCurrent();
|
||||||
|
_readerControllerEvent.subscribe(_onPageControl);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_readerControllerEvent.unsubscribe(_onPageControl);
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
reader,
|
_buildViewer(),
|
||||||
_buildFullScreenController(
|
_buildControllerAndBar(),
|
||||||
struct.fullScreen,
|
|
||||||
struct.onFullScreenChange,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onPageControl(_ReaderControllerEventArgs? args) {
|
||||||
|
if (args != null) {
|
||||||
|
var event = args.key;
|
||||||
|
switch ("$event") {
|
||||||
|
case "UP":
|
||||||
|
if (_current > 0) {
|
||||||
|
_needJumpTo(_current - 1, true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case FullScreenAction.TOUCH_ONCE:
|
case "DOWN":
|
||||||
reader = GestureDetector(
|
if (_current < widget.struct.images.length - 1) {
|
||||||
onTap: () => struct.onFullScreenChange(!struct.fullScreen),
|
_needJumpTo(_current + 1, true);
|
||||||
child: reader,
|
}
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case FullScreenAction.THREE_AREA:
|
}
|
||||||
reader = Stack(
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
late int _startIndex;
|
||||||
|
late int _current;
|
||||||
|
late int _slider;
|
||||||
|
|
||||||
|
void _initCurrent() {
|
||||||
|
if (widget.struct.initPosition != null &&
|
||||||
|
widget.struct.images.length > widget.struct.initPosition!) {
|
||||||
|
_startIndex = widget.struct.initPosition!;
|
||||||
|
} else {
|
||||||
|
_startIndex = 0;
|
||||||
|
}
|
||||||
|
_current = _startIndex;
|
||||||
|
_slider = _startIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onCurrentChange(int index) {
|
||||||
|
if (index != _current) {
|
||||||
|
setState(() {
|
||||||
|
_current = index;
|
||||||
|
_slider = index;
|
||||||
|
widget.struct.onPositionChange(index);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildControllerAndBar() {
|
||||||
|
if (widget.struct.fullScreen) {
|
||||||
|
return _buildController();
|
||||||
|
}
|
||||||
|
return SafeArea(
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
reader,
|
Expanded(
|
||||||
LayoutBuilder(
|
child: _buildController(hiddenFullScreen: true),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
color: readerAppbarColor2,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(width: 15),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.fullscreen),
|
||||||
|
color: Colors.white,
|
||||||
|
onPressed: () {
|
||||||
|
widget.struct.onFullScreenChange(!widget.struct.fullScreen);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Container(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(height: 3),
|
||||||
|
Container(
|
||||||
|
height: 25,
|
||||||
|
child: FlutterSlider(
|
||||||
|
axis: Axis.horizontal,
|
||||||
|
values: [_slider.toDouble()],
|
||||||
|
min: 0,
|
||||||
|
max: widget.struct.images.length.toDouble(),
|
||||||
|
onDragging: (handlerIndex, lowerValue, upperValue) {
|
||||||
|
_slider = (lowerValue.toInt());
|
||||||
|
},
|
||||||
|
onDragCompleted:
|
||||||
|
(handlerIndex, lowerValue, upperValue) {
|
||||||
|
_slider = (lowerValue.toInt());
|
||||||
|
if (_slider != _current) {
|
||||||
|
_needJumpTo(_slider, false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trackBar: FlutterSliderTrackBar(
|
||||||
|
inactiveTrackBar: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
activeTrackBar: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
step: FlutterSliderStep(
|
||||||
|
step: 1,
|
||||||
|
isPercentRange: false,
|
||||||
|
),
|
||||||
|
tooltip: FlutterSliderTooltip(custom: (value) {
|
||||||
|
double a = value + 1;
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color: Colors.black.withAlpha(0xCC),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius:
|
||||||
|
BorderRadiusDirectional.circular(3)),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'${a.toInt()}',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(height: 3),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(width: 10),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.skip_next_outlined),
|
||||||
|
color: Colors.white,
|
||||||
|
onPressed: () {
|
||||||
|
widget.struct.onNextAction();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Container(width: 15),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildController({bool hiddenFullScreen = false}) {
|
||||||
|
switch (currentFullScreenAction()) {
|
||||||
|
case FullScreenAction.CONTROLLER:
|
||||||
|
if (hiddenFullScreen) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
return _buildFullScreenController();
|
||||||
|
case FullScreenAction.TOUCH_ONCE:
|
||||||
|
return _buildTouchOnceController();
|
||||||
|
case FullScreenAction.THREE_AREA:
|
||||||
|
return _buildThreeAreaController();
|
||||||
|
default:
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFullScreenController() {
|
||||||
|
return Align(
|
||||||
|
alignment: Alignment.bottomLeft,
|
||||||
|
child: Material(
|
||||||
|
color: Color(0x0),
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.only(left: 10, right: 10, top: 4, bottom: 4),
|
||||||
|
margin: EdgeInsets.only(bottom: 10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topRight: Radius.circular(10),
|
||||||
|
bottomRight: Radius.circular(10),
|
||||||
|
),
|
||||||
|
color: Color(0x88000000),
|
||||||
|
),
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
widget.struct.onFullScreenChange(!widget.struct.fullScreen);
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
widget.struct.fullScreen
|
||||||
|
? Icons.fullscreen_exit
|
||||||
|
: Icons.fullscreen_outlined,
|
||||||
|
size: 30,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTouchOnceController() {
|
||||||
|
return GestureDetector(
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
onTap: () {
|
||||||
|
widget.struct.onFullScreenChange(!widget.struct.fullScreen);
|
||||||
|
},
|
||||||
|
child: Container(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildThreeAreaController() {
|
||||||
|
return LayoutBuilder(
|
||||||
builder: (BuildContext context, BoxConstraints constraints) {
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
var up = Expanded(
|
var up = Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
|
@ -190,19 +401,19 @@ class ImageReader extends StatelessWidget {
|
||||||
_readerControllerEvent
|
_readerControllerEvent
|
||||||
.broadcast(_ReaderControllerEventArgs("DOWN"));
|
.broadcast(_ReaderControllerEventArgs("DOWN"));
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
var fullScreen = Expanded(
|
var fullScreen = Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
behavior: HitTestBehavior.translucent,
|
behavior: HitTestBehavior.translucent,
|
||||||
onTap: () => struct.onFullScreenChange(!struct.fullScreen),
|
onTap: () =>
|
||||||
|
widget.struct.onFullScreenChange(!widget.struct.fullScreen),
|
||||||
child: Container(),
|
child: Container(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
late Widget child;
|
late Widget child;
|
||||||
switch (struct.pagerDirection) {
|
switch (widget.struct.pagerDirection) {
|
||||||
case ReaderDirection.TOP_TO_BOTTOM:
|
case ReaderDirection.TOP_TO_BOTTOM:
|
||||||
child = Column(children: [
|
child = Column(children: [
|
||||||
up,
|
up,
|
||||||
|
@ -231,81 +442,17 @@ class ImageReader extends StatelessWidget {
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
return reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildFullScreenController(
|
|
||||||
bool fullScreen,
|
|
||||||
FutureOr<dynamic> Function(bool fullScreen) onFullScreenChange,
|
|
||||||
) {
|
|
||||||
return Align(
|
|
||||||
alignment: Alignment.bottomLeft,
|
|
||||||
child: Material(
|
|
||||||
color: Color(0x0),
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.only(left: 10, right: 10, top: 4, bottom: 4),
|
|
||||||
margin: EdgeInsets.only(bottom: 10),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topRight: Radius.circular(10),
|
|
||||||
bottomRight: Radius.circular(10),
|
|
||||||
),
|
|
||||||
color: Color(0x88000000),
|
|
||||||
),
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
onFullScreenChange(!fullScreen);
|
|
||||||
},
|
|
||||||
child: Icon(
|
|
||||||
fullScreen ? Icons.fullscreen_exit : Icons.fullscreen_outlined,
|
|
||||||
size: 30,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class _WebToonReader extends StatefulWidget {
|
class _WebToonReaderState extends _ImageReaderState {
|
||||||
final ImageReaderStruct struct;
|
var _controllerTime = DateTime.now().millisecondsSinceEpoch + 400;
|
||||||
|
|
||||||
const _WebToonReader(this.struct);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<StatefulWidget> createState() => _WebToonReaderState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WebToonReaderState extends State<_WebToonReader> {
|
|
||||||
late final List<Size?> _trueSizes = [];
|
late final List<Size?> _trueSizes = [];
|
||||||
late final ItemScrollController _itemScrollController;
|
late final ItemScrollController _itemScrollController;
|
||||||
late final ItemPositionsListener _itemPositionsListener;
|
late final ItemPositionsListener _itemPositionsListener;
|
||||||
late final int _initialPosition;
|
|
||||||
|
|
||||||
var _current = 1;
|
|
||||||
var _slider = 1;
|
|
||||||
|
|
||||||
void _onCurrentChange() {
|
|
||||||
var to = _itemPositionsListener.itemPositions.value.first.index + 1;
|
|
||||||
if (_current != to) {
|
|
||||||
setState(() {
|
|
||||||
_current = to;
|
|
||||||
_slider = to;
|
|
||||||
if (to - 1 < widget.struct.images.length) {
|
|
||||||
widget.struct.onPositionChange(to - 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -318,81 +465,49 @@ class _WebToonReaderState extends State<_WebToonReader> {
|
||||||
});
|
});
|
||||||
_itemScrollController = ItemScrollController();
|
_itemScrollController = ItemScrollController();
|
||||||
_itemPositionsListener = ItemPositionsListener.create();
|
_itemPositionsListener = ItemPositionsListener.create();
|
||||||
_itemPositionsListener.itemPositions.addListener(_onCurrentChange);
|
_itemPositionsListener.itemPositions.addListener(_onListCurrentChange);
|
||||||
if (widget.struct.initPosition != null &&
|
|
||||||
widget.struct.images.length > widget.struct.initPosition!) {
|
|
||||||
_initialPosition = widget.struct.initPosition!;
|
|
||||||
} else {
|
|
||||||
_initialPosition = 0;
|
|
||||||
}
|
|
||||||
_readerControllerEvent.subscribe(_onPageControllerEvent);
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_itemPositionsListener.itemPositions.removeListener(_onCurrentChange);
|
_itemPositionsListener.itemPositions.removeListener(_onListCurrentChange);
|
||||||
_readerControllerEvent.unsubscribe(_onPageControllerEvent);
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onPageControllerEvent(_ReaderControllerEventArgs? args) {
|
void _onListCurrentChange() {
|
||||||
if (args != null) {
|
var to = _itemPositionsListener.itemPositions.value.first.index;
|
||||||
var event = args.key;
|
// 包含一个下一章, 假设5张图片 0,1,2,3,4 length=5, 下一章=5
|
||||||
print("EVENT : $event");
|
if (to >= 0 && to < widget.struct.images.length) {
|
||||||
switch ("$event") {
|
super._onCurrentChange(to);
|
||||||
case "UP":
|
|
||||||
if (_current > 1) {
|
|
||||||
if (noAnimation()) {
|
|
||||||
_itemScrollController.jumpTo(
|
|
||||||
index: _current - 2, // 减1 当前position 再减少1 前一个
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if (DateTime.now().millisecondsSinceEpoch < _controllerTime) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_controllerTime = DateTime.now().millisecondsSinceEpoch + 400;
|
|
||||||
_itemScrollController.scrollTo(
|
|
||||||
index: _current - 2, // 减1 当前position 再减少1 前一个
|
|
||||||
duration: Duration(milliseconds: 400),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case "DOWN":
|
|
||||||
if (_current < widget.struct.images.length) {
|
|
||||||
if (noAnimation()) {
|
|
||||||
_itemScrollController.jumpTo(index: _current);
|
|
||||||
} else {
|
|
||||||
if (DateTime.now().millisecondsSinceEpoch < _controllerTime) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_controllerTime = DateTime.now().millisecondsSinceEpoch + 400;
|
|
||||||
_itemScrollController.scrollTo(
|
|
||||||
index: _current,
|
|
||||||
duration: Duration(milliseconds: 400),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _controllerTime = DateTime.now().millisecondsSinceEpoch + 400;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
void _needJumpTo(int index, bool animation) {
|
||||||
|
if (noAnimation() || animation == false) {
|
||||||
|
_itemScrollController.jumpTo(
|
||||||
|
index: index,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (DateTime.now().millisecondsSinceEpoch < _controllerTime) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_controllerTime = DateTime.now().millisecondsSinceEpoch + 400;
|
||||||
|
_itemScrollController.scrollTo(
|
||||||
|
index: index, // 减1 当前position 再减少1 前一个
|
||||||
|
duration: Duration(milliseconds: 400),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget _buildViewer() {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
child: Stack(
|
child: _buildList(),
|
||||||
children: [
|
|
||||||
_buildList(),
|
|
||||||
..._buildControllers(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,20 +574,22 @@ class _WebToonReaderState extends State<_WebToonReader> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ScrollablePositionedList.builder(
|
return ScrollablePositionedList.builder(
|
||||||
initialScrollIndex: _initialPosition,
|
initialScrollIndex: super._startIndex,
|
||||||
scrollDirection:
|
scrollDirection:
|
||||||
widget.struct.pagerDirection == ReaderDirection.TOP_TO_BOTTOM
|
widget.struct.pagerDirection == ReaderDirection.TOP_TO_BOTTOM
|
||||||
? Axis.vertical
|
? Axis.vertical
|
||||||
: Axis.horizontal,
|
: Axis.horizontal,
|
||||||
reverse:
|
reverse:
|
||||||
widget.struct.pagerDirection == ReaderDirection.RIGHT_TO_LEFT,
|
widget.struct.pagerDirection == ReaderDirection.RIGHT_TO_LEFT,
|
||||||
padding: widget.struct.fullScreen &&
|
padding: EdgeInsets.only(
|
||||||
|
top: widget.struct.fullScreen ? (scaffold.appBarMaxHeight ?? 0) : 0,
|
||||||
|
bottom:
|
||||||
widget.struct.pagerDirection == ReaderDirection.TOP_TO_BOTTOM
|
widget.struct.pagerDirection == ReaderDirection.TOP_TO_BOTTOM
|
||||||
? EdgeInsets.only(
|
? 130
|
||||||
top: scaffold.appBarMaxHeight ?? 0,
|
: (widget.struct.fullScreen
|
||||||
bottom: scaffold.appBarMaxHeight ?? 0,
|
? (scaffold.appBarMaxHeight ?? 0)
|
||||||
)
|
: 0),
|
||||||
: null,
|
),
|
||||||
itemScrollController: _itemScrollController,
|
itemScrollController: _itemScrollController,
|
||||||
itemPositionsListener: _itemPositionsListener,
|
itemPositionsListener: _itemPositionsListener,
|
||||||
itemCount: widget.struct.images.length + 1,
|
itemCount: widget.struct.images.length + 1,
|
||||||
|
@ -487,27 +604,6 @@ class _WebToonReaderState extends State<_WebToonReader> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildControllers() {
|
|
||||||
if (widget.struct.fullScreen) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
_buildImageCount(context, "$_current / ${widget.struct.images.length}"),
|
|
||||||
_buildScrollController(
|
|
||||||
context,
|
|
||||||
_current,
|
|
||||||
_slider,
|
|
||||||
widget.struct.images.length,
|
|
||||||
(value) => _slider = value,
|
|
||||||
() {
|
|
||||||
if (_slider != _current && _slider > 0) {
|
|
||||||
_itemScrollController.jumpTo(index: _slider - 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildNextEp() {
|
Widget _buildNextEp() {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(20),
|
padding: EdgeInsets.all(20),
|
||||||
|
@ -649,15 +745,6 @@ class _WebToonReaderImageState extends State<_WebToonReaderImage> {
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class _WebToonZoomReader extends _WebToonReader {
|
|
||||||
const _WebToonZoomReader(
|
|
||||||
ImageReaderStruct struct,
|
|
||||||
) : super(struct);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<StatefulWidget> createState() => _WebToonZoomReaderState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WebToonZoomReaderState extends _WebToonReaderState {
|
class _WebToonZoomReaderState extends _WebToonReaderState {
|
||||||
@override
|
@override
|
||||||
Widget _buildList() {
|
Widget _buildList() {
|
||||||
|
@ -667,81 +754,41 @@ class _WebToonZoomReaderState extends _WebToonReaderState {
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class _GalleryReader extends StatefulWidget {
|
class _GalleryReaderState extends _ImageReaderState {
|
||||||
final ImageReaderStruct struct;
|
late PageController _pageController;
|
||||||
|
|
||||||
_GalleryReader(this.struct);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<StatefulWidget> createState() => _GalleryReaderState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _GalleryReaderState extends State<_GalleryReader> {
|
|
||||||
late int _current = (widget.struct.initPosition ?? 0) + 1;
|
|
||||||
late int _slider = (widget.struct.initPosition ?? 0) + 1;
|
|
||||||
late PageController _pageController =
|
|
||||||
PageController(initialPage: widget.struct.initPosition ?? 0);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_readerControllerEvent.subscribe(_onPageControllerEvent);
|
_pageController = PageController(initialPage: super._startIndex);
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_pageController.dispose();
|
_pageController.dispose();
|
||||||
_readerControllerEvent.unsubscribe(_onPageControllerEvent);
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onPageControllerEvent(_ReaderControllerEventArgs? args) {
|
@override
|
||||||
if (args != null) {
|
void _needJumpTo(int index, bool animation) {
|
||||||
var event = args.key;
|
if (noAnimation() || animation == false) {
|
||||||
print("EVENT : $event");
|
_pageController.jumpToPage(
|
||||||
switch ("$event") {
|
index,
|
||||||
case "UP":
|
|
||||||
if (_current > 1) {
|
|
||||||
if (noAnimation()) {
|
|
||||||
_pageController.previousPage(
|
|
||||||
duration: Duration(milliseconds: 1),
|
|
||||||
curve: Curves.ease,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
_pageController.previousPage(
|
_pageController.animateToPage(
|
||||||
|
index,
|
||||||
duration: Duration(milliseconds: 400),
|
duration: Duration(milliseconds: 400),
|
||||||
curve: Curves.ease,
|
curve: Curves.ease,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case "DOWN":
|
|
||||||
if (_current < widget.struct.images.length) {
|
|
||||||
if (noAnimation()) {
|
|
||||||
_pageController.nextPage(
|
|
||||||
duration: Duration(milliseconds: 1),
|
|
||||||
curve: Curves.ease,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
_pageController.nextPage(
|
|
||||||
duration: Duration(milliseconds: 400),
|
|
||||||
curve: Curves.ease,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
void _onGalleryPageChange(int to) {
|
||||||
Widget build(BuildContext context) {
|
// 包含一个下一章, 假设5张图片 0,1,2,3,4 length=5, 下一章=5
|
||||||
return Stack(
|
if (to >= 0 && to < widget.struct.images.length) {
|
||||||
children: [
|
super._onCurrentChange(to);
|
||||||
_buildViewer(),
|
}
|
||||||
..._buildControllers(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildViewer() {
|
Widget _buildViewer() {
|
||||||
|
@ -758,34 +805,7 @@ class _GalleryReaderState extends State<_GalleryReader> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
pageController: _pageController,
|
pageController: _pageController,
|
||||||
onPageChanged: (value) {
|
onPageChanged: _onGalleryPageChange,
|
||||||
setState(() {
|
|
||||||
_current = value + 1;
|
|
||||||
_slider = value + 1;
|
|
||||||
widget.struct.onPositionChange(value);
|
|
||||||
if (galleryPrePreloadCount > 0) {
|
|
||||||
for (var count = 1;
|
|
||||||
count <= galleryPrePreloadCount && value - count >= 0;
|
|
||||||
count++) {
|
|
||||||
var target = widget.struct.images[value - count];
|
|
||||||
if (target.downloadLocalPath == null) {
|
|
||||||
method.remoteImagePreload(target.fileServer, target.path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (galleryPreloadCount > 0) {
|
|
||||||
for (var count = 1;
|
|
||||||
count <= galleryPreloadCount &&
|
|
||||||
value + count < widget.struct.images.length;
|
|
||||||
count++) {
|
|
||||||
var target = widget.struct.images[value + count];
|
|
||||||
if (target.downloadLocalPath == null) {
|
|
||||||
method.remoteImagePreload(target.fileServer, target.path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
itemCount: widget.struct.images.length,
|
itemCount: widget.struct.images.length,
|
||||||
builder: (BuildContext context, int index) {
|
builder: (BuildContext context, int index) {
|
||||||
var item = widget.struct.images[index];
|
var item = widget.struct.images[index];
|
||||||
|
@ -821,10 +841,9 @@ class _GalleryReaderState extends State<_GalleryReader> {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
child: gallery,
|
child: gallery,
|
||||||
onLongPress: () async {
|
onLongPress: () async {
|
||||||
var index = _current - 1;
|
if (_current >= 0 && _current < widget.struct.images.length) {
|
||||||
if (index >= 0 && _current < widget.struct.images.length) {
|
|
||||||
Future<String> Function() load = () async {
|
Future<String> Function() load = () async {
|
||||||
var item = widget.struct.images[index];
|
var item = widget.struct.images[_current];
|
||||||
if (item.downloadLocalPath != null) {
|
if (item.downloadLocalPath != null) {
|
||||||
return method.downloadImagePath(item.downloadLocalPath!);
|
return method.downloadImagePath(item.downloadLocalPath!);
|
||||||
}
|
}
|
||||||
|
@ -858,155 +877,9 @@ class _GalleryReaderState extends State<_GalleryReader> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildControllers() {
|
Widget _buildNextEpButton() {
|
||||||
var controllers = <Widget>[];
|
return Container();
|
||||||
if (!widget.struct.fullScreen) {
|
|
||||||
controllers.addAll([
|
|
||||||
_buildImageCount(context, "$_current / ${widget.struct.images.length}"),
|
|
||||||
_buildScrollController(
|
|
||||||
context,
|
|
||||||
_current,
|
|
||||||
_slider,
|
|
||||||
widget.struct.images.length,
|
|
||||||
(value) => _slider = value,
|
|
||||||
() {
|
|
||||||
if (_slider != _current && _slider > 0) {
|
|
||||||
_pageController.jumpToPage(_slider - 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
if (_current == widget.struct.images.length) {
|
|
||||||
controllers.add(_buildNextEpController(
|
|
||||||
widget.struct.onNextAction,
|
|
||||||
widget.struct.onNextText,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return controllers;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Widget _buildImageCount(BuildContext context, String info) {
|
|
||||||
return Align(
|
|
||||||
alignment: Alignment.topRight,
|
|
||||||
child: Material(
|
|
||||||
color: Color(0x0),
|
|
||||||
child: Container(
|
|
||||||
margin: EdgeInsets.only(top: 10),
|
|
||||||
padding: EdgeInsets.only(left: 10, right: 10, top: 4, bottom: 4),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(10),
|
|
||||||
bottomLeft: Radius.circular(10),
|
|
||||||
),
|
|
||||||
color: Color(0x88000000),
|
|
||||||
),
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
// TODO 输入跳转页数
|
|
||||||
},
|
|
||||||
child: Text("$info", style: TextStyle(color: Colors.white)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildScrollController(
|
|
||||||
BuildContext context,
|
|
||||||
int current,
|
|
||||||
int slider,
|
|
||||||
int total,
|
|
||||||
Function(int) onSliderChange,
|
|
||||||
Function() onSliderDown,
|
|
||||||
) {
|
|
||||||
if (total == 0) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
var theme = Theme.of(context);
|
|
||||||
return Align(
|
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
child: Material(
|
|
||||||
color: Color(0x0),
|
|
||||||
child: Container(
|
|
||||||
width: 35,
|
|
||||||
height: 300,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Color(0x66000000),
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(10),
|
|
||||||
bottomLeft: Radius.circular(10),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
padding: EdgeInsets.only(top: 10, bottom: 10, left: 5, right: 6),
|
|
||||||
child: Center(
|
|
||||||
child: FlutterSlider(
|
|
||||||
axis: Axis.vertical,
|
|
||||||
values: [(slider > total ? total : slider).toDouble()],
|
|
||||||
max: total.toDouble(),
|
|
||||||
min: 1,
|
|
||||||
onDragging: (handlerIndex, lowerValue, upperValue) {
|
|
||||||
onSliderChange(lowerValue.toInt());
|
|
||||||
},
|
|
||||||
onDragCompleted: (handlerIndex, lowerValue, upperValue) {
|
|
||||||
onSliderChange(lowerValue.toInt());
|
|
||||||
onSliderDown();
|
|
||||||
},
|
|
||||||
trackBar: FlutterSliderTrackBar(
|
|
||||||
inactiveTrackBar: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
color: Colors.grey.shade300,
|
|
||||||
),
|
|
||||||
activeTrackBar: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
color: theme.colorScheme.secondary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
step: FlutterSliderStep(
|
|
||||||
step: 1,
|
|
||||||
isPercentRange: false,
|
|
||||||
),
|
|
||||||
tooltip: FlutterSliderTooltip(custom: (value) {
|
|
||||||
double a = value;
|
|
||||||
return Container(
|
|
||||||
padding: EdgeInsets.all(5),
|
|
||||||
color: Colors.white,
|
|
||||||
child:
|
|
||||||
Text('${a.toInt()}', style: TextStyle(color: Colors.black)),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildNextEpController(Function() next, String text) {
|
|
||||||
return Align(
|
|
||||||
alignment: Alignment.bottomRight,
|
|
||||||
child: Material(
|
|
||||||
color: Color(0x0),
|
|
||||||
child: Container(
|
|
||||||
margin: EdgeInsets.only(bottom: 10),
|
|
||||||
padding: EdgeInsets.only(left: 10, right: 10, top: 4, bottom: 4),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(10),
|
|
||||||
bottomLeft: Radius.circular(10),
|
|
||||||
),
|
|
||||||
color: Color(0x88000000),
|
|
||||||
),
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
next();
|
|
||||||
},
|
|
||||||
child: Text(text, style: TextStyle(color: Colors.white)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue