Media View improvements (#128)
This commit is contained in:
parent
79fb42785c
commit
430d196997
|
@ -1,3 +1,9 @@
|
|||
## Unreleased
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed image viewer dismissal to be more fun. The image now also moves on the x axis, changes scale and rotates a bit for more user enjoyment
|
||||
|
||||
## v0.2.2 - 2021-02-03
|
||||
|
||||
Minimum Lemmy version supported: `v0.9.4`
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import 'dart:math' show max, min;
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:matrix4_transform/matrix4_transform.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
|
||||
import '../widgets/bottom_modal.dart';
|
||||
|
@ -11,6 +13,8 @@ import '../widgets/bottom_modal.dart';
|
|||
class MediaViewPage extends HookWidget {
|
||||
final String url;
|
||||
final GlobalKey<ScaffoldState> _key = GlobalKey();
|
||||
static const yThreshold = 150;
|
||||
static const speedThreshold = 45;
|
||||
|
||||
MediaViewPage(this.url);
|
||||
|
||||
|
@ -18,30 +22,19 @@ class MediaViewPage extends HookWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final showButtons = useState(true);
|
||||
final isZoomedOut = useState(true);
|
||||
final scaleIsInitial = useState(true);
|
||||
|
||||
final isDragging = useState(false);
|
||||
|
||||
final offset = useState(Offset.zero);
|
||||
final prevOffset = usePrevious(offset.value);
|
||||
|
||||
notImplemented() {
|
||||
_key.currentState.showSnackBar(const SnackBar(
|
||||
content: Text("this feature hasn't been implemented yet 😰")));
|
||||
}
|
||||
|
||||
useEffect(() {
|
||||
if (showButtons.value) {
|
||||
SystemChrome.setEnabledSystemUIOverlays([
|
||||
SystemUiOverlay.bottom,
|
||||
SystemUiOverlay.top,
|
||||
]);
|
||||
} else {
|
||||
SystemChrome.setEnabledSystemUIOverlays([]);
|
||||
}
|
||||
return null;
|
||||
}, [showButtons.value]);
|
||||
|
||||
useEffect(
|
||||
() => () => SystemChrome.setEnabledSystemUIOverlays([
|
||||
SystemUiOverlay.bottom,
|
||||
SystemUiOverlay.top,
|
||||
]),
|
||||
[]);
|
||||
// TODO: hide navbar and topbar on android without a content jump
|
||||
|
||||
share() {
|
||||
showModalBottomSheet(
|
||||
|
@ -77,6 +70,8 @@ class MediaViewPage extends HookWidget {
|
|||
key: _key,
|
||||
extendBodyBehindAppBar: true,
|
||||
extendBody: true,
|
||||
backgroundColor:
|
||||
Colors.black.withOpacity(max(0, 1.0 - (offset.value.dy.abs() / 200))),
|
||||
appBar: showButtons.value
|
||||
? AppBar(
|
||||
backgroundColor: Colors.black38,
|
||||
|
@ -96,26 +91,67 @@ class MediaViewPage extends HookWidget {
|
|||
],
|
||||
)
|
||||
: null,
|
||||
body: GestureDetector(
|
||||
onTapUp: (details) => showButtons.value = !showButtons.value,
|
||||
onVerticalDragEnd: isZoomedOut.value
|
||||
? (details) {
|
||||
if (details.primaryVelocity.abs() > 1000) {
|
||||
body: Listener(
|
||||
onPointerMove: scaleIsInitial.value
|
||||
? (event) {
|
||||
if (!isDragging.value &&
|
||||
event.delta.dx.abs() > event.delta.dy.abs()) return;
|
||||
isDragging.value = true;
|
||||
offset.value += event.delta;
|
||||
}
|
||||
: (_) => isDragging.value = false,
|
||||
onPointerCancel: (_) => offset.value = Offset.zero,
|
||||
onPointerUp: isZoomedOut.value
|
||||
? (_) {
|
||||
if (!isDragging.value) {
|
||||
showButtons.value = !showButtons.value;
|
||||
return;
|
||||
}
|
||||
|
||||
isDragging.value = false;
|
||||
final speed = (offset.value - prevOffset).distance;
|
||||
if (speed > speedThreshold ||
|
||||
offset.value.dy.abs() > yThreshold) {
|
||||
Navigator.of(context).pop();
|
||||
} else {
|
||||
offset.value = Offset.zero;
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: PhotoView(
|
||||
scaleStateChangedCallback: (value) {
|
||||
isZoomedOut.value = value == PhotoViewScaleState.zoomedOut ||
|
||||
value == PhotoViewScaleState.initial;
|
||||
},
|
||||
minScale: PhotoViewComputedScale.contained,
|
||||
initialScale: PhotoViewComputedScale.contained,
|
||||
imageProvider: CachedNetworkImageProvider(url),
|
||||
heroAttributes: PhotoViewHeroAttributes(tag: url),
|
||||
loadingBuilder: (context, event) =>
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
: (_) {
|
||||
offset.value = Offset.zero;
|
||||
isDragging.value = false;
|
||||
},
|
||||
child: AnimatedContainer(
|
||||
transform: Matrix4Transform()
|
||||
.scale(max(0.9, 1 - offset.value.dy.abs() / 1000))
|
||||
.translateOffset(offset.value)
|
||||
.rotate(min(-offset.value.dx / 2000, 0.1))
|
||||
.matrix4,
|
||||
duration: isDragging.value
|
||||
? Duration.zero
|
||||
: const Duration(milliseconds: 200),
|
||||
child: PhotoView(
|
||||
backgroundDecoration:
|
||||
const BoxDecoration(color: Colors.transparent),
|
||||
scaleStateChangedCallback: (value) {
|
||||
isZoomedOut.value = value == PhotoViewScaleState.zoomedOut ||
|
||||
value == PhotoViewScaleState.initial;
|
||||
showButtons.value = isZoomedOut.value;
|
||||
|
||||
scaleIsInitial.value = value == PhotoViewScaleState.initial;
|
||||
isDragging.value = false;
|
||||
offset.value = Offset.zero;
|
||||
},
|
||||
onTapUp: isZoomedOut.value
|
||||
? null
|
||||
: (_, __, ___) => showButtons.value = !showButtons.value,
|
||||
minScale: PhotoViewComputedScale.contained,
|
||||
initialScale: PhotoViewComputedScale.contained,
|
||||
imageProvider: CachedNetworkImageProvider(url),
|
||||
heroAttributes: PhotoViewHeroAttributes(tag: url),
|
||||
loadingBuilder: (context, event) =>
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -67,6 +67,7 @@ void goToMedia(BuildContext context, String url) => Navigator.push(
|
|||
PageRouteBuilder(
|
||||
pageBuilder: (_, __, ___) => MediaViewPage(url),
|
||||
transitionDuration: const Duration(milliseconds: 300),
|
||||
opaque: false,
|
||||
transitionsBuilder: (_, animation, __, child) =>
|
||||
FadeTransition(opacity: animation, child: child),
|
||||
),
|
||||
|
|
|
@ -282,6 +282,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.10-nullsafety.1"
|
||||
matrix4_transform:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: matrix4_transform
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.7"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -44,6 +44,8 @@ dependencies:
|
|||
timeago: ^2.0.27
|
||||
fuzzy: <1.0.0
|
||||
lemmy_api_client: ^0.10.2
|
||||
matrix4_transform: ^1.1.7
|
||||
|
||||
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
|
Loading…
Reference in New Issue