Skip to content

Commit

Permalink
feat: Add option to allow swipe-down to dismiss
Browse files Browse the repository at this point in the history
An ticket asked for swipe-to-dismiss (#14)
It's easy to implement and now supported with the `swipeDismissable` argument.
This allows the user to drag the dialog down to dismiss it.
However, this is still WIP because when the user has zoomed in, you can't pan the
image anymore because the Dismissable widget begins to dismiss. Will have to address
this in a future commit.
  • Loading branch information
jfahrenkrug committed May 16, 2022
1 parent edc35d4 commit 65dbce7
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 48 deletions.
7 changes: 7 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"recommendations": [
"dart-code.dart-code",
"dart-code.flutter"
]
}

7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"[dart]": {
"editor.defaultFormatter": "Dart-Code.dart-code",
"editor.formatOnSave": false
},
"dart.lineLength": 120
}
9 changes: 3 additions & 6 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,13 @@ class _MyHomePageState extends State<MyHomePage> {
ElevatedButton(
child: const Text("Show Single Image"),
onPressed: () {
showImageViewer(
context,
Image.network("https://picsum.photos/id/1001/5616/3744")
.image);
showImageViewer(context, Image.network("https://picsum.photos/id/1001/5616/3744").image,
swipeDismissable: true);
}),
ElevatedButton(
child: const Text("Show Multiple Images (Simple)"),
onPressed: () {
MultiImageProvider multiImageProvider =
MultiImageProvider(_imageProviders);
MultiImageProvider multiImageProvider = MultiImageProvider(_imageProviders);
showImageViewerPager(context, multiImageProvider);
}),
ElevatedButton(
Expand Down
88 changes: 47 additions & 41 deletions lib/easy_image_viewer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,24 @@ const _defaultCloseButtonTooltip = 'Close';
/// Setting [immersive] to false will prevent the top and bottom bars from being hidden.
/// The optional [onViewerDismissed] callback function is called when the dialog is closed.
/// The optional [useSafeArea] boolean defaults to false and is passed to [showDialog].
/// The optional [swipeDismissable] boolean defaults to false allows swipe-down-to-dismiss.
/// The [backgroundColor] defaults to black, but can be set to any other color.
/// The [closeButtonTooltip] text is displayed when the user long-presses on the
/// close button and is used for accessibility.
/// The [closeButtonColor] defaults to white, but can be set to any other color.
Future<Dialog?> showImageViewer(
BuildContext context, ImageProvider imageProvider,
Future<Dialog?> showImageViewer(BuildContext context, ImageProvider imageProvider,
{bool immersive = true,
void Function()? onViewerDismissed,
bool useSafeArea = false,
bool swipeDismissable = false,
Color backgroundColor = _defaultBackgroundColor,
String closeButtonTooltip = _defaultCloseButtonTooltip,
Color closeButtonColor = _defaultCloseButtonColor}) {
return showImageViewerPager(context, SingleImageProvider(imageProvider),
immersive: immersive,
onViewerDismissed:
onViewerDismissed != null ? (_) => onViewerDismissed() : null,
onViewerDismissed: onViewerDismissed != null ? (_) => onViewerDismissed() : null,
useSafeArea: useSafeArea,
swipeDismissable: swipeDismissable,
backgroundColor: backgroundColor,
closeButtonTooltip: closeButtonTooltip,
closeButtonColor: closeButtonColor);
Expand All @@ -54,16 +55,17 @@ Future<Dialog?> showImageViewer(
/// The optional [onViewerDismissed] callback function is called with the index of
/// the image that is displayed when the dialog is closed.
/// The optional [useSafeArea] boolean defaults to false and is passed to [showDialog].
/// The optional [swipeDismissable] boolean defaults to false allows swipe-down-to-dismiss.
/// The [backgroundColor] defaults to black, but can be set to any other color.
/// The [closeButtonTooltip] text is displayed when the user long-presses on the
/// close button and is used for accessibility.
/// The [closeButtonColor] defaults to white, but can be set to any other color.
Future<Dialog?> showImageViewerPager(
BuildContext context, EasyImageProvider imageProvider,
Future<Dialog?> showImageViewerPager(BuildContext context, EasyImageProvider imageProvider,
{bool immersive = true,
void Function(int)? onPageChanged,
void Function(int)? onViewerDismissed,
bool useSafeArea = false,
bool swipeDismissable = false,
Color backgroundColor = _defaultBackgroundColor,
String closeButtonTooltip = _defaultCloseButtonTooltip,
Color closeButtonColor = _defaultCloseButtonColor}) {
Expand All @@ -73,8 +75,7 @@ Future<Dialog?> showImageViewerPager(
}

void Function()? internalPageChangeListener;
final pageController =
PageController(initialPage: imageProvider.initialIndex);
final pageController = PageController(initialPage: imageProvider.initialIndex);

if (onPageChanged != null) {
internalPageChangeListener = () {
Expand All @@ -87,42 +88,47 @@ Future<Dialog?> showImageViewerPager(
context: context,
useSafeArea: useSafeArea,
builder: (context) {
return Dialog(
final dialog = Dialog(
backgroundColor: backgroundColor,
insetPadding: const EdgeInsets.all(0),
child: Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: <Widget>[
EasyImageViewPager(
easyImageProvider: imageProvider,
pageController: pageController),
Positioned(
top: 5,
right: 5,
child: IconButton(
icon: const Icon(Icons.close),
color: closeButtonColor,
tooltip: closeButtonTooltip,
onPressed: () {
Navigator.of(context).pop();
child: Stack(clipBehavior: Clip.none, alignment: Alignment.center, children: <Widget>[
EasyImageViewPager(easyImageProvider: imageProvider, pageController: pageController),
Positioned(
top: 5,
right: 5,
child: IconButton(
icon: const Icon(Icons.close),
color: closeButtonColor,
tooltip: closeButtonTooltip,
onPressed: () {
Navigator.of(context).pop();

if (onViewerDismissed != null) {
onViewerDismissed(
pageController.page?.round() ?? 0);
}
if (onViewerDismissed != null) {
onViewerDismissed(pageController.page?.round() ?? 0);
}

if (immersive) {
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.edgeToEdge);
}
if (internalPageChangeListener != null) {
pageController
.removeListener(internalPageChangeListener);
}
pageController.dispose();
},
))
]));
if (immersive) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
}
if (internalPageChangeListener != null) {
pageController.removeListener(internalPageChangeListener);
}
pageController.dispose();
},
))
]));

if (swipeDismissable) {
return Dismissible(
direction: DismissDirection.down,
resizeDuration: null,
onDismissed: (_) {
Navigator.of(context).pop();
},
key: const Key('dismissable_easy_image_viewer_dialog'),
child: dialog);
} else {
return dialog;
}
});
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: easy_image_viewer
description: An easy image viewer with pinch & zoom, multi image, and built-in full-screen dialog support.
version: 1.0.4
version: 1.0.5
homepage: https://github.com/thesmythgroup/easy_image_viewer

environment:
Expand Down

0 comments on commit 65dbce7

Please sign in to comment.