opt: image viewer (#1837)

* opt: image

* opt: MatrixTransition

* update


---------

Co-authored-by: dom <githubaccount56556@proton.me>
This commit is contained in:
My-Responsitories
2026-02-15 17:13:55 +08:00
committed by GitHub
parent 9c7c6f9e4e
commit 85292a3df2
3 changed files with 101 additions and 88 deletions

View File

@@ -16,7 +16,6 @@
*/
import 'dart:io' show File, Platform;
import 'dart:ui' as ui;
import 'package:PiliPlus/common/widgets/flutter/page/page_view.dart';
import 'package:PiliPlus/common/widgets/gesture/image_horizontal_drag_gesture_recognizer.dart';
@@ -26,6 +25,7 @@ import 'package:PiliPlus/common/widgets/image_viewer/loading_indicator.dart';
import 'package:PiliPlus/common/widgets/image_viewer/viewer.dart';
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
import 'package:PiliPlus/models/common/image_preview_type.dart';
import 'package:PiliPlus/utils/extension/num_ext.dart';
import 'package:PiliPlus/utils/extension/string_ext.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
@@ -70,7 +70,7 @@ class _GalleryViewerState extends State<GalleryViewer>
late Size _containerSize;
late final int _quality;
late final RxInt _currIndex;
late final List<GlobalKey> _keys;
GlobalKey? _key;
Player? _player;
Player get _effectivePlayer => _player ??= Player();
@@ -85,7 +85,6 @@ class _GalleryViewerState extends State<GalleryViewer>
_horizontalDragGestureRecognizer;
late final LongPressGestureRecognizer _longPressGestureRecognizer;
final Rx<Matrix4> _matrix = Rx(Matrix4.identity());
late final AnimationController _animateController;
late final Animation<Decoration> _opacityAnimation;
double dx = 0, dy = 0;
@@ -106,8 +105,13 @@ class _GalleryViewerState extends State<GalleryViewer>
super.initState();
_quality = Pref.previewQ;
_currIndex = widget.initIndex.obs;
_playIfNeeded(widget.initIndex);
_keys = List.generate(widget.sources.length, (_) => GlobalKey());
final item = widget.sources[widget.initIndex];
_playIfNeeded(item);
if (!item.isLongPic) {
_key = GlobalKey();
WidgetsBinding.instance.addPostFrameCallback((_) => _key = null);
}
_pageController = PageController(initialPage: widget.initIndex);
@@ -134,27 +138,23 @@ class _GalleryViewerState extends State<GalleryViewer>
end: const BoxDecoration(color: Colors.transparent),
),
);
_animateController.addListener(_updateTransformation);
}
void _updateTransformation() {
final val = _animateController.value;
final scale = ui.lerpDouble(1.0, 0.25, val)!;
Matrix4 _onTransform(double val) {
final scale = val.lerp(1.0, 0.25);
// Matrix4.identity()
// ..translateByDouble(size.width / 2, size.height / 2, 0, 1)
// ..translateByDouble(size.width * val * dx, size.height * val * dy, 0, 1)
// ..scaleByDouble(scale, scale, 1, 1)
// ..scaleByDouble(scale, scale, scale, 1)
// ..translateByDouble(-size.width / 2, -size.height / 2, 0, 1);
final tmp = (1.0 - scale) / 2.0;
_matrix.value = Matrix4.diagonal3Values(scale, scale, scale)
..setTranslationRaw(
_containerSize.width * (val * dx + tmp),
_containerSize.height * (val * dy + tmp),
0,
);
return Matrix4.diagonal3Values(scale, scale, scale)..setTranslationRaw(
_containerSize.width * (val * dx + tmp),
_containerSize.height * (val * dy + tmp),
0,
);
}
void _updateMoveAnimation() {
@@ -217,13 +217,10 @@ class _GalleryViewerState extends State<GalleryViewer>
_player = null;
_videoController = null;
_pageController.dispose();
_animateController
..removeListener(_updateTransformation)
..dispose();
_animateController.dispose();
_tapGestureRecognizer.dispose();
_longPressGestureRecognizer.dispose();
_currIndex.close();
_matrix.close();
if (widget.quality != _quality) {
for (final item in widget.sources) {
if (item.sourceType == SourceType.networkImage) {
@@ -252,21 +249,20 @@ class _GalleryViewerState extends State<GalleryViewer>
LayoutBuilder(
builder: (context, constraints) {
_containerSize = constraints.biggest;
return Obx(
() => Transform(
transform: _matrix.value,
child:
PageView<ImageHorizontalDragGestureRecognizer>.builder(
controller: _pageController,
onPageChanged: _onPageChanged,
physics: const CustomTabBarViewScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
itemCount: widget.sources.length,
itemBuilder: _itemBuilder,
horizontalDragGestureRecognizer: () =>
_horizontalDragGestureRecognizer,
),
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,
),
);
},
@@ -308,8 +304,7 @@ class _GalleryViewerState extends State<GalleryViewer>
),
);
void _playIfNeeded(int index) {
final item = widget.sources[index];
void _playIfNeeded(SourceModel item) {
if (item.sourceType == .livePhoto) {
_effectivePlayer.open(Media(item.liveUrl!));
}
@@ -317,7 +312,7 @@ class _GalleryViewerState extends State<GalleryViewer>
void _onPageChanged(int index) {
_player?.pause();
_playIfNeeded(index);
_playIfNeeded(widget.sources[index]);
_currIndex.value = index;
}
@@ -340,11 +335,11 @@ class _GalleryViewerState extends State<GalleryViewer>
Widget _itemBuilder(BuildContext context, int index) {
final item = widget.sources[index];
Widget child;
final Widget child;
switch (item.sourceType) {
case SourceType.fileImage:
child = Image.file(
key: _keys[index],
key: _key,
File(item.url),
filterQuality: .low,
minScale: widget.minScale,
@@ -360,7 +355,7 @@ class _GalleryViewerState extends State<GalleryViewer>
case SourceType.networkImage:
final isLongPic = item.isLongPic;
child = Image(
key: _keys[index],
key: _key,
image: CachedNetworkImageProvider(_getActualUrl(item.url)),
minScale: widget.minScale,
maxScale: widget.maxScale,
@@ -414,7 +409,7 @@ class _GalleryViewerState extends State<GalleryViewer>
}
case SourceType.livePhoto:
child = Obx(
key: _keys[index],
key: _key,
() => _currIndex.value == index
? Viewer(
minScale: widget.minScale,