diff --git a/.github/workflows/flutter-analyze.yml b/.github/workflows/flutter-analyze.yml
new file mode 100644
index 00000000..312a65ba
--- /dev/null
+++ b/.github/workflows/flutter-analyze.yml
@@ -0,0 +1,24 @@
+name: Flutter Analyze
+on:
+ push:
+ branches:
+ - master
+
+ pull_request:
+ branches:
+ - '*'
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: subosito/flutter-action@v1
+ with:
+ channel: 'beta'
+ - run: flutter pub get
+
+ - name: 'Flutter Format Check'
+ run: flutter format --set-exit-if-changed --dry-run .
+
+ - run: flutter analyze
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7d5b93f3..8ca3aa04 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,54 @@
+## 0.2.20+2
+
+- Added `shouldAddChannel` to ChannelsBloc in order to check if a channel has to be added to the list when a new message arrives
+
+## 0.2.20+1
+
+- Fixed bug that caused video attachment to show the same preview
+
+## 0.2.20
+
+- Implement shadowban
+
+## 0.2.19
+
+- Updated llc dependency
+- Added loading builder in channellistview
+- Added sendButtonLocation and animationduration to messageinput
+
+## 0.2.18
+
+- Updated llc dependency
+
+## 0.2.17+2
+
+- Expose ChannelsBloc.channelsComparator to sort channels on message.new event
+
+## 0.2.17+1
+
+- Fix mention tap bug
+
+## 0.2.17
+
+- Expose messageInputDecoration as part of the theme
+
+## 0.2.16
+
+- Do not wrap channel preview builder. Users will have to implement they're custom onTap/onLongPress implementation
+- Make public autofocus field of the TextField of message_input
+
+## 0.2.15
+
+- Add onLongPress on channel when using custom channel builder
+
+## 0.2.14
+
+- Add onMessageTap callbacks
+
+## 0.2.13+2
+
+- Add debounce to on change messageinput listener
+
## 0.2.13+1
- Use TextEditingController.addListener instead of TextField.onChanged
diff --git a/README.md b/README.md
index ba5de4c1..c5e4c9e7 100644
--- a/README.md
+++ b/README.md
@@ -11,8 +11,6 @@

[](https://gitter.im/GetStream/stream-chat-flutter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)

-[](https://codecov.io/gh/GetStream/stream-chat-flutter)
-
**Quick Links**
@@ -32,10 +30,10 @@ This repo includes a fully functional example app with setup instructions.
The example is available under the [example](https://github.com/GetStream/stream-chat-flutter/tree/master/example) folder.
## Add dependency
-
+Add this to your package's pubspec.yaml file, use the latest version [](https://pub.dartlang.org/packages/stream_chat_flutter)
```yaml
dependencies:
- stream_chat_flutter: ^0.2.1
+ stream_chat_flutter: ^latest_version
```
You should then run `flutter packages get`
diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart
index d8e1006b..1ab10934 100644
--- a/lib/src/channel_list_view.dart
+++ b/lib/src/channel_list_view.dart
@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:convert';
+import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@@ -9,7 +10,6 @@ import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_flutter/src/channels_bloc.dart';
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
import 'package:stream_chat_flutter/src/utils.dart';
-import 'dart:ui' as ui;
import '../stream_chat_flutter.dart';
import 'channel_bottom_sheet.dart';
diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart
index c1536653..eac6e3c2 100644
--- a/lib/src/channel_preview.dart
+++ b/lib/src/channel_preview.dart
@@ -201,7 +201,8 @@ class ChannelPreview extends StatelessWidget {
stream: channel.state.messagesStream,
initialData: channel.state.messages,
builder: (context, snapshot) {
- final lastMessage = channel.state.lastMessage;
+ final lastMessage = snapshot.data
+ ?.lastWhere((m) => m.shadowed != true, orElse: () => null);
if (lastMessage == null) {
return SizedBox();
}
diff --git a/lib/src/channels_bloc.dart b/lib/src/channels_bloc.dart
index 9b6e55bb..c3c5c6f1 100644
--- a/lib/src/channels_bloc.dart
+++ b/lib/src/channels_bloc.dart
@@ -14,11 +14,19 @@ class ChannelsBloc extends StatefulWidget {
/// Set this to true to prevent channels to be brought to the top of the list when a new message arrives
final bool lockChannelsOrder;
+ /// Comparator used to sort the channels when a message.new event is received
+ final Comparator channelsComparator;
+
+ /// Function used to evaluate if a channel should be added to the list when a message.new event is received
+ final bool Function(Event) shouldAddChannel;
+
/// Instantiate a new ChannelsBloc
const ChannelsBloc({
Key key,
this.child,
this.lockChannelsOrder = false,
+ this.channelsComparator,
+ this.shouldAddChannel,
}) : super(key: key);
@override
@@ -85,23 +93,21 @@ class ChannelsBlocState extends State
paginationParams.offset == null ||
paginationParams.offset == 0;
final oldChannels = List.from(channels ?? []);
- await client
- .queryChannels(
+ final _channels = await client.queryChannels(
filter: filter,
sort: sortOptions,
options: options,
paginationParams: paginationParams,
onlyOffline: onlyOffline,
- )
- .then((channels) {
- if (clear) {
- _channelsController.add(channels);
- } else {
- final l = oldChannels + channels;
- _channelsController.add(l);
- }
- _queryChannelsLoadingController.sink.add(false);
- });
+ );
+
+ if (clear) {
+ _channelsController.add(_channels);
+ } else {
+ final l = oldChannels + _channels;
+ _channelsController.add(l);
+ }
+ _queryChannelsLoadingController.sink.add(false);
} catch (err, stackTrace) {
print(err);
print(stackTrace);
@@ -126,7 +132,8 @@ class ChannelsBlocState extends State
final channel = newChannels.removeAt(index);
newChannels.insert(0, channel);
}
- } else {
+ } else if (widget.shouldAddChannel != null &&
+ widget.shouldAddChannel(e)) {
final hiddenIndex = _hiddenChannels.indexWhere((c) => c.cid == e.cid);
if (hiddenIndex > -1) {
newChannels.insert(0, _hiddenChannels[hiddenIndex]);
@@ -138,6 +145,10 @@ class ChannelsBlocState extends State
}
}
}
+
+ if (widget.channelsComparator != null) {
+ newChannels.sort(widget.channelsComparator);
+ }
_channelsController.add(newChannels);
}));
}
diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart
index db9790b9..9f4cbc0d 100644
--- a/lib/src/message_list_view.dart
+++ b/lib/src/message_list_view.dart
@@ -243,7 +243,7 @@ class _MessageListViewState extends State {
return StreamBuilder>(
stream: messagesStream?.map((messages) => messages
?.where((e) =>
- !e.isDeleted ||
+ (!e.isDeleted && e.shadowed != true) ||
(e.isDeleted &&
e.user.id == streamChannel.channel.client.state.user.id))
?.toList()),
diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart
index 4b22f3ec..1200f38d 100644
--- a/lib/src/message_widget.dart
+++ b/lib/src/message_widget.dart
@@ -572,13 +572,16 @@ class _MessageWidgetState extends State {
return Padding(
padding: EdgeInsets.only(left: leftPadding),
- child: Row(
+ child: Flex(
+ direction: Axis.horizontal,
+ clipBehavior: Clip.none,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
if (!deleted && (showThreadReplyIndicator || showInChannel))
Container(
margin: EdgeInsets.only(
- bottom: widget.messageTheme.replies.fontSize / 2),
+ bottom: widget.messageTheme.replies.fontSize / 2,
+ ),
child: CustomPaint(
size: const Size(16, 32),
painter: _ThreadReplyPainter(
@@ -591,7 +594,12 @@ class _MessageWidgetState extends State {
(child) => Transform(
transform: Matrix4.rotationY(widget.reverse ? pi : 0),
alignment: Alignment.center,
- child: Container(height: 16, child: Center(child: child)),
+ child: Container(
+ height: 16,
+ child: Center(
+ child: child,
+ ),
+ ),
),
),
].insertBetween(const SizedBox(width: 8.0)),
diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart
index b5883fdb..317dfec6 100644
--- a/lib/src/stream_chat.dart
+++ b/lib/src/stream_chat.dart
@@ -125,6 +125,7 @@ class StreamChatState extends State with WidgetsBindingObserver {
.on(EventType.messageNew)
.where((e) => e.user?.id != user.id)
.where((e) => e.message.silent != true)
+ .where((e) => e.message.shadowed != true)
.listen((event) async {
final channel = client.channel(
event.channelType,
diff --git a/lib/src/system_message.dart b/lib/src/system_message.dart
index 7454b0ee..7b4dc243 100644
--- a/lib/src/system_message.dart
+++ b/lib/src/system_message.dart
@@ -4,11 +4,16 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// It shows a date divider depending on the date difference
class SystemMessage extends StatelessWidget {
+ /// This message
final Message message;
+ /// The function called when tapping on the message when the message is not failed
+ final void Function(Message) onMessageTap;
+
const SystemMessage({
Key key,
@required this.message,
+ this.onMessageTap,
}) : super(key: key);
@override
@@ -44,57 +49,68 @@ class SystemMessage extends StatelessWidget {
dayInfo = createdAt.format('dd/MM/yyyy').toUpperCase();
}
- return Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- divider,
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 32.0),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- Text(
- message.text,
- style: TextStyle(
- fontSize: 10,
- color: Theme.of(context)
- .textTheme
- .headline6
- .color
- .withOpacity(.5),
- fontWeight: FontWeight.bold,
- ),
- ),
- Text.rich(
- TextSpan(
- children: [
+ return GestureDetector(
+ behavior: HitTestBehavior.opaque,
+ onTap: () {
+ if (onMessageTap != null) {
+ onMessageTap(message);
+ }
+ },
+ child: Container(
+ width: double.infinity,
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ divider,
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 32.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Text(
+ message.text,
+ style: TextStyle(
+ fontSize: 10,
+ color: Theme.of(context)
+ .textTheme
+ .headline6
+ .color
+ .withOpacity(.5),
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ Text.rich(
TextSpan(
- text: dayInfo,
+ children: [
+ TextSpan(
+ text: dayInfo,
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ TextSpan(text: ' AT'),
+ TextSpan(text: ' $hourInfo'),
+ ],
style: TextStyle(
- fontWeight: FontWeight.bold,
+ fontWeight: FontWeight.normal,
),
),
- TextSpan(text: ' AT'),
- TextSpan(text: ' $hourInfo'),
- ],
- style: TextStyle(
- fontWeight: FontWeight.normal,
+ style: TextStyle(
+ fontSize: 10,
+ color: Theme.of(context)
+ .textTheme
+ .headline6
+ .color
+ .withOpacity(.5),
+ ),
),
- ),
- style: TextStyle(
- fontSize: 10,
- color: Theme.of(context)
- .textTheme
- .headline6
- .color
- .withOpacity(.5),
- ),
+ ],
),
- ],
- ),
+ ),
+ divider,
+ ],
),
- divider,
- ],
+ ),
);
}
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 5a3ad4e5..e29042cb 100644
--- a/pubspec.yaml
+++ b/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: 0.2.13+1
+version: 0.2.20+2
repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues