mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-04-22 03:31:09 +08:00
21
lib/common/widgets/colored_box_transition.dart
Normal file
21
lib/common/widgets/colored_box_transition.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ColoredBoxTransition extends AnimatedWidget {
|
||||
const ColoredBoxTransition({
|
||||
super.key,
|
||||
required this.color,
|
||||
this.child,
|
||||
}) : super(listenable: color);
|
||||
|
||||
final Animation<Color?> color;
|
||||
|
||||
final Widget? child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ColoredBox(
|
||||
color: color.value!,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
import 'dart:io' show File, Platform;
|
||||
|
||||
import 'package:PiliPlus/common/widgets/colored_box_transition.dart';
|
||||
import 'package:PiliPlus/common/widgets/flutter/page/page_view.dart';
|
||||
import 'package:PiliPlus/common/widgets/gesture/image_horizontal_drag_gesture_recognizer.dart';
|
||||
import 'package:PiliPlus/common/widgets/gesture/image_tap_gesture_recognizer.dart';
|
||||
@@ -52,7 +53,7 @@ class GalleryViewer extends StatefulWidget {
|
||||
this.maxScale = 8.0,
|
||||
required this.quality,
|
||||
required this.sources,
|
||||
this.initIndex = 1,
|
||||
this.initIndex = 0,
|
||||
});
|
||||
|
||||
final double minScale;
|
||||
@@ -87,14 +88,12 @@ class _GalleryViewerState extends State<GalleryViewer>
|
||||
late final LongPressGestureRecognizer _longPressGestureRecognizer;
|
||||
|
||||
late final AnimationController _animateController;
|
||||
late final Animation<Decoration> _opacityAnimation;
|
||||
late final Animation<Color?> _opacityAnimation;
|
||||
double dx = 0, dy = 0;
|
||||
|
||||
Offset _offset = Offset.zero;
|
||||
bool _dragging = false;
|
||||
|
||||
bool get _isActive => _dragging || _animateController.isAnimating;
|
||||
|
||||
String _getActualUrl(String url) {
|
||||
return _quality != 100
|
||||
? ImageUtils.thumbnailUrl(url, _quality)
|
||||
@@ -138,14 +137,16 @@ class _GalleryViewerState extends State<GalleryViewer>
|
||||
});
|
||||
|
||||
_animateController = AnimationController(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
duration: const Duration(
|
||||
milliseconds: 750,
|
||||
), // reverse only if value <= 0.2
|
||||
vsync: this,
|
||||
);
|
||||
|
||||
_opacityAnimation = _animateController.drive(
|
||||
DecorationTween(
|
||||
begin: const BoxDecoration(color: Colors.black),
|
||||
end: const BoxDecoration(color: Colors.transparent),
|
||||
ColorTween(
|
||||
begin: Colors.black,
|
||||
end: Colors.transparent,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -189,7 +190,7 @@ class _GalleryViewerState extends State<GalleryViewer>
|
||||
}
|
||||
|
||||
void _onDragUpdate(ScaleUpdateDetails details) {
|
||||
if (!_isActive || _animateController.isAnimating) {
|
||||
if (!_dragging || _animateController.isAnimating) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -202,16 +203,12 @@ class _GalleryViewerState extends State<GalleryViewer>
|
||||
}
|
||||
|
||||
void _onDragEnd(ScaleEndDetails details) {
|
||||
if (!_isActive || _animateController.isAnimating) {
|
||||
if (!_dragging || _animateController.isAnimating) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dragging = false;
|
||||
|
||||
if (_animateController.isCompleted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_animateController.isDismissed) {
|
||||
if (_animateController.value > 0.2) {
|
||||
Get.back();
|
||||
@@ -256,37 +253,35 @@ class _GalleryViewerState extends State<GalleryViewer>
|
||||
return Listener(
|
||||
behavior: .opaque,
|
||||
onPointerDown: _onPointerDown,
|
||||
child: DecoratedBoxTransition(
|
||||
decoration: _opacityAnimation,
|
||||
child: Stack(
|
||||
fit: .expand,
|
||||
alignment: .center,
|
||||
clipBehavior: .none,
|
||||
children: [
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
_containerSize = constraints.biggest;
|
||||
return MatrixTransition(
|
||||
alignment: .topLeft,
|
||||
animation: _animateController,
|
||||
onTransform: _onTransform,
|
||||
child: PageView<ImageHorizontalDragGestureRecognizer>.builder(
|
||||
controller: _pageController,
|
||||
onPageChanged: _onPageChanged,
|
||||
physics: const CustomTabBarViewScrollPhysics(
|
||||
parent: AlwaysScrollableScrollPhysics(),
|
||||
),
|
||||
itemCount: widget.sources.length,
|
||||
itemBuilder: _itemBuilder,
|
||||
horizontalDragGestureRecognizer: () =>
|
||||
_horizontalDragGestureRecognizer,
|
||||
child: Stack(
|
||||
fit: .expand,
|
||||
alignment: .center,
|
||||
clipBehavior: .none,
|
||||
children: [
|
||||
ColoredBoxTransition(color: _opacityAnimation),
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
_containerSize = constraints.biggest;
|
||||
return MatrixTransition(
|
||||
alignment: .topLeft,
|
||||
animation: _animateController,
|
||||
onTransform: _onTransform,
|
||||
child: PageView<ImageHorizontalDragGestureRecognizer>.builder(
|
||||
controller: _pageController,
|
||||
onPageChanged: _onPageChanged,
|
||||
physics: const CustomTabBarViewScrollPhysics(
|
||||
parent: AlwaysScrollableScrollPhysics(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
_buildIndicator,
|
||||
],
|
||||
),
|
||||
itemCount: widget.sources.length,
|
||||
itemBuilder: _itemBuilder,
|
||||
horizontalDragGestureRecognizer: () =>
|
||||
_horizontalDragGestureRecognizer,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
_buildIndicator,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -77,10 +77,26 @@ class _ViewerState extends State<Viewer> with SingleTickerProviderStateMixin {
|
||||
|
||||
_GestureType? _gestureType;
|
||||
|
||||
final Matrix4 _matrix = Matrix4.identity();
|
||||
|
||||
late double __scale;
|
||||
double get _scale => __scale;
|
||||
set _scale(double value) {
|
||||
__scale = value;
|
||||
_matrix[0] = _matrix[5] = _matrix[10] = value;
|
||||
}
|
||||
|
||||
late Offset __position;
|
||||
Offset get _position => __position;
|
||||
set _position(Offset value) {
|
||||
__position = value;
|
||||
_matrix
|
||||
..[12] = value.dx
|
||||
..[13] = value.dy;
|
||||
}
|
||||
|
||||
Offset? _scalePos;
|
||||
late double _scale;
|
||||
double? _scaleStart;
|
||||
late Offset _position;
|
||||
Offset? _referenceFocalPoint;
|
||||
|
||||
late Size _imageSize;
|
||||
@@ -97,10 +113,6 @@ class _ViewerState extends State<Viewer> with SingleTickerProviderStateMixin {
|
||||
late double _scaleFrom, _scaleTo;
|
||||
late Offset _positionFrom, _positionTo;
|
||||
|
||||
Matrix4 get _matrix =>
|
||||
Matrix4.translationValues(_position.dx, _position.dy, 0.0)
|
||||
..scaleByDouble(_scale, _scale, _scale, 1.0);
|
||||
|
||||
void _listener() {
|
||||
final t = Curves.easeOut.transform(_animationController.value);
|
||||
_scale = t.lerp(_scaleFrom, _scaleTo);
|
||||
@@ -396,7 +408,7 @@ class _ViewerState extends State<Viewer> with SingleTickerProviderStateMixin {
|
||||
onPointerDown: _onPointerDown,
|
||||
onPointerPanZoomStart: _onPointerPanZoomStart,
|
||||
onPointerSignal: _onPointerSignal,
|
||||
child: ClipRRect(
|
||||
child: ClipRect(
|
||||
child: Transform(
|
||||
transform: _matrix,
|
||||
child: widget.child,
|
||||
|
||||
Reference in New Issue
Block a user