diff --git a/.github/workflows/dispatch_workflows.yml b/.github/workflows/dispatch_workflows.yml index 5743a0aa..6d626fdb 100644 --- a/.github/workflows/dispatch_workflows.yml +++ b/.github/workflows/dispatch_workflows.yml @@ -20,7 +20,7 @@ jobs: repo: GetStream/flutter-samples token: ${{ secrets.GH_TOKEN }} dispatch_stable: - if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - uses: benc-uk/workflow-dispatch@v1 diff --git a/.github/workflows/pr_title.yml b/.github/workflows/pr_title.yml index 6f4ad786..2a53261b 100644 --- a/.github/workflows/pr_title.yml +++ b/.github/workflows/pr_title.yml @@ -5,6 +5,8 @@ on: - opened - edited - synchronize + branches: + - develop jobs: main: diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index 8edf9293..a25bbdb3 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -8,12 +8,12 @@ on: push: branches: - master + - develop paths-ignore: - 'docs/**' jobs: analyze: - if: github.base_ref == 'master' timeout-minutes: 15 runs-on: ubuntu-latest steps: diff --git a/README.md b/README.md index 0d465852..b0a88432 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,11 @@ Stream allows developers to rapidly deploy scalable feeds and chat messaging wit ## Sample apps and demos Our team maintains a dedicated repository for fully-fledged sample applications and demos. Consider checking out [GetStream/flutter-samples](https://github.com/GetStream/flutter-samples) to learn more or get started by looking at our latest [Stream Chat demo](https://github.com/GetStream/flutter-samples/tree/main/stream_chat_v1). +## Free for Makers + +Stream is free for most side and hobby projects. To qualify your project/company needs to have < 5 team members and < $10k in monthly revenue. +For complete pricing details visit our [Chat Pricing Page](https://getstream.io/chat/pricing/) + ## Structure Stream Chat Dart is a monorepo built using [Melos](https://docs.page/invertase/melos). Individual packages can be found in the `packages` directory while configuration and top level commands can be found in `melos.yaml`. diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index 4e30d452..8cf0fad1 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.5.0 + +- Minor fixes and improvements + ## 1.4.0-beta - Improved attachment uploading diff --git a/packages/stream_chat/analysis_options.yaml b/packages/stream_chat/analysis_options.yaml index 7e4b00fa..26001160 100644 --- a/packages/stream_chat/analysis_options.yaml +++ b/packages/stream_chat/analysis_options.yaml @@ -44,7 +44,6 @@ linter: - avoid_private_typedef_functions - avoid_redundant_argument_values - avoid_return_types_on_setters - - avoid_returning_null - avoid_returning_null_for_void - avoid_shadowing_type_parameters - avoid_single_cascade_in_expression_statements diff --git a/packages/stream_chat/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart index 52b748d4..1701fed8 100644 --- a/packages/stream_chat/lib/src/api/channel.dart +++ b/packages/stream_chat/lib/src/api/channel.dart @@ -1209,6 +1209,7 @@ class ChannelClientState { ChannelClientState( this._channel, ChannelState channelState, + //ignore: unnecessary_parenthesis ) : _debouncedUpdatePersistenceChannelState = ((ChannelState state) { _channel?._client?.chatPersistenceClient?.updateChannelState(state); }).debounced(const Duration(seconds: 1)) { diff --git a/packages/stream_chat/lib/version.dart b/packages/stream_chat/lib/version.dart index 207ba25e..c593eede 100644 --- a/packages/stream_chat/lib/version.dart +++ b/packages/stream_chat/lib/version.dart @@ -3,4 +3,4 @@ import 'package:stream_chat/src/client.dart'; /// Current package version /// Used in [StreamChatClient] to build the `x-stream-client` header // ignore: constant_identifier_names -const PACKAGE_VERSION = '1.4.0-beta'; +const PACKAGE_VERSION = '1.5.0'; diff --git a/packages/stream_chat/pubspec.yaml b/packages/stream_chat/pubspec.yaml index 410cc561..81aef23e 100644 --- a/packages/stream_chat/pubspec.yaml +++ b/packages/stream_chat/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat homepage: https://getstream.io/ description: The official Dart client for Stream Chat, a service for building chat applications. -version: 1.4.0-beta +version: 1.5.0 repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index d432f441..ff336e8d 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -1,3 +1,15 @@ +## 1.5.1 + +- Fixed unread count not updating while the chat is open + +## 1.5.0 + +- Fixed swipeable visible on navigation back +- Fixed video upload +- `MessageInput`: added more actions locations, merge actions and add `showCommandsButton` property +- 🛑 **BREAKING** Updated AttachmentBuilder signature +- Fixed image reloading on reaction.new + ## 1.4.0-beta - Unfocus `MessageInput` only when sending commands @@ -10,7 +22,7 @@ - Added `MessageListView.onAttachmentTap` callback - Fixed message newline issue - Fixed `MessageListView` scroll keyboard behaviour -- Minor fixes and improveqments +- Minor fixes and improvements ## 1.3.2-beta diff --git a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart index 49403f0c..1003c767 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart @@ -6,7 +6,6 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/src/video_thumbnail_image.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import 'package:transparent_image/transparent_image.dart'; import '../upload_progress_indicator.dart'; import 'attachment_widget.dart'; diff --git a/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart index 4ded5ca7..5bb810b4 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/giphy_attachment.dart @@ -1,10 +1,7 @@ -import 'dart:typed_data'; - import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:shimmer/shimmer.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import 'package:transparent_image/transparent_image.dart'; import '../full_screen_media.dart'; import '../stream_chat_theme.dart'; diff --git a/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart index 98509bb9..aa8d1246 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart @@ -4,9 +4,9 @@ import 'package:shimmer/shimmer.dart'; import 'package:stream_chat_flutter/src/attachment/attachment_upload_state_builder.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; -import 'attachment_title.dart'; import '../full_screen_media.dart'; import '../stream_chat_theme.dart'; +import 'attachment_title.dart'; import 'attachment_widget.dart'; class ImageAttachment extends AttachmentWidget { @@ -81,6 +81,7 @@ class ImageAttachment extends AttachmentWidget { return _buildImageAttachment( context, CachedNetworkImage( + cacheKey: imageUri.path, height: size?.height, width: size?.width, placeholder: (_, __) { diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index 883210ba..c997d09c 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -5,10 +5,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:stream_chat_flutter/src/message_action.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'extension.dart'; import 'message_input.dart'; @@ -34,6 +34,7 @@ class MessageActionsModal extends StatefulWidget { final ShapeBorder messageShape; final ShapeBorder attachmentShape; final DisplayWidget showUserAvatar; + final BorderRadius attachmentBorderRadiusGeometry; /// List of custom actions final List customActions; @@ -58,6 +59,7 @@ class MessageActionsModal extends StatefulWidget { this.attachmentShape, this.reverse = false, this.customActions = const [], + this.attachmentBorderRadiusGeometry, }) : super(key: key); @override @@ -153,6 +155,8 @@ class _MessageActionsModalState extends State { child: MessageWidget( key: Key('MessageWidget'), reverse: widget.reverse, + attachmentBorderRadiusGeometry: + widget.attachmentBorderRadiusGeometry, message: widget.message.copyWith( text: widget.message.text.length > 200 ? '${widget.message.text.substring(0, 200)}...' diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 21dda0f4..4a18bf02 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -12,12 +12,12 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:image_picker/image_picker.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:shimmer/shimmer.dart'; -import 'package:stream_chat_flutter/src/video_service.dart'; import 'package:stream_chat_flutter/src/media_list_view.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; +import 'package:stream_chat_flutter/src/video_service.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:substring_highlight/substring_highlight.dart'; @@ -35,6 +35,8 @@ typedef AttachmentThumbnailBuilder = Widget Function( enum ActionsLocation { left, right, + leftInside, + rightInside, } enum DefaultAttachmentTypes { @@ -122,6 +124,7 @@ class MessageInput extends StatefulWidget { this.hideSendAsDm = false, this.idleSendButton, this.activeSendButton, + this.showCommandsButton = true, }) : super(key: key); /// Message to edit @@ -149,6 +152,9 @@ class MessageInput extends StatefulWidget { /// If true the attachments button will not be displayed final bool disableAttachments; + /// Use this property to hide/show the commands button + final bool showCommandsButton; + /// Hide send as dm checkbox final bool hideSendAsDm; @@ -308,7 +314,7 @@ class MessageInputState extends State { ), ), Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.symmetric(vertical: 8.0), child: _buildTextField(context), ), if (widget.parentMessage != null && !widget.hideSendAsDm) @@ -336,12 +342,11 @@ class MessageInputState extends State { direction: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.center, children: [ - if (!_commandEnabled) _buildExpandActionsButton(), - if (widget.actionsLocation == ActionsLocation.left) - ...widget.actions ?? [], + if (!_commandEnabled && widget.actionsLocation == ActionsLocation.left) + _buildExpandActionsButton(), _buildTextInput(context), - if (widget.actionsLocation == ActionsLocation.right) - ...widget.actions ?? [], + if (!_commandEnabled && widget.actionsLocation == ActionsLocation.right) + _buildExpandActionsButton(), if (widget.sendButtonLocation == SendButtonLocation.outside) _animateSendButton(context), ], @@ -421,32 +426,36 @@ class MessageInputState extends State { child: widget.activeSendButton, ) : _buildSendButton(context); - return Padding( - padding: const EdgeInsets.all(8.0), - child: AnimatedCrossFade( - crossFadeState: (_messageIsPresent || _attachments.isNotEmpty) - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: sendButton, - secondChild: widget.idleSendButton ?? _buildIdleSendButton(context), - duration: - StreamChatTheme.of(context).messageInputTheme.sendAnimationDuration, - alignment: Alignment.center, - ), + return AnimatedCrossFade( + crossFadeState: (_messageIsPresent || _attachments.isNotEmpty) + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: sendButton, + secondChild: widget.idleSendButton ?? _buildIdleSendButton(context), + duration: + StreamChatTheme.of(context).messageInputTheme.sendAnimationDuration, + alignment: Alignment.center, ); } Widget _buildExpandActionsButton() { return Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.symmetric(horizontal: 8.0), child: AnimatedCrossFade( crossFadeState: _actionsShrunk ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: IconButton( onPressed: () => setState(() => _actionsShrunk = false), - icon: StreamSvgIcon.emptyCircleLeft( - color: StreamChatTheme.of(context).colorTheme.accentBlue, + icon: Transform.rotate( + alignment: Alignment.center, + angle: (widget.actionsLocation == ActionsLocation.right || + widget.actionsLocation == ActionsLocation.rightInside) + ? pi + : 0, + child: StreamSvgIcon.emptyCircleLeft( + color: StreamChatTheme.of(context).colorTheme.accentBlue, + ), ), padding: const EdgeInsets.all(0), constraints: BoxConstraints.tightFor( @@ -457,10 +466,12 @@ class MessageInputState extends State { ), secondChild: FittedBox( child: Row( + crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ + children: [ if (!widget.disableAttachments) _buildAttachmentButton(), - if (widget.editMessage == null && + if (widget.showCommandsButton && + widget.editMessage == null && StreamChannel.of(context) .channel ?.config @@ -468,6 +479,7 @@ class MessageInputState extends State { ?.isNotEmpty == true) _buildCommandButton(), + ...widget.actions ?? [], ].insertBetween(const SizedBox(width: 8)), ), ), @@ -565,51 +577,75 @@ class MessageInputState extends State { ), ), contentPadding: const EdgeInsets.fromLTRB(16, 12, 13, 11), - prefixIconConstraints: BoxConstraints.tight(Size(78, 24)), - suffixIconConstraints: BoxConstraints.tight(Size(40, 40)), prefixIcon: _commandEnabled - ? Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: theme.colorTheme.accentBlue, - ), - margin: const EdgeInsets.only(right: 4, left: 8), - alignment: Alignment.center, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - StreamSvgIcon.lightning( - color: Colors.white, - size: 16.0, - ), - Text( - _chosenCommand?.name?.toUpperCase() ?? '', - style: StreamChatTheme.of(context) - .textTheme - .footnoteBold - .copyWith( + ? Row( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + constraints: BoxConstraints.tight(Size(64, 24)), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: theme.colorTheme.accentBlue, + ), + alignment: Alignment.center, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + StreamSvgIcon.lightning( color: Colors.white, + size: 16.0, ), + Text( + _chosenCommand?.name?.toUpperCase() ?? '', + style: StreamChatTheme.of(context) + .textTheme + .footnoteBold + .copyWith( + color: Colors.white, + ), + ), + ], + ), ), - ], - ), + ), + ], ) - : null, + : (widget.actionsLocation == ActionsLocation.leftInside + ? Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildExpandActionsButton(), + ], + ) + : null), + suffixIconConstraints: BoxConstraints.tightFor(height: 40), + prefixIconConstraints: BoxConstraints.tightFor(height: 40), suffixIcon: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, children: [ if (_commandEnabled) - IconButton( - icon: StreamSvgIcon.closeSmall(), - splashRadius: 24, - padding: const EdgeInsets.all(0), - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: IconButton( + icon: StreamSvgIcon.closeSmall(), + splashRadius: 24, + padding: const EdgeInsets.all(0), + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + onPressed: () { + setState(() => _commandEnabled = false); + }, ), - onPressed: () { - setState(() => _commandEnabled = false); - }, ), + if (!_commandEnabled && + widget.actionsLocation == ActionsLocation.rightInside) + _buildExpandActionsButton(), if (widget.sendButtonLocation == SendButtonLocation.inside) _animateSendButton(context), ], @@ -619,7 +655,13 @@ class MessageInputState extends State { Timer _debounce; + String _previousValue; void _onChanged(BuildContext context, String s) { + if (s == _previousValue) { + return; + } + _previousValue = s; + if (_debounce?.isActive == true) _debounce.cancel(); _debounce = Timer( const Duration(milliseconds: 350), @@ -631,7 +673,11 @@ class MessageInputState extends State { setState(() { _messageIsPresent = s.trim().isNotEmpty; - _actionsShrunk = s.trim().isNotEmpty; + _actionsShrunk = s.trim().isNotEmpty && + ((widget.actions?.length ?? 0) + + (widget.showCommandsButton ? 1 : 0) + + (widget.disableAttachments ? 0 : 1) > + 1); }); _commandsOverlay?.remove(); @@ -1684,13 +1730,19 @@ class MessageInputState extends State { } Widget _buildCommandButton() { + final s = textEditingController.text.trim(); + return IconButton( icon: StreamSvgIcon.lightning( - color: _commandsOverlay != null - ? StreamChatTheme.of(context).messageInputTheme.actionButtonColor - : StreamChatTheme.of(context) - .messageInputTheme - .actionButtonIdleColor, + color: s.isNotEmpty + ? StreamChatTheme.of(context).colorTheme.greyGainsboro + : (_commandsOverlay != null + ? StreamChatTheme.of(context) + .messageInputTheme + .actionButtonColor + : StreamChatTheme.of(context) + .messageInputTheme + .actionButtonIdleColor), ), padding: const EdgeInsets.all(0), constraints: BoxConstraints.tightFor( @@ -1711,7 +1763,9 @@ class MessageInputState extends State { if (_commandsOverlay == null) { setState(() { _commandsOverlay = _buildCommandsOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); + if (_commandsOverlay != null) { + Overlay.of(context).insert(_commandsOverlay); + } }); } else { setState(() { @@ -1904,11 +1958,11 @@ class MessageInputState extends State { if (file == null) return; - final mimeType = file.name?.mimeType; + final mimeType = file.name?.mimeType ?? file.path.split('/').last.mimeType; final extraDataMap = {}; - if (mimeType.type == 'video' || mimeType.type == 'image') { + if (mimeType?.type == 'video' || mimeType?.type == 'image') { attachmentType = mimeType.type; } else { attachmentType = 'file'; @@ -1965,24 +2019,31 @@ class MessageInputState extends State { } Widget _buildIdleSendButton(BuildContext context) { - return StreamSvgIcon( - assetName: _getIdleSendIcon(), - color: StreamChatTheme.of(context).messageInputTheme.sendButtonIdleColor, + return Padding( + padding: const EdgeInsets.all(8.0), + child: StreamSvgIcon( + assetName: _getIdleSendIcon(), + color: + StreamChatTheme.of(context).messageInputTheme.sendButtonIdleColor, + ), ); } Widget _buildSendButton(BuildContext context) { - return IconButton( - onPressed: sendMessage, - padding: const EdgeInsets.all(0), - splashRadius: 24, - constraints: BoxConstraints.tightFor( - height: 24, - width: 24, - ), - icon: StreamSvgIcon( - assetName: _getSendIcon(), - color: StreamChatTheme.of(context).messageInputTheme.sendButtonColor, + return Padding( + padding: const EdgeInsets.all(8.0), + child: IconButton( + onPressed: sendMessage, + padding: const EdgeInsets.all(0), + splashRadius: 24, + constraints: BoxConstraints.tightFor( + height: 24, + width: 24, + ), + icon: StreamSvgIcon( + assetName: _getSendIcon(), + color: StreamChatTheme.of(context).messageInputTheme.sendButtonColor, + ), ), ); } diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 1abff664..5b1c3a99 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -749,7 +749,7 @@ class _MessageListViewState extends State { Widget messageWidget; if (widget.messageBuilder != null) { messageWidget = Builder( - key: ValueKey('BOTTOM-MESSAGE'), + key: ValueKey('BOTTOM-MESSAGE-${message.id}'), builder: (_) => widget.messageBuilder( context, MessageDetails( @@ -766,7 +766,7 @@ class _MessageListViewState extends State { } return VisibilityDetector( - key: ValueKey('BOTTOM-MESSAGE'), + key: ValueKey('BOTTOM-MESSAGE-${message.id}'), onVisibilityChanged: (visibility) { final isVisible = visibility.visibleBounds != Rect.zero; if (isVisible) { @@ -1021,15 +1021,19 @@ class _MessageListViewState extends State { !message.isSystem && !message.isEphemeral && widget.onMessageSwiped != null) { - child = Swipeable( - onSwipeEnd: () { - FocusScope.of(context).unfocus(); - widget.onMessageSwiped(message); - }, - backgroundIcon: StreamSvgIcon.reply( - color: StreamChatTheme.of(context).colorTheme.accentBlue, + child = Container( + decoration: BoxDecoration(), + clipBehavior: Clip.hardEdge, + child: Swipeable( + onSwipeEnd: () { + FocusScope.of(context).unfocus(); + widget.onMessageSwiped(message); + }, + backgroundIcon: StreamSvgIcon.reply( + color: StreamChatTheme.of(context).colorTheme.accentBlue, + ), + child: child, ), - child: Container(child: child), ); } diff --git a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart index a9e55a0a..c2a13ae7 100644 --- a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart @@ -1,17 +1,16 @@ import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/message_action.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_chat.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +import 'extension.dart'; import 'message_widget.dart'; import 'stream_chat_theme.dart'; -import 'extension.dart'; class MessageReactionsModal extends StatelessWidget { final Widget Function(BuildContext, Message) editMessageInputBuilder; @@ -24,6 +23,7 @@ class MessageReactionsModal extends StatelessWidget { final ShapeBorder messageShape; final ShapeBorder attachmentShape; final void Function(User) onUserAvatarTap; + final BorderRadius attachmentBorderRadiusGeometry; const MessageReactionsModal({ Key key, @@ -37,6 +37,7 @@ class MessageReactionsModal extends StatelessWidget { this.reverse = false, this.showUserAvatar = DisplayWidget.show, this.onUserAvatarTap, + this.attachmentBorderRadiusGeometry, }) : super(key: key); @override @@ -133,6 +134,8 @@ class MessageReactionsModal extends StatelessWidget { shape: messageShape, attachmentShape: attachmentShape, padding: const EdgeInsets.all(0), + attachmentBorderRadiusGeometry: + attachmentBorderRadiusGeometry, attachmentPadding: EdgeInsets.all( hasFileAttachment ? 4 : 2, ), diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index 67e38c75..a0c1201a 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -235,6 +235,7 @@ class MessageWidget extends StatefulWidget { ), border, reverse, + attachmentBorderRadiusGeometry ?? BorderRadius.zero, ), ); } @@ -259,6 +260,7 @@ class MessageWidget extends StatefulWidget { ), border, reverse, + attachmentBorderRadiusGeometry ?? BorderRadius.zero, ); }, 'video': (context, message, attachments) { @@ -291,6 +293,7 @@ class MessageWidget extends StatefulWidget { ), border, reverse, + attachmentBorderRadiusGeometry ?? BorderRadius.zero, ); }, 'giphy': (context, message, attachments) { @@ -318,6 +321,7 @@ class MessageWidget extends StatefulWidget { ), border, reverse, + attachmentBorderRadiusGeometry ?? BorderRadius.zero, ); }, 'file': (context, message, attachments) { @@ -329,22 +333,28 @@ class MessageWidget extends StatefulWidget { borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero, ); - return wrapAttachmentWidget( - context, - Column( - children: attachments.map((attachment) { - return FileAttachment( - message: message, - attachment: attachment, - size: Size( - MediaQuery.of(context).size.width * 0.8, - MediaQuery.of(context).size.height * 0.3, - ), - ); - }).toList(), - ), - border, - reverse, + return Column( + children: attachments + .map((attachment) { + return wrapAttachmentWidget( + context, + FileAttachment( + message: message, + attachment: attachment, + size: Size( + MediaQuery.of(context).size.width * 0.8, + MediaQuery.of(context).size.height * 0.3, + ), + ), + border, + reverse, + attachmentBorderRadiusGeometry ?? BorderRadius.zero, + ); + }) + .insertBetween(SizedBox( + height: attachmentPadding.vertical / 2, + )) + .toList(), ); }, }..addAll(customAttachmentBuilders ?? {}), @@ -822,6 +832,8 @@ class _MessageWidgetState extends State return StreamChannel( channel: channel, child: MessageActionsModal( + attachmentBorderRadiusGeometry: + widget.attachmentBorderRadiusGeometry, showUserAvatar: widget.message.user.id == channel.client.state.user.id ? DisplayWidget.gone @@ -869,6 +881,8 @@ class _MessageWidgetState extends State return StreamChannel( channel: channel, child: MessageReactionsModal( + attachmentBorderRadiusGeometry: + widget.attachmentBorderRadiusGeometry, showUserAvatar: widget.message.user.id == channel.client.state.user.id ? DisplayWidget.gone @@ -913,7 +927,7 @@ class _MessageWidgetState extends State } Widget _parseAttachments() { - Map> attachmentGroups = {}; + final attachmentGroups = >{}; widget.message.attachments .where((element) => element.ogScrapeUrl == null) @@ -925,7 +939,7 @@ class _MessageWidgetState extends State attachmentGroups[e.type].add(e); }); - List attachmentList = []; + final attachmentList = []; attachmentGroups.forEach((type, attachments) { final attachmentBuilder = widget.attachmentBuilders[type]; diff --git a/packages/stream_chat_flutter/lib/src/utils.dart b/packages/stream_chat_flutter/lib/src/utils.dart index fee747a9..8950a77c 100644 --- a/packages/stream_chat_flutter/lib/src/utils.dart +++ b/packages/stream_chat_flutter/lib/src/utils.dart @@ -356,15 +356,19 @@ Widget wrapAttachmentWidget( Widget attachmentWidget, ShapeBorder attachmentShape, bool reverse, + BorderRadius borderRadius, ) { - return Material( - clipBehavior: Clip.antiAlias, - shape: attachmentShape, - type: MaterialType.transparency, - child: Transform( - transform: Matrix4.rotationY(reverse ? pi : 0), - alignment: Alignment.center, - child: attachmentWidget, + return ClipRRect( + borderRadius: borderRadius, + child: Material( + clipBehavior: Clip.antiAlias, + shape: attachmentShape, + type: MaterialType.transparency, + child: Transform( + transform: Matrix4.rotationY(reverse ? pi : 0), + alignment: Alignment.center, + child: attachmentWidget, + ), ), ); } diff --git a/packages/stream_chat_flutter/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml index 4d480154..93c6e4d1 100644 --- a/packages/stream_chat_flutter/pubspec.yaml +++ b/packages/stream_chat_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat_flutter homepage: https://github.com/GetStream/stream-chat-flutter description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter. -version: 1.4.0-beta +version: 1.5.1 repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues @@ -11,11 +11,7 @@ environment: dependencies: flutter: sdk: flutter - stream_chat_flutter_core: - git: - url: https://github.com/GetStream/stream-chat-flutter.git - ref: develop - path: packages/stream_chat_flutter_core + stream_chat_flutter_core: ^1.5.0 photo_view: ^0.11.0 rxdart: ^0.25.0 scrollable_positioned_list: ^0.1.8 @@ -34,16 +30,13 @@ dependencies: flutter_keyboard_visibility: ^4.0.2 video_compress: ^2.1.1 visibility_detector: ^0.1.5 - http_parser: ^3.1.4 meta: ^1.2.4 lottie: ^0.7.0+1 substring_highlight: ^0.1.2 flutter_slidable: ^0.5.7 - clipboard: ^0.1.2+8 image_gallery_saver: ^1.6.7 share_plus: ^1.2.0 photo_manager: ^1.0.0 - transparent_image: ^1.0.0 ezanimation: ^0.4.1 synchronized: ^2.1.0 characters: ^1.0.0 diff --git a/packages/stream_chat_flutter_core/CHANGELOG.md b/packages/stream_chat_flutter_core/CHANGELOG.md index 0bad0c4e..ac1fc93c 100644 --- a/packages/stream_chat_flutter_core/CHANGELOG.md +++ b/packages/stream_chat_flutter_core/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.5.0 + +* Minor fixes and improvements + ## 1.4.0-beta * Added `MessageListCore.messageFilter` to filter messages locally diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index 93547384..cc36f149 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat_flutter_core homepage: https://github.com/GetStream/stream-chat-flutter description: Stream Chat official Flutter SDK Core. Build your own chat experience using Dart and Flutter. -version: 1.4.0-beta +version: 1.5.0 repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues @@ -10,11 +10,7 @@ environment: flutter: ">=1.17.0" dependencies: - stream_chat: - git: - url: https://github.com/GetStream/stream-chat-flutter.git - ref: develop - path: packages/stream_chat + stream_chat: ^1.5.0 flutter: sdk: flutter rxdart: ^0.25.0 @@ -24,5 +20,4 @@ dev_dependencies: flutter_test: sdk: flutter fake_async: ^1.1.0 - pedantic: ^1.9.2 \ No newline at end of file diff --git a/packages/stream_chat_persistence/CHANGELOG.md b/packages/stream_chat_persistence/CHANGELOG.md index 161f2d59..9c844ee3 100644 --- a/packages/stream_chat_persistence/CHANGELOG.md +++ b/packages/stream_chat_persistence/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.5.0 + +* Update llc dependency +* Wait for all operations to finish before disconnecting + ## 1.4.0-beta * Update llc dependency diff --git a/packages/stream_chat_persistence/analysis_options.yaml b/packages/stream_chat_persistence/analysis_options.yaml index 7e4b00fa..26001160 100644 --- a/packages/stream_chat_persistence/analysis_options.yaml +++ b/packages/stream_chat_persistence/analysis_options.yaml @@ -44,7 +44,6 @@ linter: - avoid_private_typedef_functions - avoid_redundant_argument_values - avoid_return_types_on_setters - - avoid_returning_null - avoid_returning_null_for_void - avoid_shadowing_type_parameters - avoid_single_cascade_in_expression_statements diff --git a/packages/stream_chat_persistence/lib/src/entity/channels.dart b/packages/stream_chat_persistence/lib/src/entity/channels.dart index 89842036..6f60fac3 100644 --- a/packages/stream_chat_persistence/lib/src/entity/channels.dart +++ b/packages/stream_chat_persistence/lib/src/entity/channels.dart @@ -18,7 +18,7 @@ class Channels extends Table { TextColumn get config => text().map(MapConverter())(); /// True if this channel entity is frozen - BoolColumn get frozen => boolean().withDefault(Constant(false))(); + BoolColumn get frozen => boolean().withDefault(const Constant(false))(); /// The date of the last message DateTimeColumn get lastMessageAt => dateTime().nullable()(); diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index 5328e1a2..f458bfe1 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_chat_persistence homepage: https://github.com/GetStream/stream-chat-flutter description: Official Stream Chat Persistence library. Build your own chat experience using Dart and Flutter. -version: 1.4.0-beta +version: 1.5.0 repository: https://github.com/GetStream/stream-chat-flutter issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues @@ -11,16 +11,14 @@ environment: dependencies: flutter: sdk: flutter - mutex: ^2.0.0 + logging: ^0.11.4 + meta: ^1.2.4 moor: ^3.4.0 + mutex: ^2.0.0 path: ^1.7.0 path_provider: ^1.6.27 sqlite3_flutter_libs: ^0.4.0+1 - stream_chat: - git: - url: https://github.com/GetStream/stream-chat-flutter.git - ref: develop - path: packages/stream_chat + stream_chat: ^1.5.0 dependency_overrides: stream_chat: