Merge branch 'v4' of https://github.com/GetStream/stream-chat-flutter into live-event-improvements
This commit is contained in:
@@ -1,6 +1,33 @@
|
||||
## 4.0.0-beta.0
|
||||
|
||||
✅ Added
|
||||
|
||||
- Added support for ownCapabilities.
|
||||
|
||||
🐞 Fixed
|
||||
|
||||
- Minor fixes and improvements.
|
||||
|
||||
## Upcoming
|
||||
|
||||
🐞 Fixed
|
||||
|
||||
- Fixed reactions not working for threads in offline mode.
|
||||
- [[#1046]](https://github.com/GetStream/stream-chat-flutter/issues/1046) After `/mute` command on reload cannot access
|
||||
any channel.
|
||||
- [[#1047]](https://github.com/GetStream/stream-chat-flutter/issues/1047) `own_capabilities` extraData missing after
|
||||
channel update.
|
||||
- [[#1054]](https://github.com/GetStream/stream-chat-flutter/issues/1054) Fix `Unsupported operation: Cannot remove from an unmodifiable list`.
|
||||
- [[#1033]](https://github.com/GetStream/stream-chat-flutter/issues/1033) Hard delete from dashboard does not delete message from client.
|
||||
|
||||
✅ Added
|
||||
|
||||
- Handle `event.message` in `channel.truncate` events
|
||||
|
||||
## 3.5.1
|
||||
|
||||
🐞 Fixed
|
||||
|
||||
- `channel.unreadCount` was being set as using global unread count on a very specific case.
|
||||
- The reconnection logic for the WebSocket connection is now more robust.
|
||||
|
||||
@@ -16,7 +43,7 @@
|
||||
- [[#890]](https://github.com/GetStream/stream-chat-flutter/pull/890) Fixed Reactions not updating on thread messages.
|
||||
Thanks [bstolinski](https://github.com/bstolinski).
|
||||
- [[#897]](https://github.com/GetStream/stream-chat-flutter/issues/897) Fixed error type mis-match in `AuthInterceptor`.
|
||||
- [[#891]](https://github.com/GetStream/stream-chat-flutter/pull/891) Fixed reply counter for parent message not
|
||||
- [[#891]](https://github.com/GetStream/stream-chat-flutter/pull/891) Fixed reply counter for parent message not
|
||||
updating correctly after deleting thread message.
|
||||
- Fix `channelState.copyWith` with respect to pinnedMessages.
|
||||
|
||||
|
||||
@@ -1116,7 +1116,6 @@ class Channel {
|
||||
// remove the passed message if response does
|
||||
// not contain message
|
||||
state!.removeMessage(message);
|
||||
await _client.chatPersistenceClient?.deleteMessageById(messageId);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -1608,10 +1607,12 @@ class ChannelClientState {
|
||||
_subscriptions.add(_channel.on(EventType.memberRemoved).listen((Event e) {
|
||||
final user = e.user;
|
||||
updateChannelState(channelState.copyWith(
|
||||
members: List.from(
|
||||
channelState.members..removeWhere((m) => m.userId == user!.id),
|
||||
),
|
||||
read: channelState.read..removeWhere((r) => r.user.id == user!.id),
|
||||
members: channelState.members
|
||||
.where((m) => m.userId != user!.id)
|
||||
.toList(growable: false),
|
||||
read: channelState.read
|
||||
.where((r) => r.user.id != user!.id)
|
||||
.toList(growable: false),
|
||||
));
|
||||
}));
|
||||
}
|
||||
@@ -1620,9 +1621,7 @@ class ChannelClientState {
|
||||
_subscriptions.add(_channel.on(EventType.channelUpdated).listen((Event e) {
|
||||
final channel = e.channel!;
|
||||
updateChannelState(channelState.copyWith(
|
||||
channel: channel.copyWith(
|
||||
ownCapabilities: channelState.channel?.ownCapabilities,
|
||||
),
|
||||
channel: channelState.channel?.merge(channel),
|
||||
members: channel.members,
|
||||
));
|
||||
}));
|
||||
@@ -1636,6 +1635,9 @@ class ChannelClientState {
|
||||
await _channel._client.chatPersistenceClient
|
||||
?.deleteMessageByCid(channel.cid);
|
||||
truncate();
|
||||
if (event.message != null) {
|
||||
updateMessage(event.message!);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1870,7 +1872,9 @@ class ChannelClientState {
|
||||
}
|
||||
|
||||
/// Remove a [message] from this [channelState].
|
||||
void removeMessage(Message message) {
|
||||
void removeMessage(Message message) async {
|
||||
await _channel._client.chatPersistenceClient?.deleteMessageById(message.id);
|
||||
|
||||
final parentId = message.parentId;
|
||||
// i.e. it's a thread message, Remove it
|
||||
if (parentId != null) {
|
||||
@@ -2151,12 +2155,12 @@ class ChannelClientState {
|
||||
final BehaviorSubject<Map<String, List<Message>>> _threadsController =
|
||||
BehaviorSubject.seeded({});
|
||||
|
||||
set _threads(Map<String, List<Message>> v) {
|
||||
_channel.client.chatPersistenceClient?.updateMessages(
|
||||
set _threads(Map<String, List<Message>> threads) {
|
||||
_threadsController.add(threads);
|
||||
_channel.client.chatPersistenceClient?.updateChannelThreads(
|
||||
_channel.cid!,
|
||||
v.values.expand((v) => v).toList(),
|
||||
threads,
|
||||
);
|
||||
_threadsController.add(v);
|
||||
}
|
||||
|
||||
/// Channel related typing users last value.
|
||||
|
||||
@@ -417,6 +417,7 @@ class StreamChatClient {
|
||||
}
|
||||
|
||||
void _connectionStatusHandler(ConnectionStatus status) async {
|
||||
final previousState = wsConnectionStatus;
|
||||
final currentState = _wsConnectionStatus = status;
|
||||
|
||||
handleEvent(Event(
|
||||
@@ -424,7 +425,8 @@ class StreamChatClient {
|
||||
online: status == ConnectionStatus.connected,
|
||||
));
|
||||
|
||||
if (currentState == ConnectionStatus.connected) {
|
||||
if (currentState == ConnectionStatus.connected &&
|
||||
previousState != ConnectionStatus.connected) {
|
||||
// connection recovered
|
||||
final cids = state.channels.keys.toList(growable: false);
|
||||
if (cids.isNotEmpty) {
|
||||
|
||||
@@ -181,7 +181,7 @@ class ChannelModel {
|
||||
updatedAt: other.updatedAt,
|
||||
deletedAt: other.deletedAt,
|
||||
memberCount: other.memberCount,
|
||||
extraData: other.extraData,
|
||||
extraData: {...extraData, ...other.extraData},
|
||||
team: other.team,
|
||||
cooldown: other.cooldown,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:stream_chat/src/core/models/channel_model.dart';
|
||||
import 'package:stream_chat/src/core/models/user.dart';
|
||||
|
||||
part 'channel_mute.g.dart';
|
||||
|
||||
/// The class that contains the information about a muted channel
|
||||
@JsonSerializable(createToJson: false)
|
||||
class ChannelMute {
|
||||
/// Constructor used for json serialization
|
||||
ChannelMute({
|
||||
required this.user,
|
||||
required this.channel,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
this.expires,
|
||||
});
|
||||
|
||||
/// Create a new instance from a json
|
||||
factory ChannelMute.fromJson(Map<String, dynamic> json) =>
|
||||
_$ChannelMuteFromJson(json);
|
||||
|
||||
/// The user that performed the muting action
|
||||
final User user;
|
||||
|
||||
/// The target channel
|
||||
final ChannelModel channel;
|
||||
|
||||
/// The date in which the channel was muted
|
||||
final DateTime createdAt;
|
||||
|
||||
/// The date of the last update
|
||||
final DateTime updatedAt;
|
||||
|
||||
/// The date in which the mute expires
|
||||
final DateTime? expires;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'channel_mute.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
ChannelMute _$ChannelMuteFromJson(Map<String, dynamic> json) => ChannelMute(
|
||||
user: User.fromJson(json['user'] as Map<String, dynamic>),
|
||||
channel: ChannelModel.fromJson(json['channel'] as Map<String, dynamic>),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
expires: json['expires'] == null
|
||||
? null
|
||||
: DateTime.parse(json['expires'] as String),
|
||||
);
|
||||
@@ -1,7 +1,5 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:stream_chat/src/core/models/channel_model.dart';
|
||||
import 'package:stream_chat/src/core/models/user.dart';
|
||||
import 'package:stream_chat/src/core/util/serializer.dart';
|
||||
|
||||
part 'mute.g.dart';
|
||||
|
||||
@@ -11,27 +9,27 @@ class Mute {
|
||||
/// Constructor used for json serialization
|
||||
Mute({
|
||||
required this.user,
|
||||
required this.channel,
|
||||
required this.target,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
this.expires,
|
||||
});
|
||||
|
||||
/// Create a new instance from a json
|
||||
factory Mute.fromJson(Map<String, dynamic> json) => _$MuteFromJson(json);
|
||||
|
||||
/// The user that performed the muting action
|
||||
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
|
||||
final User user;
|
||||
|
||||
/// The target user
|
||||
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
|
||||
final ChannelModel channel;
|
||||
final User target;
|
||||
|
||||
/// The date in which the use was muted
|
||||
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
|
||||
final DateTime createdAt;
|
||||
|
||||
/// The date of the last update
|
||||
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
|
||||
final DateTime updatedAt;
|
||||
|
||||
/// The date in which the mute expires
|
||||
final DateTime? expires;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,10 @@ part of 'mute.dart';
|
||||
|
||||
Mute _$MuteFromJson(Map<String, dynamic> json) => Mute(
|
||||
user: User.fromJson(json['user'] as Map<String, dynamic>),
|
||||
channel: ChannelModel.fromJson(json['channel'] as Map<String, dynamic>),
|
||||
target: User.fromJson(json['target'] as Map<String, dynamic>),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
expires: json['expires'] == null
|
||||
? null
|
||||
: DateTime.parse(json['expires'] as String),
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:stream_chat/src/core/models/channel_mute.dart';
|
||||
import 'package:stream_chat/src/core/util/serializer.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
|
||||
@@ -79,7 +80,7 @@ class OwnUser extends User {
|
||||
bool? banned,
|
||||
DateTime? banExpires,
|
||||
List<String>? teams,
|
||||
List<Mute>? channelMutes,
|
||||
List<ChannelMute>? channelMutes,
|
||||
List<Device>? devices,
|
||||
List<Mute>? mutes,
|
||||
int? totalUnreadCount,
|
||||
@@ -142,7 +143,7 @@ class OwnUser extends User {
|
||||
|
||||
/// List of channels muted by the user.
|
||||
@JsonKey(includeIfNull: false)
|
||||
final List<Mute> channelMutes;
|
||||
final List<ChannelMute> channelMutes;
|
||||
|
||||
/// Total unread messages by the user.
|
||||
@JsonKey(includeIfNull: false)
|
||||
|
||||
@@ -18,7 +18,7 @@ OwnUser _$OwnUserFromJson(Map<String, dynamic> json) => OwnUser(
|
||||
totalUnreadCount: json['total_unread_count'] as int? ?? 0,
|
||||
unreadChannels: json['unread_channels'] as int? ?? 0,
|
||||
channelMutes: (json['channel_mutes'] as List<dynamic>?)
|
||||
?.map((e) => Mute.fromJson(e as Map<String, dynamic>))
|
||||
?.map((e) => ChannelMute.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
const [],
|
||||
id: json['id'] as String,
|
||||
|
||||
@@ -197,6 +197,28 @@ abstract class ChatPersistenceClient {
|
||||
/// Deletes all the members by channel [cids]
|
||||
Future<void> deleteMembersByCids(List<String> cids);
|
||||
|
||||
/// Updates the channel [cid] threads data along with reactions and users.
|
||||
Future<void> updateChannelThreads(
|
||||
String cid,
|
||||
Map<String, List<Message>> threads,
|
||||
) async {
|
||||
final messages = threads.values.expand((it) => it).toList();
|
||||
|
||||
// Removing old reactions before saving the new
|
||||
final oldReactions = messages.map((it) => it.id).toList();
|
||||
await deleteReactionsByMessageId(oldReactions);
|
||||
|
||||
// Adding new reactions and users data
|
||||
final reactions = messages.expand(_expandReactions).toList();
|
||||
final users = messages.map((it) => it.user).withNullifyer.toList();
|
||||
|
||||
await Future.wait([
|
||||
updateMessages(cid, messages),
|
||||
updateReactions(reactions),
|
||||
updateUsers(users),
|
||||
]);
|
||||
}
|
||||
|
||||
/// Update the channel state data using [channelState]
|
||||
Future<void> updateChannelState(ChannelState channelState) =>
|
||||
updateChannelStates([channelState]);
|
||||
@@ -239,17 +261,8 @@ abstract class ChatPersistenceClient {
|
||||
channelWithMessages[cid] = messages;
|
||||
channelWithPinnedMessages[cid] = pinnedMessages;
|
||||
|
||||
List<Reaction> expandReactions(Message message) {
|
||||
final own = message.ownReactions;
|
||||
final latest = message.latestReactions;
|
||||
return [
|
||||
if (own != null) ...own.where((r) => r.userId != null),
|
||||
if (latest != null) ...latest.where((r) => r.userId != null),
|
||||
];
|
||||
}
|
||||
|
||||
reactions.addAll(messages.expand(expandReactions));
|
||||
pinnedReactions.addAll(pinnedMessages.expand(expandReactions));
|
||||
reactions.addAll(messages.expand(_expandReactions));
|
||||
pinnedReactions.addAll(pinnedMessages.expand(_expandReactions));
|
||||
|
||||
users.addAll([
|
||||
channel.createdBy,
|
||||
@@ -292,4 +305,13 @@ abstract class ChatPersistenceClient {
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
List<Reaction> _expandReactions(Message message) {
|
||||
final own = message.ownReactions;
|
||||
final latest = message.latestReactions;
|
||||
return [
|
||||
if (own != null) ...own.where((r) => r.userId != null),
|
||||
if (latest != null) ...latest.where((r) => r.userId != null),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ import 'package:stream_chat/src/client/client.dart';
|
||||
/// Current package version
|
||||
/// Used in [StreamChatClient] to build the `x-stream-client` header
|
||||
// ignore: constant_identifier_names
|
||||
const PACKAGE_VERSION = '3.5.1';
|
||||
const PACKAGE_VERSION = '4.0.0-beta.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: 3.5.1
|
||||
version: 4.0.0-beta.0
|
||||
repository: https://github.com/GetStream/stream-chat-flutter
|
||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"user": {
|
||||
"id": "super-band-9",
|
||||
"role": "user",
|
||||
"created_at": "2020-03-03T16:48:28.853674Z",
|
||||
"updated_at": "2021-05-26T03:22:20.296181Z",
|
||||
"last_active": "2021-06-16T11:42:29.466165498Z",
|
||||
"banned": false,
|
||||
"online": true,
|
||||
"username": "Rioland",
|
||||
"image": "https://placehold.jp/150x150.png",
|
||||
"invisible": false,
|
||||
"name": "Proud darkness",
|
||||
"unread_count": 0
|
||||
},
|
||||
"channel": {
|
||||
"id": "!members-Qsp7PpigdPkW0rJk0603y5GnTiF1iRfoDc4SAngMMmw",
|
||||
"type": "messaging",
|
||||
"cid": "messaging:!members-Qsp7PpigdPkW0rJk0603y5GnTiF1iRfoDc4SAngMMmw",
|
||||
"last_message_at": "2020-12-02T06:56:18.003432Z",
|
||||
"created_at": "2020-11-30T10:25:32.494601Z",
|
||||
"updated_at": "2020-11-30T10:25:32.494601Z",
|
||||
"created_by": {
|
||||
"id": "super-band-9",
|
||||
"role": "user",
|
||||
"created_at": "2020-03-03T16:48:28.853674Z",
|
||||
"updated_at": "2021-05-26T03:22:20.296181Z",
|
||||
"last_active": "2021-06-16T11:42:29.466165498Z",
|
||||
"banned": false,
|
||||
"online": true,
|
||||
"image": "https://placehold.jp/150x150.png",
|
||||
"invisible": false,
|
||||
"name": "Proud darkness",
|
||||
"unread_count": 0,
|
||||
"username": "Rioland"
|
||||
},
|
||||
"frozen": false,
|
||||
"disabled": false,
|
||||
"member_count": 2,
|
||||
"config": {
|
||||
"created_at": "2020-04-15T14:57:17.00966Z",
|
||||
"updated_at": "2021-05-25T14:25:30.405621Z",
|
||||
"name": "messaging",
|
||||
"typing_events": true,
|
||||
"read_events": true,
|
||||
"connect_events": true,
|
||||
"search": true,
|
||||
"reactions": true,
|
||||
"replies": true,
|
||||
"mutes": true,
|
||||
"uploads": true,
|
||||
"url_enrichment": true,
|
||||
"custom_events": false,
|
||||
"push_notifications": true,
|
||||
"message_retention": "infinite",
|
||||
"max_message_length": 5000,
|
||||
"automod": "disabled",
|
||||
"automod_behavior": "flag",
|
||||
"blocklist": "profanity_en_2020_v1",
|
||||
"blocklist_behavior": "block",
|
||||
"automod_thresholds": {},
|
||||
"commands": [
|
||||
{
|
||||
"name": "giphy",
|
||||
"description": "Post a random gif to the channel",
|
||||
"args": "[text]",
|
||||
"set": "fun_set"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"created_at": "2020-12-04T10:39:06.512021Z",
|
||||
"updated_at": "2020-12-04T10:39:06.512021Z"
|
||||
}
|
||||
+13
-55
@@ -13,61 +13,19 @@
|
||||
"name": "Proud darkness",
|
||||
"unread_count": 0
|
||||
},
|
||||
"channel": {
|
||||
"id": "!members-Qsp7PpigdPkW0rJk0603y5GnTiF1iRfoDc4SAngMMmw",
|
||||
"type": "messaging",
|
||||
"cid": "messaging:!members-Qsp7PpigdPkW0rJk0603y5GnTiF1iRfoDc4SAngMMmw",
|
||||
"last_message_at": "2020-12-02T06:56:18.003432Z",
|
||||
"created_at": "2020-11-30T10:25:32.494601Z",
|
||||
"updated_at": "2020-11-30T10:25:32.494601Z",
|
||||
"created_by": {
|
||||
"id": "super-band-9",
|
||||
"role": "user",
|
||||
"created_at": "2020-03-03T16:48:28.853674Z",
|
||||
"updated_at": "2021-05-26T03:22:20.296181Z",
|
||||
"last_active": "2021-06-16T11:42:29.466165498Z",
|
||||
"banned": false,
|
||||
"online": true,
|
||||
"image": "https://placehold.jp/150x150.png",
|
||||
"invisible": false,
|
||||
"name": "Proud darkness",
|
||||
"unread_count": 0,
|
||||
"username": "Rioland"
|
||||
},
|
||||
"frozen": false,
|
||||
"disabled": false,
|
||||
"member_count": 2,
|
||||
"config": {
|
||||
"created_at": "2020-04-15T14:57:17.00966Z",
|
||||
"updated_at": "2021-05-25T14:25:30.405621Z",
|
||||
"name": "messaging",
|
||||
"typing_events": true,
|
||||
"read_events": true,
|
||||
"connect_events": true,
|
||||
"search": true,
|
||||
"reactions": true,
|
||||
"replies": true,
|
||||
"mutes": true,
|
||||
"uploads": true,
|
||||
"url_enrichment": true,
|
||||
"custom_events": false,
|
||||
"push_notifications": true,
|
||||
"message_retention": "infinite",
|
||||
"max_message_length": 5000,
|
||||
"automod": "disabled",
|
||||
"automod_behavior": "flag",
|
||||
"blocklist": "profanity_en_2020_v1",
|
||||
"blocklist_behavior": "block",
|
||||
"automod_thresholds": {},
|
||||
"commands": [
|
||||
{
|
||||
"name": "giphy",
|
||||
"description": "Post a random gif to the channel",
|
||||
"args": "[text]",
|
||||
"set": "fun_set"
|
||||
}
|
||||
]
|
||||
}
|
||||
"target": {
|
||||
"id": "super-band-10",
|
||||
"role": "user",
|
||||
"created_at": "2020-03-03T16:48:28.853674Z",
|
||||
"updated_at": "2021-05-26T03:22:20.296181Z",
|
||||
"last_active": "2021-06-16T11:42:29.466165498Z",
|
||||
"banned": false,
|
||||
"online": true,
|
||||
"username": "Holland",
|
||||
"image": "https://placehold.jp/150x150.png",
|
||||
"invisible": false,
|
||||
"name": "Proud brightness",
|
||||
"unread_count": 0
|
||||
},
|
||||
"created_at": "2020-12-04T10:39:06.512021Z",
|
||||
"updated_at": "2020-12-04T10:39:06.512021Z"
|
||||
|
||||
@@ -645,8 +645,8 @@ void main() {
|
||||
|
||||
when(() => persistence.getChannelThreads(any()))
|
||||
.thenAnswer((_) async => {});
|
||||
when(() => persistence.updateMessages(any(), any()))
|
||||
.thenAnswer((_) => Future.value());
|
||||
when(() => persistence.updateChannelThreads(any(), any()))
|
||||
.thenAnswer((_) async => {});
|
||||
when(() => persistence.getChannelStateByCid(any(),
|
||||
messagePagination: any(named: 'messagePagination'),
|
||||
pinnedMessagePagination:
|
||||
@@ -692,7 +692,7 @@ void main() {
|
||||
|
||||
verify(() => persistence.getChannelThreads(any()))
|
||||
.called((persistentChannelStates + channelStates).length);
|
||||
verify(() => persistence.updateMessages(any(), any()))
|
||||
verify(() => persistence.updateChannelThreads(any(), any()))
|
||||
.called((persistentChannelStates + channelStates).length);
|
||||
verify(
|
||||
() => persistence.getChannelStateByCid(any(),
|
||||
@@ -733,8 +733,8 @@ void main() {
|
||||
|
||||
when(() => persistence.getChannelThreads(any()))
|
||||
.thenAnswer((_) async => {});
|
||||
when(() => persistence.updateMessages(any(), any()))
|
||||
.thenAnswer((_) => Future.value());
|
||||
when(() => persistence.updateChannelThreads(any(), any()))
|
||||
.thenAnswer((_) async => {});
|
||||
when(() => persistence.getChannelStateByCid(any(),
|
||||
messagePagination: any(named: 'messagePagination'),
|
||||
pinnedMessagePagination:
|
||||
@@ -775,7 +775,7 @@ void main() {
|
||||
|
||||
verify(() => persistence.getChannelThreads(any()))
|
||||
.called(persistentChannelStates.length);
|
||||
verify(() => persistence.updateMessages(any(), any()))
|
||||
verify(() => persistence.updateChannelThreads(any(), any()))
|
||||
.called(persistentChannelStates.length);
|
||||
verify(
|
||||
() => persistence.getChannelStateByCid(any(),
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import 'package:stream_chat/src/core/models/channel_model.dart';
|
||||
import 'package:stream_chat/src/core/models/channel_mute.dart';
|
||||
import 'package:stream_chat/src/core/models/user.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../../utils.dart';
|
||||
|
||||
void main() {
|
||||
group('src/models/channel_mute', () {
|
||||
test('should parse json correctly', () {
|
||||
final mute = ChannelMute.fromJson(jsonFixture('channel_mute.json'));
|
||||
expect(mute.user, isA<User>());
|
||||
expect(mute.channel, isA<ChannelModel>());
|
||||
expect(mute.createdAt, DateTime.parse('2020-12-04T10:39:06.512021Z'));
|
||||
expect(mute.updatedAt, DateTime.parse('2020-12-04T10:39:06.512021Z'));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:stream_chat/src/core/models/channel_model.dart';
|
||||
import 'package:stream_chat/src/core/models/mute.dart';
|
||||
import 'package:stream_chat/src/core/models/user.dart';
|
||||
import 'package:test/test.dart';
|
||||
@@ -6,12 +5,13 @@ import 'package:test/test.dart';
|
||||
import '../../utils.dart';
|
||||
|
||||
void main() {
|
||||
group('src/models/mute', () {
|
||||
group('src/models/channel_mute', () {
|
||||
test('should parse json correctly', () {
|
||||
final mute = Mute.fromJson(jsonFixture('mute.json'));
|
||||
expect(mute.channel, isA<ChannelModel>());
|
||||
expect(mute.user, isA<User>());
|
||||
expect(mute.target, isA<User>());
|
||||
expect(mute.createdAt, DateTime.parse('2020-12-04T10:39:06.512021Z'));
|
||||
expect(mute.updatedAt, DateTime.parse('2020-12-04T10:39:06.512021Z'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:stream_chat/src/core/models/channel_mute.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
@@ -6,12 +7,14 @@ import '../../utils.dart';
|
||||
|
||||
class MockMute extends Mock implements Mute {}
|
||||
|
||||
class ChannelMockMute extends Mock implements ChannelMute {}
|
||||
|
||||
class MockDevice extends Mock implements Device {}
|
||||
|
||||
void main() {
|
||||
final devices = [MockDevice(), MockDevice()];
|
||||
final mutes = [MockMute(), MockMute()];
|
||||
final channelMutes = [MockMute()];
|
||||
final channelMutes = [ChannelMockMute()];
|
||||
final createdAt = DateTime.parse('2021-05-03 12:39:21.817646');
|
||||
final updatedAt = DateTime.parse('2021-04-03 12:39:21.817646');
|
||||
final lastActive = DateTime.parse('2021-03-03 12:39:21.817646');
|
||||
|
||||
@@ -162,6 +162,23 @@ void main() {
|
||||
expect(channelState, isNotNull);
|
||||
});
|
||||
|
||||
test('updateChannelThreads', () async {
|
||||
const cid = 'test:cid';
|
||||
final user = User(id: 'test-user-id');
|
||||
final threads = {
|
||||
'parent-test-message': [
|
||||
Message(
|
||||
id: 'test-message',
|
||||
text: 'test-message',
|
||||
user: user,
|
||||
ownReactions: [Reaction(type: 'test', user: user)],
|
||||
latestReactions: [Reaction(type: 'test', user: user)],
|
||||
)
|
||||
]
|
||||
};
|
||||
persistenceClient.updateChannelThreads(cid, threads);
|
||||
});
|
||||
|
||||
test('updateChannelState', () async {
|
||||
final channelState = ChannelState();
|
||||
persistenceClient.updateChannelState(channelState);
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
## 4.0.0-beta.1
|
||||
|
||||
✅ Added
|
||||
|
||||
- Deprecated old widgets in favor of Stream-prefixed ones.
|
||||
- Use channel capabilities to show/hide actions.
|
||||
- Deprecated `ChannelListView` in favor of `StreamChannelListView`.
|
||||
- Deprecated `ChannelPreview` in favor of `StreamChannelListTile`.
|
||||
- Deprecated `ChannelAvatar` in favor of `StreamChannelAvatar`.
|
||||
- Deprecated `ChannelName` in favor of `StreamChannelName`.
|
||||
- Deprecated `MessageInput` in favor of `StreamMessageInput`.
|
||||
- Separated `MessageInput` widget in smaller components. (For example `CountDownButton`, `StreamAttachmentPicker`...)
|
||||
- Updated `stream_chat_flutter_core` dependency to [`4.0.0-beta.0`](https://pub.dev/packages/stream_chat_flutter_core/changelog).
|
||||
- Added OpenGraph preview support for links in `StreamMessageInput`.
|
||||
- Removed video compression.
|
||||
|
||||
🐞 Fixed
|
||||
|
||||
- Minor fixes and improvements
|
||||
|
||||
## Upcoming
|
||||
|
||||
🐞 Fixed
|
||||
|
||||
-[[#892]](https://github.com/GetStream/stream-chat-flutter/issues/892): Fix default `initialAlignment` in `MessageListView`.
|
||||
|
||||
## 3.5.1
|
||||
|
||||
🛑️ Breaking Changes
|
||||
|
||||
@@ -40,7 +40,7 @@ android {
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "com.example.example"
|
||||
minSdkVersion 21
|
||||
minSdkVersion 22
|
||||
targetSdkVersion 31
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 51;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -68,7 +68,6 @@
|
||||
59062C6EC2CCFE110AC70AB8 /* Pods-Runner.release.xcconfig */,
|
||||
4684439012E1DB1A82103E26 /* Pods-Runner.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -356,13 +355,17 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = EHV7XZLAHA;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
@@ -488,13 +491,17 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = EHV7XZLAHA;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
@@ -515,13 +522,17 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = EHV7XZLAHA;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
|
||||
@@ -87,7 +87,8 @@ class MyApp extends StatelessWidget {
|
||||
|
||||
/// A list of messages sent in the current channel.
|
||||
///
|
||||
/// This is implemented using [StreamMessageListView], a widget that provides query
|
||||
/// This is implemented using [StreamMessageListView],
|
||||
/// a widget that provides query
|
||||
/// functionalities fetching the messages from the api and showing them in a
|
||||
/// listView.
|
||||
class ChannelPage extends StatelessWidget {
|
||||
|
||||
@@ -27,7 +27,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
/// - We make [StreamChat] the root Widget of our application
|
||||
///
|
||||
/// - We create a single [ChannelPage] widget under [StreamChat] with three
|
||||
/// widgets: [StreamChannelHeader], [StreamMessageListView] and [StreamMessageInput]
|
||||
/// widgets: [StreamChannelHeader], [StreamMessageListView]
|
||||
/// and [StreamMessageInput]
|
||||
///
|
||||
/// If you now run the simulator you will see a single channel UI.
|
||||
void main() async {
|
||||
|
||||
@@ -25,7 +25,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
/// The [ChannelListPage] widget retrieves the list of channels based on a
|
||||
/// custom query and ordering. In this case we are showing the list of
|
||||
/// channels in which the current user is a member and we order them based
|
||||
/// on the time they had a new message. [StreamChannelListView] handles pagination
|
||||
/// on the time they had a new message.
|
||||
/// [StreamChannelListView] handles pagination
|
||||
/// and updates automatically when new channels are created or when a new
|
||||
/// message is added to a channel.
|
||||
void main() async {
|
||||
|
||||
@@ -15,9 +15,10 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
/// We start by changing how channel previews are shown in the channel list
|
||||
/// and include the number of unread messages for each.
|
||||
///
|
||||
/// We're passing a custom widget to [StreamChannelListView.channelPreviewBuilder];
|
||||
/// this will override the default [StreamChannelPreview] and allows you to create
|
||||
/// one yourself.
|
||||
/// We're passing a custom widget
|
||||
/// to [StreamChannelListView.channelPreviewBuilder];
|
||||
/// this will override the default [StreamChannelPreview] and allows you
|
||||
/// to create one yourself.
|
||||
///
|
||||
/// There are a couple interesting things we do in this widget:
|
||||
///
|
||||
|
||||
@@ -8,8 +8,10 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
/// to create sub-conversations inside the same channel.
|
||||
///
|
||||
/// Using threaded conversations is very simple and mostly a matter of
|
||||
/// plugging the [StreamMessageListView] to another widget that renders the widget.
|
||||
/// To make this simple, such a widget only needs to build [StreamMessageListView]
|
||||
/// plugging the [StreamMessageListView]
|
||||
/// to another widget that renders the widget.
|
||||
/// To make this simple, such a widget only needs
|
||||
/// to build [StreamMessageListView]
|
||||
/// with the parent attribute set to the thread’s root message.
|
||||
///
|
||||
/// Now we can open threads and create new ones as well. If you long-press a
|
||||
|
||||
@@ -58,7 +58,8 @@ class AttachmentActionsModal extends StatelessWidget {
|
||||
/// List of custom actions
|
||||
final List<AttachmentAction> customActions;
|
||||
|
||||
/// Creates a copy of [StreamMessageWidget] with specified attributes overridden.
|
||||
/// Creates a copy of [StreamMessageWidget] with
|
||||
/// specified attributes overridden.
|
||||
AttachmentActionsModal copyWith({
|
||||
Key? key,
|
||||
int? currentIndex,
|
||||
|
||||
@@ -513,13 +513,19 @@ class _ChannelListViewState extends State<ChannelListView> {
|
||||
final canDeleteChannel =
|
||||
channel.ownCapabilities.contains(PermissionType.deleteChannel);
|
||||
|
||||
final actionPaneChildren =
|
||||
widget.swipeActions?.length ?? (canDeleteChannel ? 2 : 1);
|
||||
final actionPaneExtentRatio = actionPaneChildren > 5
|
||||
? 1 / actionPaneChildren
|
||||
: actionPaneChildren * 0.2;
|
||||
|
||||
return StreamChannel(
|
||||
key: ValueKey<String>('CHANNEL-${channel.cid}'),
|
||||
channel: channel,
|
||||
child: Slidable(
|
||||
enabled: widget.swipeToAction,
|
||||
endActionPane: ActionPane(
|
||||
extentRatio: canDeleteChannel ? 0.4 : 0.2,
|
||||
extentRatio: actionPaneExtentRatio,
|
||||
motion: const BehindMotion(),
|
||||
children: widget.swipeActions
|
||||
?.map((e) => CustomSlidableAction(
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:jiffy/jiffy.dart';
|
||||
import 'package:stream_chat_flutter/src/connection_status_builder.dart';
|
||||
import 'package:stream_chat_flutter/src/message_input/message_input.dart';
|
||||
import 'package:stream_chat_flutter/src/message_list_view.dart';
|
||||
import 'package:stream_chat_flutter/src/message_search_list_view.dart';
|
||||
import 'package:stream_chat_flutter/src/v4/message_input/stream_message_input.dart';
|
||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'
|
||||
show User;
|
||||
|
||||
@@ -87,7 +87,8 @@ abstract class Translations {
|
||||
/// The label for "reconnecting" in [StreamConnectionStatusBuilder]
|
||||
String get reconnectingLabel;
|
||||
|
||||
/// The label for also send as direct message "checkbox"" in [StreamMessageInput]
|
||||
/// The label for also send
|
||||
/// as direct message "checkbox"" in [StreamMessageInput]
|
||||
String get alsoSendAsDirectMessageLabel;
|
||||
|
||||
/// The label for search Gif
|
||||
|
||||
@@ -392,7 +392,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
||||
double get _initialAlignment {
|
||||
final initialAlignment = widget.initialAlignment;
|
||||
if (initialAlignment != null) return initialAlignment;
|
||||
return 0.1;
|
||||
return streamChannel!.initialMessageId == null ? 0 : 0.1;
|
||||
}
|
||||
|
||||
bool _isInitialMessage(String id) => streamChannel!.initialMessageId == id;
|
||||
|
||||
@@ -428,7 +428,8 @@ class StreamMessageWidget extends StatefulWidget {
|
||||
/// Customize onTap on attachment
|
||||
final void Function(Message message, Attachment attachment)? onAttachmentTap;
|
||||
|
||||
/// Creates a copy of [StreamMessageWidget] with specified attributes overridden.
|
||||
/// Creates a copy of [StreamMessageWidget] with
|
||||
/// specified attributes overridden.
|
||||
StreamMessageWidget copyWith({
|
||||
Key? key,
|
||||
void Function(User)? onMentionTap,
|
||||
|
||||
@@ -12,7 +12,8 @@ typedef ChannelListHeaderTheme = StreamChannelListHeaderTheme;
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [StreamChannelListHeaderThemeData], which is used to configure this theme.
|
||||
/// * [StreamChannelListHeaderThemeData], which is used
|
||||
/// to configure this theme.
|
||||
/// {@endtemplate}
|
||||
class StreamChannelListHeaderTheme extends InheritedTheme {
|
||||
/// Creates a [StreamChannelListHeaderTheme].
|
||||
@@ -90,7 +91,8 @@ class StreamChannelListHeaderThemeData with Diagnosticable {
|
||||
color: color ?? this.color,
|
||||
);
|
||||
|
||||
/// Linearly interpolate from one [StreamChannelListHeaderThemeData] to another.
|
||||
/// Linearly interpolate from one [StreamChannelListHeaderThemeData]
|
||||
/// to another.
|
||||
StreamChannelListHeaderThemeData lerp(
|
||||
StreamChannelListHeaderThemeData a,
|
||||
StreamChannelListHeaderThemeData b,
|
||||
|
||||
@@ -58,12 +58,14 @@ typedef ChannelListViewThemeData = StreamChannelListViewThemeData;
|
||||
|
||||
/// {@template channel_list_view_theme_data}
|
||||
/// A style that overrides the default appearance of [ChannelListView]s when
|
||||
/// used with [StreamChannelListViewTheme] or with the overall [StreamChatTheme]'s
|
||||
/// used with [StreamChannelListViewTheme]
|
||||
/// or with the overall [StreamChatTheme]'s
|
||||
/// [StreamChatThemeData.channelListViewTheme].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [StreamChannelListViewTheme], the theme which is configured with this class.
|
||||
/// * [StreamChannelListViewTheme], the theme
|
||||
/// which is configured with this class.
|
||||
/// * [StreamChatThemeData.channelListViewTheme], which can be used to override
|
||||
/// the default style for [ChannelListView]s below the overall
|
||||
/// [StreamChatTheme].
|
||||
|
||||
@@ -64,7 +64,8 @@ typedef ChannelPreviewThemeData = StreamChannelPreviewThemeData;
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [StreamChannelPreviewTheme], the theme which is configured with this class.
|
||||
/// * [StreamChannelPreviewTheme], the theme
|
||||
/// which is configured with this class.
|
||||
/// * [StreamChatThemeData.channelPreviewTheme], which can be used to override
|
||||
/// the default style for [ChannelHeader]s below the overall [StreamChatTheme].
|
||||
/// {@endtemplate}
|
||||
|
||||
@@ -61,7 +61,8 @@ typedef MessageInputThemeData = StreamMessageInputThemeData;
|
||||
|
||||
/// {@template message_input_theme_data}
|
||||
/// A style that overrides the default appearance of [MessageInput] widgets
|
||||
/// when used with [StreamMessageInputTheme] or with the overall [StreamChatTheme]'s
|
||||
/// when used with [StreamMessageInputTheme]
|
||||
/// or with the overall [StreamChatTheme]'s
|
||||
/// [StreamChatThemeData.messageInputTheme].
|
||||
/// {@endtemplate}
|
||||
class StreamMessageInputThemeData with Diagnosticable {
|
||||
@@ -133,7 +134,8 @@ class StreamMessageInputThemeData with Diagnosticable {
|
||||
/// Shadow for the [MessageInput] widget
|
||||
final BoxShadow? shadow;
|
||||
|
||||
/// Returns a new [StreamMessageInputThemeData] replacing some of its properties
|
||||
/// Returns a new [StreamMessageInputThemeData]
|
||||
/// replacing some of its properties
|
||||
StreamMessageInputThemeData copyWith({
|
||||
Duration? sendAnimationDuration,
|
||||
Color? inputBackgroundColor,
|
||||
|
||||
@@ -58,12 +58,14 @@ typedef MessageListViewThemeData = StreamMessageListViewThemeData;
|
||||
|
||||
/// {@template message_list_view_theme_data}
|
||||
/// A style that overrides the default appearance of [MessageListView]s when
|
||||
/// used with [StreamMessageListViewTheme] or with the overall [StreamChatTheme]'s
|
||||
/// used with [StreamMessageListViewTheme] or with
|
||||
/// the overall [StreamChatTheme]'s
|
||||
/// [StreamChatThemeData.messageListViewTheme].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [StreamMessageListViewTheme], the theme which is configured with this class.
|
||||
/// * [StreamMessageListViewTheme], the theme
|
||||
/// which is configured with this class.
|
||||
/// * [StreamChatThemeData.messageListViewTheme], which can be used to override
|
||||
/// the default style for [MessageListView]s below the overall
|
||||
/// [StreamChatTheme].
|
||||
|
||||
@@ -63,8 +63,8 @@ typedef MessageSearchListViewThemeData = StreamMessageSearchListViewThemeData;
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [StreamMessageSearchListViewTheme], the theme which is configured with this
|
||||
/// class.
|
||||
/// * [StreamMessageSearchListViewTheme], the theme
|
||||
/// which is configured with this class.
|
||||
/// * [StreamChatThemeData.messageSearchListViewTheme], which can be used to
|
||||
/// override the default style for [UserListView]s below the overall
|
||||
/// [StreamChatTheme].
|
||||
|
||||
-9
@@ -1,16 +1,7 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:jiffy/jiffy.dart';
|
||||
import 'package:stream_chat_flutter/src/extension.dart';
|
||||
import 'package:stream_chat_flutter/src/sending_indicator.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/channel_preview_theme.dart';
|
||||
import 'package:stream_chat_flutter/src/typing_indicator.dart';
|
||||
import 'package:stream_chat_flutter/src/unread_indicator.dart';
|
||||
import 'package:stream_chat_flutter/src/v4/stream_channel_avatar.dart';
|
||||
import 'package:stream_chat_flutter/src/v4/stream_channel_name.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||
|
||||
/// A widget that displays a channel preview.
|
||||
///
|
||||
|
||||
+1
-1
@@ -352,7 +352,7 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
|
||||
|
||||
if (mediaFile == null) return;
|
||||
|
||||
var file = AttachmentFile(
|
||||
final file = AttachmentFile(
|
||||
path: mediaFile.path,
|
||||
size: await mediaFile.length(),
|
||||
bytes: mediaFile.readAsBytesSync(),
|
||||
+4
-3
@@ -13,11 +13,11 @@ import 'package:stream_chat_flutter/src/commands_overlay.dart';
|
||||
import 'package:stream_chat_flutter/src/emoji/emoji.dart';
|
||||
import 'package:stream_chat_flutter/src/emoji_overlay.dart';
|
||||
import 'package:stream_chat_flutter/src/extension.dart';
|
||||
import 'package:stream_chat_flutter/src/message_input/simple_safe_area.dart';
|
||||
import 'package:stream_chat_flutter/src/message_input/tld.dart';
|
||||
import 'package:stream_chat_flutter/src/multi_overlay.dart';
|
||||
import 'package:stream_chat_flutter/src/quoted_message_widget.dart';
|
||||
import 'package:stream_chat_flutter/src/user_mentions_overlay.dart';
|
||||
import 'package:stream_chat_flutter/src/v4/message_input/simple_safe_area.dart';
|
||||
import 'package:stream_chat_flutter/src/v4/message_input/tld.dart';
|
||||
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
@@ -34,7 +34,8 @@ typedef ErrorListener = void Function(
|
||||
StackTrace? stackTrace,
|
||||
);
|
||||
|
||||
/// A callback that can be passed to [StreamMessageInput.onAttachmentLimitExceed].
|
||||
/// A callback that can be passed to
|
||||
/// [StreamMessageInput.onAttachmentLimitExceed].
|
||||
///
|
||||
/// This callback should not throw.
|
||||
///
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/channel_info.dart';
|
||||
import 'package:stream_chat_flutter/src/extension.dart';
|
||||
import 'package:stream_chat_flutter/src/option_list_tile.dart';
|
||||
@@ -8,6 +7,7 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
||||
import 'package:stream_chat_flutter/src/user_avatar.dart';
|
||||
import 'package:stream_chat_flutter/src/v4/stream_channel_name.dart';
|
||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||
|
||||
/// A [BottomSheet] that shows information about a [Channel].
|
||||
class StreamChannelInfoBottomSheet extends StatelessWidget {
|
||||
|
||||
@@ -23,11 +23,6 @@ export 'src/localization/stream_chat_localizations.dart';
|
||||
export 'src/localization/translations.dart' show DefaultTranslations;
|
||||
export 'src/message_action.dart';
|
||||
export 'src/message_input.dart' show MessageInput, MessageInputState;
|
||||
export 'src/message_input/countdown_button.dart';
|
||||
export 'src/message_input/message_input.dart';
|
||||
export 'src/message_input/stream_attachment_picker.dart';
|
||||
export 'src/message_input/stream_message_send_button.dart';
|
||||
export 'src/message_input/stream_message_text_field.dart';
|
||||
export 'src/message_list_view.dart';
|
||||
export 'src/message_search_item.dart';
|
||||
export 'src/message_search_list_view.dart';
|
||||
@@ -51,11 +46,15 @@ export 'src/user_item.dart';
|
||||
export 'src/user_list_view.dart';
|
||||
export 'src/user_mention_tile.dart';
|
||||
export 'src/utils.dart';
|
||||
|
||||
// v4
|
||||
export 'src/v4/channel_list_view/stream_channel_list_loading_tile.dart';
|
||||
export 'src/v4/channel_list_view/stream_channel_list_tile.dart';
|
||||
export 'src/v4/channel_list_view/stream_channel_list_view.dart';
|
||||
export 'src/v4/message_input/countdown_button.dart';
|
||||
export 'src/v4/message_input/stream_attachment_picker.dart';
|
||||
export 'src/v4/message_input/stream_message_input.dart';
|
||||
export 'src/v4/message_input/stream_message_send_button.dart';
|
||||
export 'src/v4/message_input/stream_message_text_field.dart';
|
||||
export 'src/v4/stream_channel_avatar.dart';
|
||||
export 'src/v4/stream_channel_info_bottom_sheet.dart';
|
||||
export 'src/v4/stream_channel_name.dart';
|
||||
|
||||
@@ -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: 3.5.1
|
||||
version: 4.0.0-beta.1
|
||||
repository: https://github.com/GetStream/stream-chat-flutter
|
||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||
|
||||
@@ -36,7 +36,7 @@ dependencies:
|
||||
rxdart: ^0.27.0
|
||||
share_plus: ^4.0.1
|
||||
shimmer: ^2.0.0
|
||||
stream_chat_flutter_core: ^3.5.1
|
||||
stream_chat_flutter_core: ^4.0.0-beta.0
|
||||
substring_highlight: ^1.0.26
|
||||
url_launcher: ^6.0.3
|
||||
video_player: ^2.1.0
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
## 4.0.0-beta.0
|
||||
|
||||
✅ Added
|
||||
|
||||
- Added `MessageInputController` to hold `Message` related data.
|
||||
- Deprecated old widgets in favor of Stream-prefixed ones.
|
||||
- Deprecated `ChannelsBloc` in favor of `StreamChannelListController` to control the channel list.
|
||||
- Added `MessageTextFieldController` to be used with the new `StreamTextField` ui widget.
|
||||
|
||||
- Updated `stream_chat` dependency to [`4.0.0-beta.0`](https://pub.dev/packages/stream_chat/changelog).
|
||||
|
||||
## 3.5.1
|
||||
|
||||
- Updated `stream_chat` dependency to [`3.5.1`](https://pub.dev/packages/stream_chat/changelog).
|
||||
@@ -9,10 +20,6 @@
|
||||
## 3.4.0
|
||||
- Updated `stream_chat` dependency to [`3.4.0`](https://pub.dev/packages/stream_chat/changelog).
|
||||
|
||||
✅ Added
|
||||
|
||||
- Added `MessageInputController` to hold `Message` related data.
|
||||
|
||||
🐞 Fixed
|
||||
|
||||
- Do not move a channel to top if the new message is from a thread.
|
||||
|
||||
@@ -220,7 +220,10 @@ class StreamChannelListController extends PagedValueNotifier<int, Channel> {
|
||||
_unsubscribeFromChannelListEvents();
|
||||
}
|
||||
|
||||
_channelEventSubscription = client.on().listen((event) {
|
||||
_channelEventSubscription =
|
||||
client.on().skip(1) // Skipping the last emitted event.
|
||||
// We only need to handle the latest events.
|
||||
.listen((event) {
|
||||
// Returns early if the event is already handled by the listener.
|
||||
if (eventListener?.call(event) ?? false) return;
|
||||
|
||||
@@ -237,10 +240,6 @@ class StreamChannelListController extends PagedValueNotifier<int, Channel> {
|
||||
_eventHandler.onChannelVisible(event, this);
|
||||
} else if (eventType == EventType.connectionRecovered) {
|
||||
_eventHandler.onConnectionRecovered(event, this);
|
||||
} else if (eventType == EventType.connectionChanged) {
|
||||
if (event.online != null) {
|
||||
_eventHandler.onConnectionRecovered(event, this);
|
||||
}
|
||||
} else if (eventType == EventType.messageNew) {
|
||||
_eventHandler.onMessageNew(event, this);
|
||||
} else if (eventType == EventType.notificationAddedToChannel) {
|
||||
|
||||
@@ -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: 3.5.1
|
||||
version: 4.0.0-beta.0
|
||||
repository: https://github.com/GetStream/stream-chat-flutter
|
||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||
|
||||
@@ -17,7 +17,7 @@ dependencies:
|
||||
freezed_annotation: ^1.0.0
|
||||
meta: ^1.3.0
|
||||
rxdart: ^0.27.0
|
||||
stream_chat: ^3.5.1
|
||||
stream_chat: ^4.0.0-beta.0
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.0.1
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 3.0.0-beta.1
|
||||
|
||||
* Updated `stream_chat_flutter` dependency to [`4.0.0-beta.1`](https://pub.dev/packages/stream_chat_flutter/changelog).
|
||||
|
||||
## 2.1.0
|
||||
|
||||
✅ Added
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: stream_chat_localizations
|
||||
description: The Official localizations for Stream Chat Flutter, a service for building chat applications
|
||||
version: 2.1.0
|
||||
version: 3.0.0-beta.1
|
||||
homepage: 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
|
||||
@@ -14,7 +14,7 @@ dependencies:
|
||||
sdk: flutter
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
stream_chat_flutter: ^3.4.0
|
||||
stream_chat_flutter: ^4.0.0-beta.1
|
||||
|
||||
dev_dependencies:
|
||||
dart_code_metrics: ^4.4.0
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 4.0.0-beta.0
|
||||
|
||||
- Updated `stream_chat` dependency to [`4.0.0-beta.0`](https://pub.dev/packages/stream_chat/changelog).
|
||||
|
||||
## 3.1.0
|
||||
|
||||
- Bump `drift` to `1.3.0`.
|
||||
|
||||
@@ -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: 3.1.0
|
||||
version: 4.0.0-beta.0
|
||||
repository: https://github.com/GetStream/stream-chat-flutter
|
||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||
|
||||
@@ -19,7 +19,7 @@ dependencies:
|
||||
path: ^1.8.0
|
||||
path_provider: ^2.0.1
|
||||
sqlite3_flutter_libs: ^0.5.0
|
||||
stream_chat: ^3.4.0
|
||||
stream_chat: ^4.0.0-beta.0
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.0.1
|
||||
|
||||
Reference in New Issue
Block a user