add listview reader type

This commit is contained in:
niuhuan 2021-12-04 11:54:19 +08:00
parent 046a9e8f50
commit 6328e7d83b
2 changed files with 257 additions and 59 deletions

View File

@ -7,12 +7,14 @@ enum ReaderType {
WEB_TOON, WEB_TOON,
WEB_TOON_ZOOM, WEB_TOON_ZOOM,
GALLERY, GALLERY,
WEB_TOON_FREE_ZOOM,
} }
const _types = { const _types = {
'WebToon (默认)': ReaderType.WEB_TOON, 'WebToon (默认)': ReaderType.WEB_TOON,
'WebToon + 双击放大': ReaderType.WEB_TOON_ZOOM, 'WebToon (双击放大)': ReaderType.WEB_TOON_ZOOM,
'相册': ReaderType.GALLERY, '相册': ReaderType.GALLERY,
'WebToon (ListView双击放大)\n(此模式进度条无效)': ReaderType.WEB_TOON_FREE_ZOOM
}; };
const _propertyName = "readerType"; const _propertyName = "readerType";

View File

@ -202,6 +202,8 @@ class _ImageReaderContent extends StatefulWidget {
return _WebToonZoomReaderState(); return _WebToonZoomReaderState();
case ReaderType.GALLERY: case ReaderType.GALLERY:
return _GalleryReaderState(); return _GalleryReaderState();
case ReaderType.WEB_TOON_FREE_ZOOM:
return _ListViewReaderState();
default: default:
throw Exception("ERROR READER TYPE"); throw Exception("ERROR READER TYPE");
} }
@ -352,7 +354,26 @@ abstract class _ImageReaderContentState extends State<_ImageReaderContent> {
), ),
Container(width: 10), Container(width: 10),
Expanded( Expanded(
child: Column( child: widget.pagerType != ReaderType.WEB_TOON_FREE_ZOOM
? _buildSlider()
: Container(),
),
Container(width: 10),
IconButton(
icon: Icon(Icons.skip_next_outlined),
color: Colors.white,
onPressed: _onNextAction,
),
Container(width: 15),
],
),
)
],
);
}
Widget _buildSlider() {
return Column(
children: [ children: [
Expanded(child: Container()), Expanded(child: Container()),
Container( Container(
@ -365,8 +386,7 @@ abstract class _ImageReaderContentState extends State<_ImageReaderContent> {
onDragging: (handlerIndex, lowerValue, upperValue) { onDragging: (handlerIndex, lowerValue, upperValue) {
_slider = (lowerValue.toInt()); _slider = (lowerValue.toInt());
}, },
onDragCompleted: onDragCompleted: (handlerIndex, lowerValue, upperValue) {
(handlerIndex, lowerValue, upperValue) {
_slider = (lowerValue.toInt()); _slider = (lowerValue.toInt());
if (_slider != _current) { if (_slider != _current) {
_needJumpTo(_slider, false); _needJumpTo(_slider, false);
@ -393,8 +413,7 @@ abstract class _ImageReaderContentState extends State<_ImageReaderContent> {
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: Colors.black.withAlpha(0xCC), color: Colors.black.withAlpha(0xCC),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: borderRadius: BorderRadiusDirectional.circular(3)),
BorderRadiusDirectional.circular(3)),
), ),
child: Text( child: Text(
'${a.toInt()}', '${a.toInt()}',
@ -409,19 +428,6 @@ abstract class _ImageReaderContentState extends State<_ImageReaderContent> {
), ),
Expanded(child: Container()), Expanded(child: Container()),
], ],
),
),
Container(width: 10),
IconButton(
icon: Icon(Icons.skip_next_outlined),
color: Colors.white,
onPressed: _onNextAction,
),
Container(width: 15),
],
),
)
],
); );
} }
@ -1096,6 +1102,196 @@ class _WebToonZoomReaderState extends _WebToonReaderState {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
class _ListViewReaderState extends _ImageReaderContentState
with SingleTickerProviderStateMixin {
final List<Size?> _trueSizes = [];
final _transformationController = TransformationController();
late TapDownDetails _doubleTapDetails;
late final _animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 100),
);
@override
void initState() {
widget.struct.images.forEach((e) {
if (e.downloadLocalPath != null) {
_trueSizes.add(Size(e.width!.toDouble(), e.height!.toDouble()));
} else {
_trueSizes.add(null);
}
});
super.initState();
}
@override
void dispose() {
_transformationController.dispose();
_animationController.dispose();
super.dispose();
}
@override
void _needJumpTo(int index, bool animation) {}
@override
Widget _buildViewer() {
return Container(
decoration: BoxDecoration(
color: Colors.black,
),
child: _buildList(),
);
}
Widget _buildList() {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
// reload _images size
List<Widget> _images = [];
for (var index = 0; index < widget.struct.images.length; index++) {
late Size renderSize;
if (_trueSizes[index] != null) {
if (widget.pagerDirection == ReaderDirection.TOP_TO_BOTTOM) {
renderSize = Size(
constraints.maxWidth,
constraints.maxWidth *
_trueSizes[index]!.height /
_trueSizes[index]!.width,
);
} else {
renderSize = Size(
constraints.maxHeight *
_trueSizes[index]!.width /
_trueSizes[index]!.height,
constraints.maxHeight,
);
}
} else {
if (widget.pagerDirection == ReaderDirection.TOP_TO_BOTTOM) {
renderSize = Size(constraints.maxWidth, constraints.maxWidth / 2);
} else {
// ReaderDirection.LEFT_TO_RIGHT
// ReaderDirection.RIGHT_TO_LEFT
renderSize =
Size(constraints.maxWidth / 2, constraints.maxHeight);
}
}
var currentIndex = index;
var onTrueSize = (Size size) {
setState(() {
_trueSizes[currentIndex] = size;
});
};
var e = widget.struct.images[index];
if (e.downloadLocalPath != null) {
_images.add(_WebToonDownloadImage(
fileServer: e.fileServer,
path: e.path,
localPath: e.downloadLocalPath!,
fileSize: e.fileSize!,
width: e.width!,
height: e.height!,
format: e.format!,
size: renderSize,
onTrueSize: onTrueSize,
));
} else {
_images.add(_WebToonRemoteImage(
e.fileServer,
e.path,
renderSize,
onTrueSize,
));
}
}
var list = ListView.builder(
scrollDirection:
widget.pagerDirection == ReaderDirection.TOP_TO_BOTTOM
? Axis.vertical
: Axis.horizontal,
reverse: widget.pagerDirection == ReaderDirection.RIGHT_TO_LEFT,
padding: EdgeInsets.only(
// , ,
top: super._topBarHeight(),
bottom: widget.pagerDirection == ReaderDirection.TOP_TO_BOTTOM
? 130 // 130
: ( //
widget.struct.fullScreen
? super._topBarHeight() //
: super._bottomBarHeight())
// , BAR的高度, BAR的高度,
,
),
itemCount: widget.struct.images.length + 1,
itemBuilder: (BuildContext context, int index) {
if (widget.struct.images.length == index) {
return _buildNextEp();
}
return _images[index];
},
);
var viewer = InteractiveViewer(
transformationController: _transformationController,
minScale: 1,
maxScale: 2,
child: list,
);
return GestureDetector(
onDoubleTap: _handleDoubleTap,
onDoubleTapDown: _handleDoubleTapDown,
child: viewer,
);
},
);
}
Widget _buildNextEp() {
return Container(
padding: EdgeInsets.all(20),
child: MaterialButton(
onPressed: () {
if (super._hasNextEp()) {
super._onNextAction();
} else {
Navigator.of(context).pop();
}
},
textColor: Colors.white,
child: Container(
padding: EdgeInsets.only(top: 40, bottom: 40),
child: Text(super._hasNextEp() ? '下一章' : '结束阅读'),
),
),
);
}
void _handleDoubleTapDown(TapDownDetails details) {
_doubleTapDetails = details;
}
void _handleDoubleTap() {
if (_animationController.isAnimating) {
return;
}
if (_transformationController.value != Matrix4.identity()) {
_transformationController.value = Matrix4.identity();
} else {
var position = _doubleTapDetails.localPosition;
var animation = Tween(begin: 0, end: 1.0).animate(_animationController);
animation.addListener(() {
_transformationController.value = Matrix4.identity()
..translate(
-position.dx * animation.value, -position.dy * animation.value)
..scale(animation.value + 1.0);
});
_animationController.forward(from: 0);
}
}
}
///////////////////////////////////////////////////////////////////////////////
class _GalleryReaderState extends _ImageReaderContentState { class _GalleryReaderState extends _ImageReaderContentState {
late PageController _pageController; late PageController _pageController;