diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 1345921c..f9e235c2 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -40,6 +40,8 @@ class ChannelPreview extends StatelessWidget { } Text _buildDate(BuildContext context, DateTime lastMessageAt) { + lastMessageAt = lastMessageAt.toLocal(); + String stringDate; final now = DateTime.now(); diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 56c1aeea..1350cd0b 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -51,46 +51,70 @@ class _MessageWidgetState extends State final alignment = isMyMessage ? Alignment.centerRight : Alignment.centerLeft; - var row = [ - Column( - crossAxisAlignment: - isMyMessage ? CrossAxisAlignment.end : CrossAxisAlignment.start, - children: [ - _buildBubble(context, isMyMessage, isLastUser), - _buildThreadIndicator(context), - isNextUser ? SizedBox() : _buildTimestamp(isMyMessage, alignment), - ], - ), - isNextUser - ? Container( - width: 40, - ) - : Padding( - padding: EdgeInsets.only( - left: isMyMessage ? 8.0 : 0, - right: isMyMessage ? 0 : 8.0, - ), - child: UserAvatar(user: widget.message.user), - ), - ]; + Widget child; - if (!isMyMessage) { - row = row.reversed.toList(); + if (widget.message.type == 'deleted') { + child = Align( + alignment: alignment, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 54, + vertical: 14, + ), + child: Text( + 'This message was deleted...', + style: TextStyle(fontStyle: FontStyle.italic), + ), + ), + ); + } else { + var row = [ + Column( + crossAxisAlignment: + isMyMessage ? CrossAxisAlignment.end : CrossAxisAlignment.start, + children: [ + _buildBubble(context, isMyMessage, isLastUser), + _buildThreadIndicator(context), + isNextUser ? SizedBox() : _buildTimestamp(isMyMessage, alignment), + ], + ), + isNextUser + ? Container( + width: 40, + ) + : Padding( + padding: EdgeInsets.only( + left: isMyMessage ? 8.0 : 0, + right: isMyMessage ? 0 : 8.0, + ), + child: UserAvatar(user: widget.message.user), + ), + ]; + + if (!isMyMessage) { + row = row.reversed.toList(); + } + + child = AnimatedContainer( + duration: Duration(milliseconds: 300), + padding: const EdgeInsets.symmetric(horizontal: 10.0), + margin: EdgeInsets.only( + top: isLastUser ? 5 : 24, + bottom: widget.nextMessage == null ? 30 : 0, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: + isMyMessage ? MainAxisAlignment.end : MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: row, + ), + ); } - return Container( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - margin: EdgeInsets.only( - top: isLastUser ? 5 : 24, - bottom: widget.nextMessage == null ? 30 : 0, - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: - isMyMessage ? MainAxisAlignment.end : MainAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: row, - ), + return AnimatedSwitcher( + duration: Duration(milliseconds: 300), + child: child, ); } @@ -147,71 +171,75 @@ class _MessageWidgetState extends State if (attachmentWidget != null) { final boxDecoration = _buildBoxDecoration(isMyMessage, isLastUser) .copyWith(color: Color(0xffebebeb)); - return ClipRRect( - borderRadius: boxDecoration.borderRadius, - child: Container( - decoration: boxDecoration, - constraints: BoxConstraints.loose(Size.fromWidth(300)), - child: Stack( - children: [ - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - attachmentWidget, - attachment.title != null - ? Container( - constraints: - BoxConstraints.loose(Size.fromHeight(70)), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - attachment.title, - overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .subtitle - .copyWith(color: Colors.blue), - ), - Text( - Uri.parse(attachment.thumbUrl) - .authority - .split('.') - .reversed - .take(2) - .toList() - .reversed - .join('.'), - overflow: TextOverflow.ellipsis, - style: - Theme.of(context).textTheme.caption, - ), - ], + return Padding( + padding: const EdgeInsets.only(bottom: 2.0), + child: ClipRRect( + borderRadius: boxDecoration.borderRadius, + child: Container( + decoration: boxDecoration, + constraints: BoxConstraints.loose(Size.fromWidth(300)), + child: Stack( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + attachmentWidget, + attachment.title != null + ? Container( + constraints: + BoxConstraints.loose(Size.fromHeight(70)), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + attachment.title, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .subtitle + .copyWith(color: Colors.blue), + ), + Text( + Uri.parse(attachment.thumbUrl) + .authority + .split('.') + .reversed + .take(2) + .toList() + .reversed + .join('.'), + overflow: TextOverflow.ellipsis, + style: + Theme.of(context).textTheme.caption, + ), + ], + ), ), + color: Color(0xffebebeb), + ) + : Container(), + ], + ), + attachment.type == 'image' && attachment.titleLink != null + ? Positioned.fill( + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => _launchURL(attachment.titleLink), ), - color: Color(0xffebebeb), - ) - : Container(), - ], - ), - attachment.type == 'image' && attachment.titleLink != null - ? Positioned.fill( - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: () => _launchURL(attachment.titleLink), ), - ), - ) - : SizedBox(), - ], - ), - margin: EdgeInsets.only( - top: nOfAttachmentWidgets > 1 ? 5 : 0, + ) + : SizedBox(), + ], + ), + margin: EdgeInsets.only( + top: nOfAttachmentWidgets > 1 ? 5 : 0, + ), ), ), ); @@ -223,8 +251,6 @@ class _MessageWidgetState extends State ); if (widget.message.text.trim().isNotEmpty) { - final topPadding = - widget.message.reactionCounts?.isNotEmpty == true ? 2.0 : 0.0; column.children.addAll( [ IntrinsicWidth( @@ -246,7 +272,7 @@ class _MessageWidgetState extends State ? Positioned( left: isMyMessage ? 8 : null, right: !isMyMessage ? 8 : null, - top: -4, + top: -6, child: CustomPaint( painter: ReactionBubblePainter(), ), @@ -258,11 +284,6 @@ class _MessageWidgetState extends State left: isMyMessage ? 8.0 : 0.0, ), child: Container( - margin: EdgeInsets.only( - top: nOfAttachmentWidgets > 0 - ? (topPadding) - : (topPadding), - ), decoration: _buildBoxDecoration(isMyMessage, isLastUser || nOfAttachmentWidgets > 0), padding: EdgeInsets.all(10), @@ -289,11 +310,11 @@ class _MessageWidgetState extends State return GestureDetector( child: column, onLongPress: () { - _showMessageBottomSheet(context); + _showMessageBottomSheet(context, isMyMessage); }); } - void _showMessageBottomSheet(BuildContext context) { + void _showMessageBottomSheet(BuildContext context, bool isMyMessage) { showModalBottomSheet( context: context, builder: (context) { @@ -301,38 +322,68 @@ class _MessageWidgetState extends State final textStyle = TextStyle( fontSize: fontSize, ); - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, + return Column( mainAxisSize: MainAxisSize.min, - children: reactionToEmoji.keys.map((reactionType) { - final ownReactionIndex = widget.message.ownReactions - .indexWhere((reaction) => reaction.type == reactionType); - return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - IconButton( - iconSize: fontSize + 10, - icon: Text( - reactionToEmoji[reactionType], - style: textStyle, - ), - onPressed: () { - if (ownReactionIndex != -1) { - removeReaction(reactionType); - } else { - sendReaction(reactionType); - } - }, - ), - ownReactionIndex != -1 - ? Text(widget.message.ownReactions[ownReactionIndex].score - .toString()) - : SizedBox(), - ], - ); - }).toList(), + children: reactionToEmoji.keys.map((reactionType) { + final ownReactionIndex = widget.message.ownReactions + .indexWhere((reaction) => reaction.type == reactionType); + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + IconButton( + iconSize: fontSize + 10, + icon: Text( + reactionToEmoji[reactionType], + style: textStyle, + ), + onPressed: () { + if (ownReactionIndex != -1) { + removeReaction(reactionType); + } else { + sendReaction(reactionType); + } + }, + ), + ownReactionIndex != -1 + ? Padding( + padding: const EdgeInsets.only(bottom: 4.0), + child: Text(widget + .message.ownReactions[ownReactionIndex].score + .toString()), + ) + : SizedBox(), + ], + ); + }).toList(), + ), + isMyMessage + ? FlatButton( + child: Padding( + padding: const EdgeInsets.all(28.0), + child: Text( + 'Delete message', + style: Theme.of(context) + .textTheme + .headline + .copyWith(color: Colors.red), + ), + ), + onPressed: () { + StreamChat.of(context) + .client + .deleteMessage(widget.message.id); + Navigator.pop(context); + }, + ) + : SizedBox(), + ], ); }); } @@ -340,10 +391,12 @@ class _MessageWidgetState extends State Widget _buildReactions(bool isMyMessage) { return GestureDetector( onTap: () { - _showMessageBottomSheet(context); + _showMessageBottomSheet(context, isMyMessage); }, child: Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), + padding: EdgeInsets.symmetric( + vertical: + widget.message.reactionCounts?.isNotEmpty == true ? 4.0 : 0), child: AnimatedContainer( duration: Duration(milliseconds: 300), curve: Curves.decelerate,