From 64ed2b2187d8eac5a6343bd779ed172c545b2c96 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 13 Nov 2020 19:41:45 +0530 Subject: [PATCH] feat: Added image actions modal --- lib/src/full_screen_image.dart | 100 +++++++++++---------- lib/src/image_actions_modal.dart | 145 +++++++++++++++++++++++++++++++ lib/src/image_header.dart | 16 +++- 3 files changed, 215 insertions(+), 46 deletions(-) create mode 100644 lib/src/image_actions_modal.dart diff --git a/lib/src/full_screen_image.dart b/lib/src/full_screen_image.dart index e0dd79a3..b616c17a 100644 --- a/lib/src/full_screen_image.dart +++ b/lib/src/full_screen_image.dart @@ -35,7 +35,7 @@ class _FullScreenImageState extends State AnimationController _controller; PageController _pageController; - + int _currentPage; @override @@ -53,56 +53,66 @@ class _FullScreenImageState extends State body: Stack( children: [ AnimatedBuilder( - animation: _controller, - builder: (context, snapshot) { - return PageView.builder( - controller: _pageController, - onPageChanged: (val) { - setState(() { - _currentPage = val; - }); - }, - itemBuilder: (context, position) { - return PhotoView( - imageProvider: CachedNetworkImageProvider(widget.urls[position]), - maxScale: PhotoViewComputedScale.covered, - minScale: PhotoViewComputedScale.contained, - heroAttributes: PhotoViewHeroAttributes( - tag: widget.urls, - ), - backgroundDecoration: BoxDecoration( - color: ColorTween( - begin: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .color, - end: Colors.black).lerp(_controller.value), - ), - onTapUp: (a, b, c) { - setState(() { - _optionsShown = !_optionsShown; - }); - if(_controller.isCompleted) { - _controller.reverse(); - } else { - _controller.forward(); - } - }, - ); - }, - itemCount: widget.urls.length, - ); - } - ), + animation: _controller, + builder: (context, snapshot) { + return PageView.builder( + controller: _pageController, + onPageChanged: (val) { + setState(() { + _currentPage = val; + }); + }, + itemBuilder: (context, position) { + return PhotoView( + imageProvider: + CachedNetworkImageProvider(widget.urls[position]), + maxScale: PhotoViewComputedScale.covered, + minScale: PhotoViewComputedScale.contained, + heroAttributes: PhotoViewHeroAttributes( + tag: widget.urls, + ), + backgroundDecoration: BoxDecoration( + color: ColorTween( + begin: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .color, + end: Colors.black) + .lerp(_controller.value), + ), + onTapUp: (a, b, c) { + setState(() { + _optionsShown = !_optionsShown; + }); + if (_controller.isCompleted) { + _controller.reverse(); + } else { + _controller.forward(); + } + }, + ); + }, + itemCount: widget.urls.length, + ); + }), AnimatedOpacity( opacity: _optionsShown ? 1.0 : 0.0, duration: Duration(milliseconds: 300), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - ImageHeader(userName: widget.userName, sentAt: 'Sent at${Jiffy(widget.sentAt.toLocal()) - .format(' HH:mm')}',), - ImageFooter(currentPage: _currentPage, totalPages: widget.urls.length,), + ImageHeader( + userName: widget.userName, + sentAt: + 'Sent at${Jiffy(widget.sentAt.toLocal()).format(' HH:mm')}', + onBackPressed: () { + Navigator.of(context).pop(); + }, + ), + ImageFooter( + currentPage: _currentPage, + totalPages: widget.urls.length, + ), ], ), ), diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart new file mode 100644 index 00000000..03603795 --- /dev/null +++ b/lib/src/image_actions_modal.dart @@ -0,0 +1,145 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +import '../stream_chat_flutter.dart'; +import 'stream_icons.dart'; + +class ImageActionsModal extends StatelessWidget { + final String userName; + final String sentAt; + + ImageActionsModal({this.userName, this.sentAt}); + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Navigator.pop(context); + }, + child: Stack( + children: [ + Positioned.fill( + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black.withOpacity(0.8), + Colors.transparent, + ], + stops: [0.0, 0.4], + ) + ), + ) + ), + _buildPage(context), + ], + ), + ); + } + + Widget _buildPage(context) { + return Material( + color: Colors.transparent, + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + width: 40.0, + ), + ), + Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text( + userName, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w700, + color: Colors.white, + ), + ), + ), + Text( + sentAt, + style: + StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith(color: Colors.white.withOpacity(0.5)), + ), + ], + ), + IconButton( + icon: Icon( + StreamIcons.close, + size: 24.0, + color: Colors.white, + ), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + Align( + alignment: Alignment.centerRight, + child: Container( + width: MediaQuery.of(context).size.width / 1.8, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + color: Color(0xffe5e5e5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: ListTile.divideTiles( + context: context, + tiles: [ + _buildButton(context, 'Reply', StreamIcons.curve_line_down_left, () {}), + _buildButton(context, 'Show in Chat', StreamIcons.eye, () {}), + _buildButton(context, 'Save Image', StreamIcons.save_1, () {}), + _buildButton(context, 'Copy', StreamIcons.copy, () {}), + _buildButton(context, 'Delete', StreamIcons.delete, () {}, color: Colors.red), + ], + ).toList(), + ), + ), + ), + ), + ), + ], + ), + ); + } + + Widget _buildButton(context, String title, IconData iconData, VoidCallback onTap, {Color color}) { + var titleStyle = TextStyle( + fontSize: 14.5, + color: Colors.black, + fontWeight: FontWeight.w500, + ); + + return ListTile( + dense: true, + title: Text( + title, + style: color == null ? titleStyle : titleStyle.copyWith(color: color), + ), + leading: Icon( + iconData, + color: color ?? StreamChatTheme.of(context).primaryIconTheme.color, + size: 24.0, + ), + onTap: onTap, + ); + } +} diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart index 39f2ccb9..b4dfb36d 100644 --- a/lib/src/image_header.dart +++ b/lib/src/image_header.dart @@ -8,6 +8,7 @@ import 'package:stream_chat_flutter/src/stream_icons.dart'; import './channel_name.dart'; import 'channel_image.dart'; +import 'image_actions_modal.dart'; import 'stream_channel.dart'; class ImageHeader extends StatelessWidget implements PreferredSizeWidget { @@ -63,7 +64,9 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { color: Colors.black, size: 24.0, ), - onPressed: () {}, + onPressed: () { + _showMessageActionModalBottomSheet(context); + }, ), ], centerTitle: true, @@ -98,4 +101,15 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { @override final Size preferredSize; + + void _showMessageActionModalBottomSheet(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return ImageActionsModal( + userName: userName, + sentAt: sentAt, + ); + }); + } }