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:
@@ -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
|
||||
|
||||
@@ -5,6 +5,8 @@ on:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
branches:
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
main:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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`.
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.5.0
|
||||
|
||||
- Minor fixes and improvements
|
||||
|
||||
## 1.4.0-beta
|
||||
|
||||
- Improved attachment uploading
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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: (_, __) {
|
||||
|
||||
@@ -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<MessageAction> 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<MessageActionsModal> {
|
||||
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)}...'
|
||||
|
||||
@@ -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<MessageInput> {
|
||||
),
|
||||
),
|
||||
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<MessageInput> {
|
||||
direction: Axis.horizontal,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
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<MessageInput> {
|
||||
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<MessageInput> {
|
||||
),
|
||||
secondChild: FittedBox(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
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<MessageInput> {
|
||||
?.isNotEmpty ==
|
||||
true)
|
||||
_buildCommandButton(),
|
||||
...widget.actions ?? [],
|
||||
].insertBetween(const SizedBox(width: 8)),
|
||||
),
|
||||
),
|
||||
@@ -565,51 +577,75 @@ class MessageInputState extends State<MessageInput> {
|
||||
),
|
||||
),
|
||||
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<MessageInput> {
|
||||
|
||||
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<MessageInput> {
|
||||
|
||||
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<MessageInput> {
|
||||
}
|
||||
|
||||
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<MessageInput> {
|
||||
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<MessageInput> {
|
||||
|
||||
if (file == null) return;
|
||||
|
||||
final mimeType = file.name?.mimeType;
|
||||
final mimeType = file.name?.mimeType ?? file.path.split('/').last.mimeType;
|
||||
|
||||
final extraDataMap = <String, dynamic>{};
|
||||
|
||||
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<MessageInput> {
|
||||
}
|
||||
|
||||
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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -749,7 +749,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
Widget messageWidget;
|
||||
if (widget.messageBuilder != null) {
|
||||
messageWidget = Builder(
|
||||
key: ValueKey<String>('BOTTOM-MESSAGE'),
|
||||
key: ValueKey<String>('BOTTOM-MESSAGE-${message.id}'),
|
||||
builder: (_) => widget.messageBuilder(
|
||||
context,
|
||||
MessageDetails(
|
||||
@@ -766,7 +766,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
}
|
||||
|
||||
return VisibilityDetector(
|
||||
key: ValueKey<String>('BOTTOM-MESSAGE'),
|
||||
key: ValueKey<String>('BOTTOM-MESSAGE-${message.id}'),
|
||||
onVisibilityChanged: (visibility) {
|
||||
final isVisible = visibility.visibleBounds != Rect.zero;
|
||||
if (isVisible) {
|
||||
@@ -1021,15 +1021,19 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
!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),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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<Widget>((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<MessageWidget>
|
||||
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<MessageWidget>
|
||||
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<MessageWidget>
|
||||
}
|
||||
|
||||
Widget _parseAttachments() {
|
||||
Map<String, List<Attachment>> attachmentGroups = {};
|
||||
final attachmentGroups = <String, List<Attachment>>{};
|
||||
|
||||
widget.message.attachments
|
||||
.where((element) => element.ogScrapeUrl == null)
|
||||
@@ -925,7 +939,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
attachmentGroups[e.type].add(e);
|
||||
});
|
||||
|
||||
List<Widget> attachmentList = [];
|
||||
final attachmentList = <Widget>[];
|
||||
|
||||
attachmentGroups.forEach((type, attachments) {
|
||||
final attachmentBuilder = widget.attachmentBuilders[type];
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.5.0
|
||||
|
||||
* Minor fixes and improvements
|
||||
|
||||
## 1.4.0-beta
|
||||
|
||||
* Added `MessageListCore.messageFilter` to filter messages locally
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -18,7 +18,7 @@ class Channels extends Table {
|
||||
TextColumn get config => text().map(MapConverter<Object>())();
|
||||
|
||||
/// 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()();
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user