Merge branches 'develop' and 'persistence/add-tests' of https://github.com/GetStream/stream-chat-flutter into persistence/add-tests

 Conflicts:
	packages/stream_chat_persistence/analysis_options.yaml
	packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart
	packages/stream_chat_persistence/lib/src/dao/message_dao.dart
	packages/stream_chat_persistence/lib/src/dao/user_dao.dart
	packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart
	packages/stream_chat_persistence/lib/src/db/shared/native_db.dart
	packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart
	packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart
	packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart
	packages/stream_chat_persistence/pubspec.yaml
This commit is contained in:
Sahil Kumar
2021-03-19 18:26:31 +05:30
26 changed files with 263 additions and 159 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
repo: GetStream/flutter-samples repo: GetStream/flutter-samples
token: ${{ secrets.GH_TOKEN }} token: ${{ secrets.GH_TOKEN }}
dispatch_stable: dispatch_stable:
if: github.ref == 'refs/heads/master' if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: benc-uk/workflow-dispatch@v1 - uses: benc-uk/workflow-dispatch@v1
+2
View File
@@ -5,6 +5,8 @@ on:
- opened - opened
- edited - edited
- synchronize - synchronize
branches:
- develop
jobs: jobs:
main: main:
@@ -8,12 +8,12 @@ on:
push: push:
branches: branches:
- master - master
- develop
paths-ignore: paths-ignore:
- 'docs/**' - 'docs/**'
jobs: jobs:
analyze: analyze:
if: github.base_ref == 'master'
timeout-minutes: 15 timeout-minutes: 15
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
+5
View File
@@ -20,6 +20,11 @@ Stream allows developers to rapidly deploy scalable feeds and chat messaging wit
## Sample apps and demos ## 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). 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 ## 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`. 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`.
+4
View File
@@ -1,3 +1,7 @@
## 1.5.0
- Minor fixes and improvements
## 1.4.0-beta ## 1.4.0-beta
- Improved attachment uploading - Improved attachment uploading
@@ -44,7 +44,6 @@ linter:
- avoid_private_typedef_functions - avoid_private_typedef_functions
- avoid_redundant_argument_values - avoid_redundant_argument_values
- avoid_return_types_on_setters - avoid_return_types_on_setters
- avoid_returning_null
- avoid_returning_null_for_void - avoid_returning_null_for_void
- avoid_shadowing_type_parameters - avoid_shadowing_type_parameters
- avoid_single_cascade_in_expression_statements - avoid_single_cascade_in_expression_statements
@@ -1209,6 +1209,7 @@ class ChannelClientState {
ChannelClientState( ChannelClientState(
this._channel, this._channel,
ChannelState channelState, ChannelState channelState,
//ignore: unnecessary_parenthesis
) : _debouncedUpdatePersistenceChannelState = ((ChannelState state) { ) : _debouncedUpdatePersistenceChannelState = ((ChannelState state) {
_channel?._client?.chatPersistenceClient?.updateChannelState(state); _channel?._client?.chatPersistenceClient?.updateChannelState(state);
}).debounced(const Duration(seconds: 1)) { }).debounced(const Duration(seconds: 1)) {
+1 -1
View File
@@ -3,4 +3,4 @@ import 'package:stream_chat/src/client.dart';
/// Current package version /// Current package version
/// Used in [StreamChatClient] to build the `x-stream-client` header /// Used in [StreamChatClient] to build the `x-stream-client` header
// ignore: constant_identifier_names // ignore: constant_identifier_names
const PACKAGE_VERSION = '1.4.0-beta'; const PACKAGE_VERSION = '1.5.0';
+1 -1
View File
@@ -1,7 +1,7 @@
name: stream_chat name: stream_chat
homepage: https://getstream.io/ homepage: https://getstream.io/
description: The official Dart client for Stream Chat, a service for building chat applications. 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 repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
+13 -1
View File
@@ -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 ## 1.4.0-beta
- Unfocus `MessageInput` only when sending commands - Unfocus `MessageInput` only when sending commands
@@ -10,7 +22,7 @@
- Added `MessageListView.onAttachmentTap` callback - Added `MessageListView.onAttachmentTap` callback
- Fixed message newline issue - Fixed message newline issue
- Fixed `MessageListView` scroll keyboard behaviour - Fixed `MessageListView` scroll keyboard behaviour
- Minor fixes and improveqments - Minor fixes and improvements
## 1.3.2-beta ## 1.3.2-beta
@@ -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/utils.dart';
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart'; import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.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 '../upload_progress_indicator.dart';
import 'attachment_widget.dart'; import 'attachment_widget.dart';
@@ -1,10 +1,7 @@
import 'dart:typed_data';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shimmer/shimmer.dart'; import 'package:shimmer/shimmer.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.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 '../full_screen_media.dart';
import '../stream_chat_theme.dart'; import '../stream_chat_theme.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/src/attachment/attachment_upload_state_builder.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'attachment_title.dart';
import '../full_screen_media.dart'; import '../full_screen_media.dart';
import '../stream_chat_theme.dart'; import '../stream_chat_theme.dart';
import 'attachment_title.dart';
import 'attachment_widget.dart'; import 'attachment_widget.dart';
class ImageAttachment extends AttachmentWidget { class ImageAttachment extends AttachmentWidget {
@@ -81,6 +81,7 @@ class ImageAttachment extends AttachmentWidget {
return _buildImageAttachment( return _buildImageAttachment(
context, context,
CachedNetworkImage( CachedNetworkImage(
cacheKey: imageUri.path,
height: size?.height, height: size?.height,
width: size?.width, width: size?.width,
placeholder: (_, __) { placeholder: (_, __) {
@@ -5,10 +5,10 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:stream_chat_flutter/src/message_action.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/reaction_picker.dart';
import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/src/utils.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'extension.dart'; import 'extension.dart';
import 'message_input.dart'; import 'message_input.dart';
@@ -34,6 +34,7 @@ class MessageActionsModal extends StatefulWidget {
final ShapeBorder messageShape; final ShapeBorder messageShape;
final ShapeBorder attachmentShape; final ShapeBorder attachmentShape;
final DisplayWidget showUserAvatar; final DisplayWidget showUserAvatar;
final BorderRadius attachmentBorderRadiusGeometry;
/// List of custom actions /// List of custom actions
final List<MessageAction> customActions; final List<MessageAction> customActions;
@@ -58,6 +59,7 @@ class MessageActionsModal extends StatefulWidget {
this.attachmentShape, this.attachmentShape,
this.reverse = false, this.reverse = false,
this.customActions = const [], this.customActions = const [],
this.attachmentBorderRadiusGeometry,
}) : super(key: key); }) : super(key: key);
@override @override
@@ -153,6 +155,8 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
child: MessageWidget( child: MessageWidget(
key: Key('MessageWidget'), key: Key('MessageWidget'),
reverse: widget.reverse, reverse: widget.reverse,
attachmentBorderRadiusGeometry:
widget.attachmentBorderRadiusGeometry,
message: widget.message.copyWith( message: widget.message.copyWith(
text: widget.message.text.length > 200 text: widget.message.text.length > 200
? '${widget.message.text.substring(0, 200)}...' ? '${widget.message.text.substring(0, 200)}...'
@@ -12,12 +12,12 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:photo_manager/photo_manager.dart'; import 'package:photo_manager/photo_manager.dart';
import 'package:shimmer/shimmer.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/media_list_view.dart';
import 'package:stream_chat_flutter/src/message_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_chat_theme.dart';
import 'package:stream_chat_flutter/src/stream_svg_icon.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/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:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:substring_highlight/substring_highlight.dart'; import 'package:substring_highlight/substring_highlight.dart';
@@ -35,6 +35,8 @@ typedef AttachmentThumbnailBuilder = Widget Function(
enum ActionsLocation { enum ActionsLocation {
left, left,
right, right,
leftInside,
rightInside,
} }
enum DefaultAttachmentTypes { enum DefaultAttachmentTypes {
@@ -122,6 +124,7 @@ class MessageInput extends StatefulWidget {
this.hideSendAsDm = false, this.hideSendAsDm = false,
this.idleSendButton, this.idleSendButton,
this.activeSendButton, this.activeSendButton,
this.showCommandsButton = true,
}) : super(key: key); }) : super(key: key);
/// Message to edit /// Message to edit
@@ -149,6 +152,9 @@ class MessageInput extends StatefulWidget {
/// If true the attachments button will not be displayed /// If true the attachments button will not be displayed
final bool disableAttachments; final bool disableAttachments;
/// Use this property to hide/show the commands button
final bool showCommandsButton;
/// Hide send as dm checkbox /// Hide send as dm checkbox
final bool hideSendAsDm; final bool hideSendAsDm;
@@ -308,7 +314,7 @@ class MessageInputState extends State<MessageInput> {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.symmetric(vertical: 8.0),
child: _buildTextField(context), child: _buildTextField(context),
), ),
if (widget.parentMessage != null && !widget.hideSendAsDm) if (widget.parentMessage != null && !widget.hideSendAsDm)
@@ -336,12 +342,11 @@ class MessageInputState extends State<MessageInput> {
direction: Axis.horizontal, direction: Axis.horizontal,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
if (!_commandEnabled) _buildExpandActionsButton(), if (!_commandEnabled && widget.actionsLocation == ActionsLocation.left)
if (widget.actionsLocation == ActionsLocation.left) _buildExpandActionsButton(),
...widget.actions ?? [],
_buildTextInput(context), _buildTextInput(context),
if (widget.actionsLocation == ActionsLocation.right) if (!_commandEnabled && widget.actionsLocation == ActionsLocation.right)
...widget.actions ?? [], _buildExpandActionsButton(),
if (widget.sendButtonLocation == SendButtonLocation.outside) if (widget.sendButtonLocation == SendButtonLocation.outside)
_animateSendButton(context), _animateSendButton(context),
], ],
@@ -421,32 +426,36 @@ class MessageInputState extends State<MessageInput> {
child: widget.activeSendButton, child: widget.activeSendButton,
) )
: _buildSendButton(context); : _buildSendButton(context);
return Padding( return AnimatedCrossFade(
padding: const EdgeInsets.all(8.0), crossFadeState: (_messageIsPresent || _attachments.isNotEmpty)
child: AnimatedCrossFade( ? CrossFadeState.showFirst
crossFadeState: (_messageIsPresent || _attachments.isNotEmpty) : CrossFadeState.showSecond,
? CrossFadeState.showFirst firstChild: sendButton,
: CrossFadeState.showSecond, secondChild: widget.idleSendButton ?? _buildIdleSendButton(context),
firstChild: sendButton, duration:
secondChild: widget.idleSendButton ?? _buildIdleSendButton(context), StreamChatTheme.of(context).messageInputTheme.sendAnimationDuration,
duration: alignment: Alignment.center,
StreamChatTheme.of(context).messageInputTheme.sendAnimationDuration,
alignment: Alignment.center,
),
); );
} }
Widget _buildExpandActionsButton() { Widget _buildExpandActionsButton() {
return Padding( return Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: AnimatedCrossFade( child: AnimatedCrossFade(
crossFadeState: _actionsShrunk crossFadeState: _actionsShrunk
? CrossFadeState.showFirst ? CrossFadeState.showFirst
: CrossFadeState.showSecond, : CrossFadeState.showSecond,
firstChild: IconButton( firstChild: IconButton(
onPressed: () => setState(() => _actionsShrunk = false), onPressed: () => setState(() => _actionsShrunk = false),
icon: StreamSvgIcon.emptyCircleLeft( icon: Transform.rotate(
color: StreamChatTheme.of(context).colorTheme.accentBlue, 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), padding: const EdgeInsets.all(0),
constraints: BoxConstraints.tightFor( constraints: BoxConstraints.tightFor(
@@ -457,10 +466,12 @@ class MessageInputState extends State<MessageInput> {
), ),
secondChild: FittedBox( secondChild: FittedBox(
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: <Widget>[
if (!widget.disableAttachments) _buildAttachmentButton(), if (!widget.disableAttachments) _buildAttachmentButton(),
if (widget.editMessage == null && if (widget.showCommandsButton &&
widget.editMessage == null &&
StreamChannel.of(context) StreamChannel.of(context)
.channel .channel
?.config ?.config
@@ -468,6 +479,7 @@ class MessageInputState extends State<MessageInput> {
?.isNotEmpty == ?.isNotEmpty ==
true) true)
_buildCommandButton(), _buildCommandButton(),
...widget.actions ?? [],
].insertBetween(const SizedBox(width: 8)), ].insertBetween(const SizedBox(width: 8)),
), ),
), ),
@@ -565,51 +577,75 @@ class MessageInputState extends State<MessageInput> {
), ),
), ),
contentPadding: const EdgeInsets.fromLTRB(16, 12, 13, 11), contentPadding: const EdgeInsets.fromLTRB(16, 12, 13, 11),
prefixIconConstraints: BoxConstraints.tight(Size(78, 24)),
suffixIconConstraints: BoxConstraints.tight(Size(40, 40)),
prefixIcon: _commandEnabled prefixIcon: _commandEnabled
? Container( ? Row(
decoration: BoxDecoration( mainAxisSize: MainAxisSize.min,
borderRadius: BorderRadius.circular(12), children: [
color: theme.colorTheme.accentBlue, Padding(
), padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.only(right: 4, left: 8), child: Container(
alignment: Alignment.center, constraints: BoxConstraints.tight(Size(64, 24)),
child: Row( decoration: BoxDecoration(
mainAxisSize: MainAxisSize.min, borderRadius: BorderRadius.circular(12),
children: [ color: theme.colorTheme.accentBlue,
StreamSvgIcon.lightning( ),
color: Colors.white, alignment: Alignment.center,
size: 16.0, child: Row(
), mainAxisSize: MainAxisSize.min,
Text( children: [
_chosenCommand?.name?.toUpperCase() ?? '', StreamSvgIcon.lightning(
style: StreamChatTheme.of(context)
.textTheme
.footnoteBold
.copyWith(
color: Colors.white, 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( suffixIcon: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
if (_commandEnabled) if (_commandEnabled)
IconButton( Padding(
icon: StreamSvgIcon.closeSmall(), padding: const EdgeInsets.only(right: 8.0),
splashRadius: 24, child: IconButton(
padding: const EdgeInsets.all(0), icon: StreamSvgIcon.closeSmall(),
constraints: BoxConstraints.tightFor( splashRadius: 24,
height: 24, padding: const EdgeInsets.all(0),
width: 24, 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) if (widget.sendButtonLocation == SendButtonLocation.inside)
_animateSendButton(context), _animateSendButton(context),
], ],
@@ -619,7 +655,13 @@ class MessageInputState extends State<MessageInput> {
Timer _debounce; Timer _debounce;
String _previousValue;
void _onChanged(BuildContext context, String s) { void _onChanged(BuildContext context, String s) {
if (s == _previousValue) {
return;
}
_previousValue = s;
if (_debounce?.isActive == true) _debounce.cancel(); if (_debounce?.isActive == true) _debounce.cancel();
_debounce = Timer( _debounce = Timer(
const Duration(milliseconds: 350), const Duration(milliseconds: 350),
@@ -631,7 +673,11 @@ class MessageInputState extends State<MessageInput> {
setState(() { setState(() {
_messageIsPresent = s.trim().isNotEmpty; _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(); _commandsOverlay?.remove();
@@ -1684,13 +1730,19 @@ class MessageInputState extends State<MessageInput> {
} }
Widget _buildCommandButton() { Widget _buildCommandButton() {
final s = textEditingController.text.trim();
return IconButton( return IconButton(
icon: StreamSvgIcon.lightning( icon: StreamSvgIcon.lightning(
color: _commandsOverlay != null color: s.isNotEmpty
? StreamChatTheme.of(context).messageInputTheme.actionButtonColor ? StreamChatTheme.of(context).colorTheme.greyGainsboro
: StreamChatTheme.of(context) : (_commandsOverlay != null
.messageInputTheme ? StreamChatTheme.of(context)
.actionButtonIdleColor, .messageInputTheme
.actionButtonColor
: StreamChatTheme.of(context)
.messageInputTheme
.actionButtonIdleColor),
), ),
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
constraints: BoxConstraints.tightFor( constraints: BoxConstraints.tightFor(
@@ -1711,7 +1763,9 @@ class MessageInputState extends State<MessageInput> {
if (_commandsOverlay == null) { if (_commandsOverlay == null) {
setState(() { setState(() {
_commandsOverlay = _buildCommandsOverlayEntry(); _commandsOverlay = _buildCommandsOverlayEntry();
Overlay.of(context).insert(_commandsOverlay); if (_commandsOverlay != null) {
Overlay.of(context).insert(_commandsOverlay);
}
}); });
} else { } else {
setState(() { setState(() {
@@ -1904,11 +1958,11 @@ class MessageInputState extends State<MessageInput> {
if (file == null) return; if (file == null) return;
final mimeType = file.name?.mimeType; final mimeType = file.name?.mimeType ?? file.path.split('/').last.mimeType;
final extraDataMap = <String, dynamic>{}; final extraDataMap = <String, dynamic>{};
if (mimeType.type == 'video' || mimeType.type == 'image') { if (mimeType?.type == 'video' || mimeType?.type == 'image') {
attachmentType = mimeType.type; attachmentType = mimeType.type;
} else { } else {
attachmentType = 'file'; attachmentType = 'file';
@@ -1965,24 +2019,31 @@ class MessageInputState extends State<MessageInput> {
} }
Widget _buildIdleSendButton(BuildContext context) { Widget _buildIdleSendButton(BuildContext context) {
return StreamSvgIcon( return Padding(
assetName: _getIdleSendIcon(), padding: const EdgeInsets.all(8.0),
color: StreamChatTheme.of(context).messageInputTheme.sendButtonIdleColor, child: StreamSvgIcon(
assetName: _getIdleSendIcon(),
color:
StreamChatTheme.of(context).messageInputTheme.sendButtonIdleColor,
),
); );
} }
Widget _buildSendButton(BuildContext context) { Widget _buildSendButton(BuildContext context) {
return IconButton( return Padding(
onPressed: sendMessage, padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(0), child: IconButton(
splashRadius: 24, onPressed: sendMessage,
constraints: BoxConstraints.tightFor( padding: const EdgeInsets.all(0),
height: 24, splashRadius: 24,
width: 24, constraints: BoxConstraints.tightFor(
), height: 24,
icon: StreamSvgIcon( width: 24,
assetName: _getSendIcon(), ),
color: StreamChatTheme.of(context).messageInputTheme.sendButtonColor, icon: StreamSvgIcon(
assetName: _getSendIcon(),
color: StreamChatTheme.of(context).messageInputTheme.sendButtonColor,
),
), ),
); );
} }
@@ -749,7 +749,7 @@ class _MessageListViewState extends State<MessageListView> {
Widget messageWidget; Widget messageWidget;
if (widget.messageBuilder != null) { if (widget.messageBuilder != null) {
messageWidget = Builder( messageWidget = Builder(
key: ValueKey<String>('BOTTOM-MESSAGE'), key: ValueKey<String>('BOTTOM-MESSAGE-${message.id}'),
builder: (_) => widget.messageBuilder( builder: (_) => widget.messageBuilder(
context, context,
MessageDetails( MessageDetails(
@@ -766,7 +766,7 @@ class _MessageListViewState extends State<MessageListView> {
} }
return VisibilityDetector( return VisibilityDetector(
key: ValueKey<String>('BOTTOM-MESSAGE'), key: ValueKey<String>('BOTTOM-MESSAGE-${message.id}'),
onVisibilityChanged: (visibility) { onVisibilityChanged: (visibility) {
final isVisible = visibility.visibleBounds != Rect.zero; final isVisible = visibility.visibleBounds != Rect.zero;
if (isVisible) { if (isVisible) {
@@ -1021,15 +1021,19 @@ class _MessageListViewState extends State<MessageListView> {
!message.isSystem && !message.isSystem &&
!message.isEphemeral && !message.isEphemeral &&
widget.onMessageSwiped != null) { widget.onMessageSwiped != null) {
child = Swipeable( child = Container(
onSwipeEnd: () { decoration: BoxDecoration(),
FocusScope.of(context).unfocus(); clipBehavior: Clip.hardEdge,
widget.onMessageSwiped(message); child: Swipeable(
}, onSwipeEnd: () {
backgroundIcon: StreamSvgIcon.reply( FocusScope.of(context).unfocus();
color: StreamChatTheme.of(context).colorTheme.accentBlue, widget.onMessageSwiped(message);
},
backgroundIcon: StreamSvgIcon.reply(
color: StreamChatTheme.of(context).colorTheme.accentBlue,
),
child: child,
), ),
child: Container(child: child),
); );
} }
@@ -1,17 +1,16 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; 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_bubble.dart';
import 'package:stream_chat_flutter/src/reaction_picker.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/stream_chat.dart';
import 'package:stream_chat_flutter/src/user_avatar.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 'message_widget.dart';
import 'stream_chat_theme.dart'; import 'stream_chat_theme.dart';
import 'extension.dart';
class MessageReactionsModal extends StatelessWidget { class MessageReactionsModal extends StatelessWidget {
final Widget Function(BuildContext, Message) editMessageInputBuilder; final Widget Function(BuildContext, Message) editMessageInputBuilder;
@@ -24,6 +23,7 @@ class MessageReactionsModal extends StatelessWidget {
final ShapeBorder messageShape; final ShapeBorder messageShape;
final ShapeBorder attachmentShape; final ShapeBorder attachmentShape;
final void Function(User) onUserAvatarTap; final void Function(User) onUserAvatarTap;
final BorderRadius attachmentBorderRadiusGeometry;
const MessageReactionsModal({ const MessageReactionsModal({
Key key, Key key,
@@ -37,6 +37,7 @@ class MessageReactionsModal extends StatelessWidget {
this.reverse = false, this.reverse = false,
this.showUserAvatar = DisplayWidget.show, this.showUserAvatar = DisplayWidget.show,
this.onUserAvatarTap, this.onUserAvatarTap,
this.attachmentBorderRadiusGeometry,
}) : super(key: key); }) : super(key: key);
@override @override
@@ -133,6 +134,8 @@ class MessageReactionsModal extends StatelessWidget {
shape: messageShape, shape: messageShape,
attachmentShape: attachmentShape, attachmentShape: attachmentShape,
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
attachmentBorderRadiusGeometry:
attachmentBorderRadiusGeometry,
attachmentPadding: EdgeInsets.all( attachmentPadding: EdgeInsets.all(
hasFileAttachment ? 4 : 2, hasFileAttachment ? 4 : 2,
), ),
@@ -235,6 +235,7 @@ class MessageWidget extends StatefulWidget {
), ),
border, border,
reverse, reverse,
attachmentBorderRadiusGeometry ?? BorderRadius.zero,
), ),
); );
} }
@@ -259,6 +260,7 @@ class MessageWidget extends StatefulWidget {
), ),
border, border,
reverse, reverse,
attachmentBorderRadiusGeometry ?? BorderRadius.zero,
); );
}, },
'video': (context, message, attachments) { 'video': (context, message, attachments) {
@@ -291,6 +293,7 @@ class MessageWidget extends StatefulWidget {
), ),
border, border,
reverse, reverse,
attachmentBorderRadiusGeometry ?? BorderRadius.zero,
); );
}, },
'giphy': (context, message, attachments) { 'giphy': (context, message, attachments) {
@@ -318,6 +321,7 @@ class MessageWidget extends StatefulWidget {
), ),
border, border,
reverse, reverse,
attachmentBorderRadiusGeometry ?? BorderRadius.zero,
); );
}, },
'file': (context, message, attachments) { 'file': (context, message, attachments) {
@@ -329,22 +333,28 @@ class MessageWidget extends StatefulWidget {
borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero, borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero,
); );
return wrapAttachmentWidget( return Column(
context, children: attachments
Column( .map<Widget>((attachment) {
children: attachments.map((attachment) { return wrapAttachmentWidget(
return FileAttachment( context,
message: message, FileAttachment(
attachment: attachment, message: message,
size: Size( attachment: attachment,
MediaQuery.of(context).size.width * 0.8, size: Size(
MediaQuery.of(context).size.height * 0.3, MediaQuery.of(context).size.width * 0.8,
), MediaQuery.of(context).size.height * 0.3,
); ),
}).toList(), ),
), border,
border, reverse,
reverse, attachmentBorderRadiusGeometry ?? BorderRadius.zero,
);
})
.insertBetween(SizedBox(
height: attachmentPadding.vertical / 2,
))
.toList(),
); );
}, },
}..addAll(customAttachmentBuilders ?? {}), }..addAll(customAttachmentBuilders ?? {}),
@@ -822,6 +832,8 @@ class _MessageWidgetState extends State<MessageWidget>
return StreamChannel( return StreamChannel(
channel: channel, channel: channel,
child: MessageActionsModal( child: MessageActionsModal(
attachmentBorderRadiusGeometry:
widget.attachmentBorderRadiusGeometry,
showUserAvatar: showUserAvatar:
widget.message.user.id == channel.client.state.user.id widget.message.user.id == channel.client.state.user.id
? DisplayWidget.gone ? DisplayWidget.gone
@@ -869,6 +881,8 @@ class _MessageWidgetState extends State<MessageWidget>
return StreamChannel( return StreamChannel(
channel: channel, channel: channel,
child: MessageReactionsModal( child: MessageReactionsModal(
attachmentBorderRadiusGeometry:
widget.attachmentBorderRadiusGeometry,
showUserAvatar: showUserAvatar:
widget.message.user.id == channel.client.state.user.id widget.message.user.id == channel.client.state.user.id
? DisplayWidget.gone ? DisplayWidget.gone
@@ -913,7 +927,7 @@ class _MessageWidgetState extends State<MessageWidget>
} }
Widget _parseAttachments() { Widget _parseAttachments() {
Map<String, List<Attachment>> attachmentGroups = {}; final attachmentGroups = <String, List<Attachment>>{};
widget.message.attachments widget.message.attachments
.where((element) => element.ogScrapeUrl == null) .where((element) => element.ogScrapeUrl == null)
@@ -925,7 +939,7 @@ class _MessageWidgetState extends State<MessageWidget>
attachmentGroups[e.type].add(e); attachmentGroups[e.type].add(e);
}); });
List<Widget> attachmentList = []; final attachmentList = <Widget>[];
attachmentGroups.forEach((type, attachments) { attachmentGroups.forEach((type, attachments) {
final attachmentBuilder = widget.attachmentBuilders[type]; final attachmentBuilder = widget.attachmentBuilders[type];
@@ -356,15 +356,19 @@ Widget wrapAttachmentWidget(
Widget attachmentWidget, Widget attachmentWidget,
ShapeBorder attachmentShape, ShapeBorder attachmentShape,
bool reverse, bool reverse,
BorderRadius borderRadius,
) { ) {
return Material( return ClipRRect(
clipBehavior: Clip.antiAlias, borderRadius: borderRadius,
shape: attachmentShape, child: Material(
type: MaterialType.transparency, clipBehavior: Clip.antiAlias,
child: Transform( shape: attachmentShape,
transform: Matrix4.rotationY(reverse ? pi : 0), type: MaterialType.transparency,
alignment: Alignment.center, child: Transform(
child: attachmentWidget, transform: Matrix4.rotationY(reverse ? pi : 0),
alignment: Alignment.center,
child: attachmentWidget,
),
), ),
); );
} }
+2 -9
View File
@@ -1,7 +1,7 @@
name: stream_chat_flutter name: stream_chat_flutter
homepage: https://github.com/GetStream/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. 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 repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -11,11 +11,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
stream_chat_flutter_core: stream_chat_flutter_core: ^1.5.0
git:
url: https://github.com/GetStream/stream-chat-flutter.git
ref: develop
path: packages/stream_chat_flutter_core
photo_view: ^0.11.0 photo_view: ^0.11.0
rxdart: ^0.25.0 rxdart: ^0.25.0
scrollable_positioned_list: ^0.1.8 scrollable_positioned_list: ^0.1.8
@@ -34,16 +30,13 @@ dependencies:
flutter_keyboard_visibility: ^4.0.2 flutter_keyboard_visibility: ^4.0.2
video_compress: ^2.1.1 video_compress: ^2.1.1
visibility_detector: ^0.1.5 visibility_detector: ^0.1.5
http_parser: ^3.1.4
meta: ^1.2.4 meta: ^1.2.4
lottie: ^0.7.0+1 lottie: ^0.7.0+1
substring_highlight: ^0.1.2 substring_highlight: ^0.1.2
flutter_slidable: ^0.5.7 flutter_slidable: ^0.5.7
clipboard: ^0.1.2+8
image_gallery_saver: ^1.6.7 image_gallery_saver: ^1.6.7
share_plus: ^1.2.0 share_plus: ^1.2.0
photo_manager: ^1.0.0 photo_manager: ^1.0.0
transparent_image: ^1.0.0
ezanimation: ^0.4.1 ezanimation: ^0.4.1
synchronized: ^2.1.0 synchronized: ^2.1.0
characters: ^1.0.0 characters: ^1.0.0
@@ -1,3 +1,7 @@
## 1.5.0
* Minor fixes and improvements
## 1.4.0-beta ## 1.4.0-beta
* Added `MessageListCore.messageFilter` to filter messages locally * Added `MessageListCore.messageFilter` to filter messages locally
@@ -1,7 +1,7 @@
name: stream_chat_flutter_core name: stream_chat_flutter_core
homepage: https://github.com/GetStream/stream-chat-flutter homepage: https://github.com/GetStream/stream-chat-flutter
description: Stream Chat official Flutter SDK Core. Build your own chat experience using Dart and 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 repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -10,11 +10,7 @@ environment:
flutter: ">=1.17.0" flutter: ">=1.17.0"
dependencies: dependencies:
stream_chat: stream_chat: ^1.5.0
git:
url: https://github.com/GetStream/stream-chat-flutter.git
ref: develop
path: packages/stream_chat
flutter: flutter:
sdk: flutter sdk: flutter
rxdart: ^0.25.0 rxdart: ^0.25.0
@@ -24,5 +20,4 @@ dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
fake_async: ^1.1.0 fake_async: ^1.1.0
pedantic: ^1.9.2
@@ -1,3 +1,8 @@
## 1.5.0
* Update llc dependency
* Wait for all operations to finish before disconnecting
## 1.4.0-beta ## 1.4.0-beta
* Update llc dependency * Update llc dependency
@@ -44,7 +44,6 @@ linter:
- avoid_private_typedef_functions - avoid_private_typedef_functions
- avoid_redundant_argument_values - avoid_redundant_argument_values
- avoid_return_types_on_setters - avoid_return_types_on_setters
- avoid_returning_null
- avoid_returning_null_for_void - avoid_returning_null_for_void
- avoid_shadowing_type_parameters - avoid_shadowing_type_parameters
- avoid_single_cascade_in_expression_statements - avoid_single_cascade_in_expression_statements
@@ -18,7 +18,7 @@ class Channels extends Table {
TextColumn get config => text().map(MapConverter<Object>())(); TextColumn get config => text().map(MapConverter<Object>())();
/// True if this channel entity is frozen /// 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 /// The date of the last message
DateTimeColumn get lastMessageAt => dateTime().nullable()(); DateTimeColumn get lastMessageAt => dateTime().nullable()();
@@ -1,7 +1,7 @@
name: stream_chat_persistence name: stream_chat_persistence
homepage: https://github.com/GetStream/stream-chat-flutter homepage: https://github.com/GetStream/stream-chat-flutter
description: Official Stream Chat Persistence library. Build your own chat experience using Dart and 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 repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -11,16 +11,14 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
mutex: ^2.0.0 logging: ^0.11.4
meta: ^1.2.4
moor: ^3.4.0 moor: ^3.4.0
mutex: ^2.0.0
path: ^1.7.0 path: ^1.7.0
path_provider: ^1.6.27 path_provider: ^1.6.27
sqlite3_flutter_libs: ^0.4.0+1 sqlite3_flutter_libs: ^0.4.0+1
stream_chat: stream_chat: ^1.5.0
git:
url: https://github.com/GetStream/stream-chat-flutter.git
ref: develop
path: packages/stream_chat
dependency_overrides: dependency_overrides:
stream_chat: stream_chat: